About This Mentoring Session
This material was created for developer mentoring sessions, designed to teach Git from scratch in a single day. Whether you’re learning through a structured program or self-study, this guide provides a complete foundation with clear explanations and practical examples. The content, flow, and analogies have been refined through real teaching experience to ensure maximum clarity.
If you prefer hands-on practice, check out the companion lab workbook after reading through the concepts here.
What You Will Learn (Day 1)
By the end of Day 1 you will understand:
- What version control is and why every developer needs it
- The difference between local, centralized, and distributed version control
- How to install and configure Git on any platform
- Every core Git terminology — repository, commit, branch, HEAD, remote, fork, and more
- The three-state workflow that drives every Git operation
- How to create repositories, view history, and write meaningful commits
- How
.gitignoreworks and how to track (or untrack) files correctly - What happens behind the scenes inside the
.gitdirectory - How branching works and which workflow to choose
- How to undo mistakes at every stage — restore, reset, revert, and clean
- How to read and interpret
git diffandgit showoutput - A decision guide for choosing the right command in any scenario
This is Part 1 of our four-part mentorship series:
- Day 1 Guide — You are here. Conceptual foundations of Git and GitHub
- Day 1 Lab Workbook — Hands-on exercises for Day 1 topics
- Day 2 Guide — Advanced Git techniques (stash, tags, rebase, hooks, and more)
- Day 2 Lab Workbook — Hands-on exercises for Day 2 topics
Whether you are brand new to version control or looking to fill gaps in your understanding, this guide gives you the complete mental model you need before writing a single command.
Let us begin.
0. Editor Basics (Vim Quick Commands)
Before diving into Git, there is one prerequisite that trips up many beginners: the text editor that Git opens by default. On most systems, that editor is Vim. You do not need to become a Vim expert, but you do need to know how to save a file, quit, and enter text. Here are the essential commands.
Essential Vim Commands
:wq— Save all changes and quit Vim:q!— Quit without saving changes:w— Save changes without quittingi— Enter insert mode (start typing)Esc— Exit insert mode:set number— Show line numbers/searchterm— Search for text
Real-life analogy: Like writing in a notebook — :wq means save and close, :q! means close without saving.
When you will encounter Vim:
- Git commit messages often open in Vim by default
- Merge conflict resolution
- Interactive rebase operations
- Editing configuration files
Tip: If you prefer a different editor, you can change the default later in the configuration section. Many developers set VS Code as their Git editor with
git config --global core.editor "code --wait".
1. Version Control Systems (VCS)
Why Version Control?
Version control systems solve critical problems in software development:
- Track changes in files over time
- See who changed what, when, and why
- Understand evolution of codebase
- Roll back to previous versions
- Recover from mistakes
- Compare different versions
- Collaborate with multiple developers safely
- Work simultaneously without conflicts
- Merge changes intelligently
Real-life analogy: Google Docs version history, but more powerful for code.
If you have ever lost work because you overwrote a file, emailed yourself backup copies, or had two people edit the same document at once, version control is the solution. It is one of those foundational skills — like learning to type or use a terminal — that pays dividends across your entire career.
Types of VCS
1. Local Version Control (LVCS)
How it works:
- Changes stored in a local database on one machine
- Simple patch sets applied to files
- Example: RCS (Revision Control System)
Limitations:
- No collaboration
- No backup if disk fails
- Single point of failure
When it was used:
- Early days of programming (1980s)
- Personal projects
- Single-developer scenarios
2. Centralized Version Control (CVCS)
How it works:
- Single central server contains all versions
- Clients check out files from central place
- Examples:
- CVS (Concurrent Versions System)
- SVN (Apache Subversion)
- Perforce
Advantages:
- Everyone sees what others are doing
- Administrators control access
- Easier to manage than LVCS
Drawback:
- Server failure = no collaboration
- No offline work
- Slow operations (network dependent)
- Single point of failure
Real-world example:
- Company has one SVN server
- If server goes down, no one can commit
- If server disk corrupts, entire history lost
3. Distributed Version Control (DVCS)
How it works:
- Every developer has full copy of entire repository
- Full history available locally
- Example: Git, Mercurial
Advantages:
- Offline work – commit, branch, merge without network
- Faster operations – everything is local
- Multiple backups – every clone is a full backup
- Flexible workflows – can have multiple remotes
Git meaning (joke):
- Global Information Tracker (when it works)
- Goddamn Idiotic Trash (when it doesn’t)
Real-world scenario:
- Developer on plane writes code
- Commits locally during flight
- Pushes to server after landing
- No work lost, full history maintained
2. Git Basics
What is Git?
Git is a distributed version control system created by Linus Torvalds in 2005.
Key characteristics:
- Fast and lightweight
- Designed for Linux kernel development
- Handles projects of any size
- Strong support for branching and merging
Git vs GitHub
- Git — Software (VCS tool) – runs on your computer
- GitHub — Online hosting service for Git repositories – web platform
Analogy:
- Git is like Microsoft Word (software)
- GitHub is like Google Drive (cloud storage)
This distinction matters. You can use Git without GitHub, and GitHub is not the only hosting option (GitLab, Bitbucket, and others exist). But GitHub is where the majority of open source development happens, which is why it features so prominently in this guide.
Before Git
Previous version control systems:
- SVN (Subversion) – Centralized VCS
- Mercurial (Hg) – Distributed VCS, competitor to Git
- CVS – Older centralized system
- Perforce – Used in gaming industry
Installation
Windows:
# Download from git-scm.com
# Verify installation
git --version
macOS:
# Using Homebrew
brew install git
# Verify
git --version
Linux:
# Ubuntu/Debian
sudo apt-get install git
# Fedora
sudo dnf install git
# Verify
git --version
GitHub Account
Steps:
- Go to github.com
- Sign up with email
- Verify email address
- Set up profile
Why needed:
- Host repositories online
- Collaborate with others
- Showcase your work
- Contribute to open source
3. Git Terminologies (Detailed)
Understanding the vocabulary is half the battle with Git. This section defines every core term you will encounter throughout this guide and in your daily work. Come back to this section whenever a term feels unfamiliar.
Repository (Repo)
Definition: A directory that Git tracks, containing all files and complete history.
Types:
- Local Repository – On your computer
- Remote Repository – On GitHub/GitLab/Bitbucket
Structure:
my-project/ # Working directory
├── .git/ # Hidden folder (Git metadata)
├── src/
├── README.md
└── .gitignore
Working Directory
Definition: The actual files you see and edit in your project folder.
States of files:
- Untracked – New files Git doesn’t know about
- Tracked – Files Git is monitoring
- Unmodified – No changes since last commit
- Modified – Changed but not staged
- Staged – Marked for next commit
Staging Area (Index)
Definition: A holding area for changes before committing.
Purpose:
- Review changes before committing
- Selectively choose what to commit
- Create atomic commits
Real-life analogy: Shopping cart before checkout.
Example:
# Modified 3 files: app.js, style.css, README.md
# Only want to commit app.js and style.css
git add app.js style.css # Add to staging
git commit -m "Updated UI" # Commit only these two
# README.md still modified but not committed
Commit
Definition: A snapshot of your repository at a specific point in time.
Components:
- SHA-1 hash – Unique identifier (40 characters)
- Author – Who made the commit
- Date – When it was created
- Message – Description of changes
- Parent commit(s) – Previous commit(s)
- Snapshot – Complete state of files
Example:
commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date: Mon Feb 6 14:30:00 2026 +0100
Add user authentication feature
Branch
Definition: An independent line of development, a movable pointer to a commit.
Default branch: main (or master in older repos)
Types:
- Feature branch – New feature development
- Bugfix branch – Bug fixes
- Release branch – Preparing releases
- Hotfix branch – Emergency fixes
Real-life analogy: Parallel universes in multiverse.
HEAD
Definition: A pointer to the current branch reference, indicating where you are in the repository.
States:
- Attached HEAD – Points to a branch
- Detached HEAD – Points directly to a commit (not recommended for work)
Example:
# Normal state
HEAD -> main -> commit abc123
# After switching branch
HEAD -> feature -> commit def456
Remote
Definition: A version of your repository hosted on the internet or network.
Common names:
- origin – Default name for primary remote
- upstream – Original repository (in forks)
Commands:
git remote -v # List remotes
git remote add origin <url> # Add remote
git remote remove origin # Remove remote
git remote rename origin main # Rename remote
Upstream
Definition: The original repository you forked from.
Usage in open source:
# Your fork: github.com/yourname/project
# Original: github.com/owner/project
git remote add upstream https://github.com/owner/project.git
git fetch upstream # Get latest changes
git merge upstream/main # Merge into your branch
Fork
Definition: A copy of someone else’s repository under your GitHub account.
Purpose:
- Contribute to projects you don’t own
- Experiment without affecting original
- Create your own version of a project
Workflow:
- Fork on GitHub
- Clone your fork
- Make changes
- Push to your fork
- Create Pull Request to original
Clone
Definition: Download a complete copy of a repository from remote to local.
git clone https://github.com/user/repo.git
What it does:
- Downloads all files
- Downloads complete history
- Sets up remote connection
- Checks out default branch
Pull Request (PR)
Definition: A request to merge your changes into another repository/branch.
Process:
- Push branch to GitHub
- Open PR on GitHub
- Code review by maintainers
- Discussion and changes
- Approval and merge
Also called: Merge Request (in GitLab)
Merge
Definition: Combining changes from different branches.
Types:
- Fast-forward – Linear history
- 3-way merge – Creates merge commit
- Squash merge – Combines all commits into one
Conflict
Definition: When Git cannot automatically merge changes because same lines were modified.
Causes:
- Two people edit same line
- One person deletes file, another modifies it
- Complex refactoring
Stash
Definition: Temporary storage for uncommitted changes.
When to use:
- Need to switch branches quickly
- Pull latest changes without committing
- Save work in progress
Tag
Definition: A named reference to a specific commit, typically used for releases.
Types:
- Lightweight tag – Just a name
- Annotated tag – Contains metadata (recommended)
Submodule
Definition: A Git repository embedded inside another Git repository, allowing you to keep external code separate while including it in your project.
Real-life analogy: Like a reference book kept inside your project folder – the book stays separate but you can access it.
When to use:
- External dependencies that are independently developed
- Shared components across multiple projects
- Third-party libraries you might modify
Example:
git submodule add https://github.com/user/library.git vendor/library
git submodule update --init --recursive
Worktree
Definition: Multiple working directories attached to the same repository, each checking out a different branch simultaneously.
Real-life analogy: Having multiple copies of a book open to different chapters at the same time – work on different parts without losing your place.
When to use:
- Working on multiple features simultaneously
- Quick hotfixes without disrupting current work
- Code reviews while continuing development
Example:
git worktree add ../project-feature feature-branch
git worktree list
Bisect
Definition: A tool that uses binary search to find the commit that introduced a bug.
Real-life analogy: Finding a typo in a 1000-page book by repeatedly checking the middle page – you find it in about 10 checks instead of 1000.
When to use:
- Bug exists but don’t know when it was introduced
- Performance degradation over time
- Finding breaking changes
Example:
git bisect start
git bisect bad # Current commit has bug
git bisect good abc123 # This old commit was good
# Test, mark as good/bad, repeat until found
Hook
Definition: Scripts that Git executes automatically before or after events like commit, push, or merge.
Real-life analogy: Automatic reminders or checklists that run before you submit a form – ensures you don’t forget important steps.
Common hooks:
- pre-commit – Run tests before committing
- commit-msg – Validate commit message format
- pre-push – Prevent pushing to protected branches
Example:
# Hooks located in .git/hooks/
# pre-commit hook runs automatically before each commit
Alias
Definition: Custom shortcuts for Git commands to increase productivity and save typing.
Real-life analogy: Text shortcuts on your phone – “omw” expands to “On my way!”
When to use:
- Frequently used commands
- Complex commands you want to remember
- Team-wide standard shortcuts
Example:
git config --global alias.co checkout # Use: git co
git config --global alias.st status # Use: git st
git config --global alias.lg 'log --oneline --graph'
4. Initial Git Configuration (Detailed)
With Git installed and the vocabulary in place, the next step is configuration. This only needs to happen once per machine, but getting it right saves headaches later. Think of it as setting up your identity badge before entering the building.
Global Configuration
Purpose: Set your identity for all Git repositories on your system.
# Required settings
git config --global user.name "Your Full Name"
git config --global user.email "your.email@example.com"
# Optional but useful settings
git config --global core.editor "code --wait" # Use VS Code
git config --global init.defaultBranch main # Default branch name
git config --global color.ui auto # Colored output
git config --global pull.rebase false # Merge strategy
Configuration Levels
1. System level (--system)
- Applies to all users on the computer
- Rarely used
git config --system core.editor vim
2. Global level (--global)
- Applies to all repositories for current user
- Most commonly used
git config --global user.name "John"
3. Local level (default)
- Applies only to current repository
- Overrides global settings
git config user.email "work@company.com"
Viewing Configuration
# List all settings
git config --list
# List with origin
git config --list --show-origin
# Get specific value
git config user.name
# Edit config file directly
git config --global --edit
Useful Configurations
# Set default editor
git config --global core.editor "nano"
git config --global core.editor "vim"
git config --global core.editor "code --wait"
# Set line ending behavior
git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # Mac/Linux
# Create aliases
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual 'log --oneline --graph --all'
# Now you can use:
git st # instead of git status
git co main # instead of git checkout main
5. Git Workflow (Core Concept – Detailed)
This section is arguably the most important in the entire guide. If you understand the three-state model and the flow of changes from working directory to remote repository, every Git command will make intuitive sense. If you skip this section, commands will feel like arbitrary magic.
The Three States
Git has three main states that files can be in:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Working │─────>│ Staging │─────>│ Committed │
│ Directory │ add │ Area │commit│ (Repository) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
└──────────────────> restore <────────────────────┘
Complete Workflow
Working Directory → Staging Area → Local Repo → Remote Repo
↓ ↓ ↓ ↓
Files git add git commit git push GitHub/GitLab
Commands Mapping
| Stage | Command | Description |
|---|---|---|
| Modify | (edit files) | Make changes to files |
| Stage | git add <file> | Add to staging area |
| Stage | git add . | Add all changes |
| Commit | git commit -m "msg" | Save to local repo |
| Push | git push origin main | Upload to remote |
| Pull | git pull origin main | Download from remote |
Detailed Step-by-Step
Step 1: Modify files
# Edit app.js
echo "console.log('Hello');" > app.js
Step 2: Check status
git status
# Shows: modified: app.js (in red)
Step 3: Stage changes
git add app.js
# Or add all: git add .
Step 4: Verify staging
git status
# Shows: modified: app.js (in green)
Step 5: Commit
git commit -m "Add hello world log"
Step 6: Push to remote
git push origin main
Undo at Each Stage
| Stage | Undo Command | Effect |
|---|---|---|
| Modified (not staged) | git restore <file> | Discard changes |
| Staged (not committed) | git restore --staged <file> | Unstage |
| Committed (not pushed) | git reset --soft HEAD~1 | Undo commit, keep changes |
| Pushed | git revert <commit> | Create opposite commit |
This undo table is one of the most referenced parts of this guide. Bookmark it.
6. Creating a Git Repository (Detailed)
Method 1: Initialize New Repository
# Create project directory
mkdir my-project
cd my-project
# Initialize Git
git init
# What this does:
# - Creates .git folder
# - Sets up Git data structures
# - Creates default branch (main/master)
What’s inside .git folder:
.git/
├── HEAD # Points to current branch
├── config # Repository settings
├── description # Repository description
├── hooks/ # Git hooks (automation)
├── info/ # Additional info
├── objects/ # All commits, files (database)
├── refs/ # Branch and tag pointers
│ ├── heads/ # Local branches
│ └── tags/ # Tags
└── index # Staging area
Method 2: Clone Existing Repository
# Clone from GitHub
git clone https://github.com/username/repo.git
# Clone with different name
git clone https://github.com/username/repo.git my-project
# Clone specific branch
git clone -b develop https://github.com/username/repo.git
First Steps After Init
# 1. Check status
git status
# Output: On branch main, No commits yet, nothing to commit
# 2. Create initial files
echo "# My Project" > README.md
echo "node_modules/" > .gitignore
# 3. Check status again
git status
# Output: Untracked files: README.md, .gitignore
# 4. Stage files
git add .
# 5. Create first commit
git commit -m "Initial commit"
# 6. Verify
git log
Common Initial Commit Workflow
# Full initial setup
git init
echo "# Project Name" > README.md
echo "node_modules/
.env
*.log" > .gitignore
git add .
git commit -m "Initial commit: Add README and gitignore"
7. Viewing History (Detailed)
Once you start making commits, knowing how to navigate and read history becomes essential. Git provides powerful log and show commands that let you inspect any point in your project’s timeline. Mastering these commands is what separates someone who uses Git from someone who understands Git.
Basic Log Commands
# Full log
git log
# Output:
commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date: Mon Feb 6 14:30:00 2026 +0100
Add user authentication feature
# Compact one-line log
git log --oneline
# Output:
a3f2b1c Add user authentication
b2c3d4e Fix login bug
c4d5e6f Update README
Advanced Log Options
# Show last 5 commits
git log -5
# Show commits with file changes
git log --stat
# Show commits with actual code changes
git log -p
git log --patch
# Show graph of branches
git log --graph --oneline --all
# Beautiful graph
git log --graph --oneline --decorate --all
# Filter by author
git log --author="John"
# Filter by date
git log --since="2 weeks ago"
git log --after="2026-01-01"
git log --before="2026-02-01"
# Filter by commit message
git log --grep="fix"
# Show commits that changed specific file
git log -- path/to/file.js
# Show commits in date range
git log --since="2026-01-01" --until="2026-02-01"
Custom Log Format
# Custom format
git log --pretty=format:"%h - %an, %ar : %s"
# Output:
a3f2b1c - John Doe, 2 hours ago : Add authentication
b2c3d4e - Jane Smith, 1 day ago : Fix bug
# Format placeholders:
# %h - Abbreviated commit hash
# %H - Full commit hash
# %an - Author name
# %ae - Author email
# %ad - Author date
# %ar - Author date, relative (e.g., "2 hours ago")
# %s - Commit message subject
# %b - Commit message body
Viewing Specific Commit
# Show complete commit details
git show a3f2b1c
# Show specific file from commit
git show a3f2b1c:path/to/file.js
# Show files changed in commit
git show --name-only a3f2b1c
# Show commit statistics
git show --stat a3f2b1c
Best Practice: Atomic Commits
What is an atomic commit?
- One logical change = One commit
- Easy to understand
- Easy to revert
- Clear history
Bad example:
git commit -m "Fixed bugs and added features and updated docs"
Good example:
git commit -m "Fix login validation bug"
git commit -m "Add password reset feature"
git commit -m "Update API documentation"
Commit Message Best Practices:
# Format: <type>: <description>
# Examples:
git commit -m "feat: Add user registration"
git commit -m "fix: Resolve null pointer exception in login"
git commit -m "docs: Update installation instructions"
git commit -m "refactor: Simplify authentication logic"
git commit -m "test: Add unit tests for user service"
# Types:
# feat - New feature
# fix - Bug fix
# docs - Documentation
# style - Formatting, no code change
# refactor - Code restructuring
# test - Adding tests
# chore - Maintenance
Good commit messages are a form of documentation. When you need to understand why a change was made six months from now, the commit message is often the first place you look. Treat them as part of your code quality practice, just like you would treat naming variables or writing clear comments.
8. Ignoring and Tracking Files (Detailed)
.gitignore Purpose
What it does: Tells Git which files/folders to NOT track.
Why needed:
- Avoid committing sensitive data (.env files)
- Exclude build artifacts (node_modules, dist/)
- Skip OS-specific files (.DS_Store, Thumbs.db)
- Ignore IDE settings (.vscode/, .idea/)
Security matters here. Accidentally committing a .env file with API keys or database credentials is one of the most common mistakes developers make, and it can have serious consequences.
Creating .gitignore
# Create file
touch .gitignore
# Add patterns
echo "node_modules/" >> .gitignore
echo ".env" >> .gitignore
echo "*.log" >> .gitignore
.gitignore Patterns
# Ignore specific file
secret.txt
# Ignore all files with extension
*.log
*.tmp
# Ignore folder
node_modules/
dist/
build/
# Ignore files in any directory
**/*.log
# Ignore all .txt files except one
*.txt
!important.txt
# Ignore files only in root
/config.json
# Ignore all .md files in docs directory
docs/*.md
# Comments
# This is a comment
Complete .gitignore Example
# Dependencies
node_modules/
vendor/
bower_components/
# Environment variables
.env
.env.local
.env.production
# Build outputs
dist/
build/
out/
*.min.js
*.min.css
# Logs
logs/
*.log
npm-debug.log*
# Operating System
.DS_Store
Thumbs.db
desktop.ini
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Testing
coverage/
.nyc_output/
# Temporary files
tmp/
temp/
*.tmp
# Compiled files
*.class
*.pyc
*.o
*.exe
Global .gitignore
For OS/IDE files across all projects:
# Create global gitignore
git config --global core.excludesfile ~/.gitignore_global
# Edit the file
nano ~/.gitignore_global
# Add patterns:
.DS_Store
Thumbs.db
.idea/
.vscode/
Untracking Already Committed Files
# Stop tracking file but keep it locally
git rm --cached filename
# Stop tracking folder
git rm -r --cached folder/
# Example: Accidentally committed .env
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit -m "Remove .env from tracking"
.gitkeep for Empty Folders
Problem: Git doesn’t track empty folders.
Solution: Add .gitkeep file.
# Create empty directory structure
mkdir -p logs/error
mkdir -p logs/access
# Git won't track these empty folders
git status # Won't show logs/
# Add .gitkeep files
touch logs/error/.gitkeep
touch logs/access/.gitkeep
# Now Git tracks the structure
git add logs/
git commit -m "Add log directory structure"
When to use .gitkeep:
- Required folder structure for application
- Output directories for logs
- Upload directories that start empty
Checking Ignored Files
# See which files are ignored
git status --ignored
# Check if specific file is ignored
git check-ignore -v filename
# Example output:
.gitignore:3:*.log debug.log
# Shows: file .gitignore, line 3, pattern *.log matches debug.log
9. Git Behind the Scenes (Detailed)
You do not need to understand Git internals to use Git effectively, but understanding how it works under the hood will deepen your intuition and make troubleshooting far easier. This section lifts the curtain on what happens inside the .git directory.
Git Object Model
Git stores everything as objects in .git/objects/ directory.
Four types of objects:
- Blob (Binary Large Object)
- Stores file content
- Identified by SHA-1 hash of content
- Tree
- Represents a directory
- Contains blobs and other trees
- Like a snapshot of file structure
- Commit
- Points to a tree
- Contains metadata (author, date, message)
- Points to parent commit(s)
- Tag
- Points to a commit
- Contains additional information
How Git Stores a Commit
Commit Object (a3f2b1c)
├── Tree (def456)
│ ├── Blob (abc123) - README.md content
│ ├── Blob (789xyz) - app.js content
│ └── Tree (456abc) - src/ directory
│ └── Blob (xyz789) - index.js content
├── Parent: b2c3d4e
├── Author: John Doe
├── Date: 2026-02-06
└── Message: "Add authentication"
SHA-1 Hashing
# Git uses SHA-1 to create unique identifiers
# Example: a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
# Content → Hash
echo "Hello Git" | git hash-object --stdin
# Output: 8d0e41234f24b6da002d962a26c2495ea16a4254
# Same content = Same hash (content-addressable storage)
Viewing Git Objects
# List all objects
find .git/objects -type f
# View object type
git cat-file -t a3f2b1c
# View object content
git cat-file -p a3f2b1c
# Example output for commit:
tree def456abc789
parent b2c3d4e5f6a7
author John Doe <john@example.com> 1675694400 +0100
committer John Doe <john@example.com> 1675694400 +0100
Add user authentication
How Git Stores Changes Efficiently
Git uses:
- Content-addressable storage
- Objects identified by content hash
- Compression
- Objects are zlib compressed
- Packing
- Similar objects stored as deltas (differences)
# View repository size
du -sh .git
# Garbage collection and optimization
git gc
# Aggressive optimization
git gc --aggressive --prune=now
HEAD File
# View HEAD
cat .git/HEAD
# Output for normal state:
ref: refs/heads/main
# This means HEAD → main branch → commit
# View where main points
cat .git/refs/heads/main
# Output: a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
10. Branching in Git (Detailed)
Branching is one of Git’s most powerful features and the foundation of every collaborative workflow. If the three-state model is the engine of Git, branching is the steering wheel. Understanding it well will shape how you work on teams and how you structure your own projects.
What is a Branch?
Technical definition: A lightweight movable pointer to a commit.
Practical definition: An independent line of development.
Why Use Branches?
- Feature development – Work on new features without affecting main code
- Bug fixes – Fix bugs in isolation
- Experimentation – Try new ideas safely
- Collaboration – Multiple people work simultaneously
- Release management – Maintain multiple versions
Branch Commands (Comprehensive)
# List all local branches
git branch
# List all branches (including remote)
git branch -a
# List only remote branches
git branch -r
# Create new branch
git branch feature-login
# Create and switch to new branch
git switch -c feature-login
# OR (older syntax)
git checkout -b feature-login
# Switch to existing branch
git switch main
# OR
git checkout main
# Rename current branch
git branch -m new-name
# Rename other branch
git branch -m old-name new-name
# Delete branch (safe - won't delete if unmerged)
git branch -d feature-login
# Force delete branch (even if unmerged)
git branch -D feature-login
# Delete remote branch
git push origin --delete feature-login
# View last commit on each branch
git branch -v
# View merged branches
git branch --merged
# View unmerged branches
git branch --no-merged
Branch Workflows
1. Feature Branch Workflow
# Start new feature
git switch -c feature-user-profile
# Work on feature
# ... edit files ...
git add .
git commit -m "Add user profile page"
# More commits...
git commit -m "Add profile editing"
# Switch back to main
git switch main
# Merge feature
git merge feature-user-profile
# Delete feature branch
git branch -d feature-user-profile
2. Gitflow Workflow
main (production)
├── develop (integration)
│ ├── feature/login
│ ├── feature/signup
│ └── feature/profile
├── release/v1.0
└── hotfix/critical-bug
3. GitHub Flow (Simpler)
main
├── feature/add-api
├── feature/ui-update
└── bugfix/login-error
Viewing Branch History
# Visualize all branches
git log --graph --oneline --all
# Output example:
* a3f2b1c (HEAD -> main) Merge feature-login
|\
| * b2c3d4e (feature-login) Add login form
| * c4d5e6f Add validation
|/
* d5e6f7a Initial commit
# Show branch relationships
git show-branch
# Compare branches
git diff main..feature-login
When to Create a Branch
Always create a branch when:
- Starting new feature
- Fixing a bug
- Experimenting with code
- Working collaboratively
- Making any significant change
Stay on main when:
- Making quick hotfixes (though branch is still better)
- Never – always use branches!
Real-world analogy:
- Main branch = Published book
- Feature branch = Draft manuscript
- Merge = Publishing new edition
11. Undo and Restore (Comprehensive)
Mistakes happen. What separates productive developers from frustrated ones is knowing exactly which undo command to reach for. Git gives you multiple tools for different situations, and choosing the wrong one can make things worse. This section maps every possible mistake to the correct recovery command.
Understanding the States
Untracked → Modified → Staged → Committed → Pushed
↓ ↓ ↓ ↓ ↓
(delete) restore restore reset/ revert
--staged revert
1. Restore (Uncommitted Changes)
Discard changes in working directory:
# Restore single file (discard changes)
git restore app.js
# Restore all files
git restore .
# What it does:
# - Reverts file to last committed state
# - CAUTION: Changes are permanently lost!
Unstage files (keep changes):
# Remove from staging, keep modifications
git restore --staged app.js
# Unstage all
git restore --staged .
# What it does:
# - Moves file from staging to modified state
# - Changes still exist in working directory
Combined example:
# Scenario: Modified and staged app.js, want to discard
git restore --staged app.js # Unstage
git restore app.js # Discard changes
# Shorter (discard directly):
git restore app.js # Discards even if staged
2. Reset (Before Push – Rewrite History)
Three types of reset:
a) Soft Reset
git reset --soft HEAD~1
# What it does:
# - Moves HEAD back 1 commit
# - Keeps changes in staging area
# - File modifications preserved
# - Use when: Want to recommit with better message
b) Mixed Reset (default)
git reset HEAD~1
# OR
git reset --mixed HEAD~1
# What it does:
# - Moves HEAD back 1 commit
# - Keeps changes in working directory (unstaged)
# - Use when: Want to reorganize commits
c) Hard Reset
git reset --hard HEAD~1
# What it does:
# - Moves HEAD back 1 commit
# - DELETES all changes
# - Working directory = that commit
# - CAUTION: Destructive! Use with care
Reset to specific commit:
# Reset to specific commit hash
git reset --soft a3f2b1c
git reset --mixed b2c3d4e
git reset --hard c4d5e6f
# Reset to 3 commits back
git reset --soft HEAD~3
3. Revert (After Push – Safe Undo)
# Create new commit that undoes changes
git revert HEAD
# Revert specific commit
git revert a3f2b1c
# Revert multiple commits
git revert HEAD~3..HEAD
# Revert without committing (review first)
git revert -n HEAD
# What it does:
# - Creates NEW commit
# - Opposite changes of specified commit
# - Doesn't rewrite history
# - Safe for shared/pushed commits
4. Clean (Remove Untracked Files)
# See what would be deleted (dry run)
git clean -n
# Delete untracked files
git clean -f
# Delete untracked files and directories
git clean -fd
# Delete ignored files too
git clean -fdx
# Interactive mode (choose what to delete)
git clean -i
Comparison Table
| Command | Scope | Safety | Use When |
|---|---|---|---|
git restore <file> | Working dir | Destructive | Discard local changes |
git restore --staged | Staging | Safe | Unstage files |
git reset --soft | Commits | Safe | Redo commit message |
git reset --mixed | Commits | Safe | Reorganize commits |
git reset --hard | Everything | Destructive | Completely undo |
git revert | Commits | Safe | Undo pushed commits |
git clean | Untracked | Destructive | Remove untracked files |
Recovery from Mistakes
# OH NO! I did git reset --hard by mistake!
# Don't panic, use reflog
# View all HEAD movements
git reflog
# Output:
a3f2b1c HEAD@{0}: reset: moving to HEAD~1
b2c3d4e HEAD@{1}: commit: Add feature
c4d5e6f HEAD@{2}: commit: Fix bug
# Restore to before reset
git reset --hard HEAD@{1}
# Now back to commit b2c3d4e!
When to Use Each Command
| Scenario | Command |
|---|---|
| Typo in file, not staged | git restore file.txt |
| Staged wrong file | git restore --staged file.txt |
| Bad commit message, not pushed | git reset --soft HEAD~1 then recommit |
| Want to reorganize last 3 commits | git reset --mixed HEAD~3 |
| Completely undo last commit | git reset --hard HEAD~1 |
| Undo commit that’s already pushed | git revert HEAD |
| Remove all uncommitted changes | git restore . && git clean -fd |
12. Git Diff (Comprehensive)
What is Git Diff?
Definition: Shows differences between files, commits, branches, or states.
Purpose:
- Review changes before staging
- Compare different versions
- Review what’s being committed
- Compare branches
If git log tells you what changed, git diff tells you how it changed. Together they give you complete visibility into your project’s evolution.
Basic Diff Commands
1. Working Directory vs Staging
# Show unstaged changes
git diff
# Example output:
diff --git a/app.js b/app.js
index a3f2b1c..b2c3d4e 100644
--- a/app.js
+++ b/app.js
@@ -1,3 +1,4 @@
function login() {
console.log("Login");
+ validateUser();
}
# Meaning:
# - Lines removed (red)
# + Lines added (green)
# @@ Line numbers @@
2. Staging vs Last Commit
# Show staged changes (what will be committed)
git diff --staged
# OR
git diff --cached
# Shows what's in staging area vs HEAD
3. Working Directory vs Commit
# Compare current state with specific commit
git diff a3f2b1c
# Compare with HEAD (last commit)
git diff HEAD
# Compare with 2 commits ago
git diff HEAD~2
Comparing Commits
# Compare two commits
git diff a3f2b1c..b2c3d4e
# OR
git diff a3f2b1c b2c3d4e
# Show only file names that changed
git diff --name-only a3f2b1c..b2c3d4e
# Show file names with status
git diff --name-status a3f2b1c..b2c3d4e
# Output:
# M modified.txt
# A added.txt
# D deleted.txt
# Show statistics
git diff --stat a3f2b1c..b2c3d4e
# Output:
# app.js | 10 +++++-----
# style.css | 3 +++
# 2 files changed, 8 insertions(+), 5 deletions(-)
Comparing Branches
# Compare current branch with main
git diff main
# Compare two branches
git diff main..feature-login
# Show only files that differ
git diff --name-only main..feature-login
# Show what's in feature but not in main
git diff main...feature-login
# Three-dot vs two-dot:
# Two dots (..) : Compare branch tips directly
# Three dots (...): Compare from common ancestor
Diff for Specific Files
# Diff for single file
git diff app.js
# Diff for specific file between commits
git diff a3f2b1c..b2c3d4e -- app.js
# Diff for all files in directory
git diff src/
# Diff for files matching pattern
git diff '*.js'
Advanced Diff Options
# Ignore whitespace changes
git diff -w
# OR
git diff --ignore-all-space
# Show word-by-word diff
git diff --word-diff
# Show function names with changes
git diff --function-context
# Colorful diff with highlighting
git diff --color-words
# Show diff with more context (default 3 lines)
git diff -U10 # 10 lines of context
# Minimal diff (fewest changes)
git diff --minimal
Understanding Diff Output
diff --git a/app.js b/app.js ← File being compared
index a3f2b1c..b2c3d4e 100644 ← Hash IDs and file mode
--- a/app.js ← Original file
+++ b/app.js ← Modified file
@@ -1,3 +1,4 @@ ← Line numbers: old(1,3) new(1,4)
function login() { ← Unchanged line
console.log("Login"); ← Unchanged line
+ validateUser(); ← Added line (green)
} ← Unchanged line
Diff Statistics
# Summary of changes
git diff --shortstat
# Output: 2 files changed, 10 insertions(+), 3 deletions(-)
# Detailed statistics
git diff --stat
# Output:
# app.js | 10 +++++-----
# README.md | 3 +++
# style.css | 5 -----
# 3 files changed, 13 insertions(+), 8 deletions(-)
# Numerical statistics
git diff --numstat
# Output:
# 10 5 app.js
# 3 0 README.md
# 0 5 style.css
Diff Tools (External)
# Use external diff tool
git difftool
# Configure diff tool (e.g., VS Code)
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# Other popular tools:
# - meld
# - kdiff3
# - Beyond Compare
# - vimdiff
When to Use Git Diff
| Scenario | Command |
|---|---|
| Review before staging | git diff |
| Review before committing | git diff --staged |
| Compare with last commit | git diff HEAD |
| Compare branches | git diff main..feature |
| Review specific file | git diff path/file.js |
| See what changed in commit | git show a3f2b1c |
| Compare two commits | git diff abc123..def456 |
13. Git Show (Comprehensive)
What is Git Show?
Definition: Display detailed information about Git objects (commits, tags, trees).
Primary use: Inspect complete details of a specific commit.
Basic Show Commands
1. Show Last Commit
# Show HEAD (last commit)
git show
# Output:
commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date: Mon Feb 6 14:30:00 2026 +0100
Add user authentication feature
diff --git a/auth.js b/auth.js
new file mode 100644
index 0000000..a3f2b1c
--- /dev/null
+++ b/auth.js
@@ -0,0 +1,5 @@
+function authenticate(user) {
+ // authentication logic
+}
2. Show Specific Commit
# By commit hash
git show a3f2b1c
# By relative reference
git show HEAD~1 # Previous commit
git show HEAD~2 # 2 commits ago
git show HEAD^ # Parent of HEAD
# By branch
git show main
git show feature-login
Show Specific Files
# Show file as it was in specific commit
git show a3f2b1c:path/to/file.js
# Show file from HEAD
git show HEAD:app.js
# Show file from different branch
git show feature:app.js
# Show file from tag
git show v1.0:README.md
Show Options
1. Show Only Changes (No Diff)
# Show commit metadata only
git show --no-patch a3f2b1c
# OR
git show -s a3f2b1c
# Output: Just commit info, no diff
2. Show Only File Names
# List files changed in commit
git show --name-only a3f2b1c
# Output:
# commit a3f2b1c...
# Author: John Doe...
#
# Add authentication
#
# auth.js
# login.js
# config.js
3. Show File Names with Status
# Show file names with change status
git show --name-status a3f2b1c
# Output:
# A auth.js (Added)
# M login.js (Modified)
# D old-auth.js (Deleted)
4. Show Statistics
# Show change statistics
git show --stat a3f2b1c
# Output:
# commit a3f2b1c...
#
# auth.js | 45 +++++++++++++++++++++++++++++
# login.js | 12 ++++++---
# config.js | 3 ++-
# 3 files changed, 56 insertions(+), 4 deletions(-)
Show Tags
# Show annotated tag
git show v1.0
# Output:
# tag v1.0
# Tagger: John Doe <john@example.com>
# Date: Mon Feb 6 14:30:00 2026 +0100
#
# Release version 1.0
#
# commit a3f2b1c...
# (shows commit details)
Show Tree Objects
# Show tree (directory listing) from commit
git show a3f2b1c^{tree}
# Show specific directory
git show a3f2b1c:src/
# Show blob (file content)
git show a3f2b1c:app.js
Show with Formatting
# Custom format
git show --pretty=format:"%h - %an, %ar : %s" a3f2b1c
# Show only specific parts
git show --format="%an %ae" --no-patch a3f2b1c
# Output: John Doe john@example.com
# Show with color
git show --color a3f2b1c
Show Multiple Commits
# Show multiple commits
git show a3f2b1c b2c3d4e
# Show range
git show HEAD~3..HEAD
# Show last 2 commits
git show HEAD~2..HEAD
Comparing Show vs Diff
| Feature | git show | git diff |
|---|---|---|
| Purpose | View single commit | Compare two states |
| Default | Shows last commit | Shows unstaged changes |
| Output | Commit info + diff | Just diff |
| Usage | Inspect commits | Compare versions |
Practical Show Examples
1. Quick commit inspection
# What changed in last commit?
git show --stat
# Who made this commit?
git show --format="%an <%ae>" --no-patch
# When was this commit made?
git show --format="%ad" --no-patch
2. Review specific commit
# Full details of a commit
git show a3f2b1c
# Just see what files changed
git show --name-status a3f2b1c
# See file as it was then
git show a3f2b1c:old-version.js
3. Debugging
# Check file state in previous version
git show HEAD~5:src/bug.js
# Compare file between commits
git show commit1:file.js > /tmp/old.js
git show commit2:file.js > /tmp/new.js
diff /tmp/old.js /tmp/new.js
When to Use Git Show
| Scenario | Command |
|---|---|
| View last commit details | git show |
| Inspect specific commit | git show a3f2b1c |
| See file from commit | git show a3f2b1c:file.js |
| Check what changed | git show --stat |
| View tag information | git show v1.0 |
| Quick commit summary | git show --no-patch |
14. When to Use Which Command (Decision Guide)
This section ties everything together. When you are in the middle of work and something goes wrong, you do not want to read through entire sections — you want a quick answer. Use the tables below as a rapid reference. Bookmark this section.
Scenario-Based Command Selection
Scenario 1: Want to see my uncommitted changes
# See what you modified (unstaged)
git diff
# See what you staged
git diff --staged
Scenario 2: Review specific commit
# See full commit details
git show a3f2b1c
# See only what files changed
git show --name-status a3f2b1c
Scenario 3: Compare branches
# See differences between branches
git diff main..feature
# See divergence from common ancestor
git diff main...feature
Scenario 4: Undo mistakes
# Discard uncommitted changes
git restore file.txt
# Undo last commit (keep changes)
git reset --soft HEAD~1
# Undo pushed commit (safe)
git revert HEAD
Scenario 5: View history
# See all commits
git log --oneline
# See commit graph
git log --graph --all --oneline
# See last commit
git show
Command Cheat Sheet by Purpose
VIEWING CHANGES:
git status # What's changed overall
git diff # Unstaged changes
git diff --staged # Staged changes
git show # Last commit details
git show a3f2b1c # Specific commit
git log # Commit history
MAKING CHANGES:
git add <file> # Stage changes
git commit # Save snapshot
git restore # Discard changes
git reset # Undo commits (local)
git revert # Undo commits (safe)
BRANCHING:
git branch # List/create branches
git switch # Change branches
git merge # Combine branches
git rebase # Reapply commits
COLLABORATION:
git clone # Download repository
git pull # Get updates
git push # Share changes
git fetch # Download without merge
Usage Summary Tables
File State Commands
| Current State | Want to | Command |
|---|---|---|
| Modified | Discard changes | git restore file |
| Modified | Stage changes | git add file |
| Staged | Unstage | git restore --staged file |
| Staged | Commit | git commit -m "msg" |
| Committed (local) | Undo commit | git reset --soft HEAD~1 |
| Committed (pushed) | Undo safely | git revert HEAD |
Viewing Commands
| Want to see | Command |
|---|---|
| Unstaged changes | git diff |
| Staged changes | git diff --staged |
| Last commit | git show |
| Specific commit | git show a3f2b1c |
| Commit history | git log --oneline |
| File from commit | git show a3f2b1c:file.js |
| HEAD movements | git reflog |
Branch Operations
| Action | Command |
|---|---|
| Create branch | git branch name |
| Create + switch | git switch -c name |
| Switch branch | git switch name |
| Delete branch | git branch -d name |
| List branches | git branch -a |
| Merge branch | git merge name |
Frequently Asked Questions
Is Git the same as GitHub?
No. Git is the version control software that runs locally on your machine. GitHub is a web platform that hosts Git repositories online and adds collaboration features like pull requests, issues, and project boards. You can use Git without GitHub, and there are alternatives like GitLab and Bitbucket.
Do I need to memorize all these commands?
Not at all. Focus on the core workflow first: git add, git commit, git push, git pull, git status, and git log. The rest you can look up as needed. Over time, the commands you use frequently will become muscle memory. Use the decision guide as a quick reference.
What happens if I accidentally commit sensitive data like passwords or API keys?
Simply deleting the file and committing again does not remove it from history. You will need to rewrite history using tools like git filter-repo or BFG Repo-Cleaner. Better yet, use a .gitignore file to prevent sensitive files from being tracked in the first place. If credentials have been exposed, rotate them immediately.
Should I use git checkout or git switch?
git switch was introduced in Git 2.23 to make branch operations clearer. git checkout still works and does more (it can also restore files), but git switch is recommended for switching branches because its intent is unambiguous.
What is the difference between git pull and git fetch?
git fetch downloads changes from the remote repository but does not modify your working directory. git pull does a git fetch followed by a git merge, which means it downloads and immediately integrates changes. Use fetch when you want to review changes before merging.
How often should I commit?
Commit whenever you complete a logical unit of work. A good commit should be atomic — it represents one change that makes sense on its own. Small, frequent commits are better than large, infrequent ones because they are easier to review, revert, and understand.
What’s Next: Day 1 Labs and Day 2
You now have the complete conceptual foundation for Git. The next step is to put these concepts into practice.
- Day 1 Lab Workbook — Hands-on exercises covering repository creation, branching, merging, conflict resolution, and recovery. Every command from this guide gets practiced in a real terminal.
- Day 2 Guide — Advanced Git techniques including stash, tags, cherry-pick, rebase, reflog, submodules, worktree, bisect, hooks, aliases, and more. If Day 1 gives you the steering wheel, Day 2 gives you the full dashboard.
- Day 2 Lab Workbook — Hands-on exercises for all Day 2 advanced topics.
Happy versioning!


