Git Crash Course#

Git does not store diffs or file deltas — it records snapshots of your entire repository over time. Once you understand the three areas (working directory, staging area, repository) and how pointers move, Git commands become intuitive instead of a series of incantations.

Table of Contents#

  1. 1. Mental Model: The Three Areas
  2. 2. Setup & Configuration
  3. 3. The Core Snapshot Cycle
  4. 4. Branching & Switching
  5. 5. Merging vs. Rebasing
  6. 6. Resolving Merge Conflicts
  7. 7. Cherry-Picking Commits (git cherry-pick)
  8. 8. Remote Workflows (Fetch, Pull, Push)
  9. 9. Undoing Mistakes Safely
  10. 10. Stashing Work
  11. 11. Quick Reference & Cheat Sheet

1. Mental Model: The Three Areas#

Every Git repository operates with three local states:

  1. Working Directory: The sandbox on your local disk containing actual files currently unpacked and editable.
  2. Staging Area (Index): A staging buffer where you craft the exact contents of your next commit. You can stage individual files, lines, or hunks.
  3. Repository (.git directory / HEAD): The permanent content-addressable database of immutable commit snapshots.

Mental Model: Think of Git like an artist's photography studio. The working directory is the messy room where props change. The staging area is the stage where you place only what should appear in the shot. The commit is snapping the photo and archiving it in the photo album.

2. Setup & Configuration#

Before making commits, configure your global identity and default branch:

# Set global identity
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

# Set default branch name to main
git config --global init.defaultBranch main

# Enable colored CLI output and sensible pull defaults
git config --global color.ui auto
git config --global pull.rebase false

# Inspect all configurations
git config --list --show-origin

3. The Core Snapshot Cycle#

Moving changes through the snapshot cycle:

# Check current repository status
git status

# Stage specific files or entire directory
git add path/to/file.js
git add .

# Stage interactively hunk by hunk
git add -p

# Inspect unstaged vs staged changes
git diff            # Working tree vs Staging area
git diff --staged   # Staging area vs HEAD commit

# Record the snapshot
git commit -m "feat(auth): implement JWT token verification"

4. Branching & Switching#

In Git, a branch is just a 41-byte movable pointer pointing to a commit SHA-1/SHA-256 hash. Creating or deleting a branch is instantaneous and costs zero storage overhead.

# Create and switch to a new branch (modern syntax)
git switch -c feat/user-profile

# Switch between existing branches
git switch main
git switch feat/user-profile

# List all local and remote branches
git branch -a

# Delete a branch that has been merged
git branch -d feat/user-profile

5. Merging vs. Rebasing#

There are two primary ways to integrate changes from one branch into another:

  1. Fast-Forward Merge: If target branch hasn't diverged, Git simply slides the branch pointer forward to match the incoming tip.
  2. 3-Way Merge (git merge): Creates a new merge commit with two parents, preserving the complete branching history and timeline.
  3. Rebase (git rebase): Replays your branch commits one by one on top of the target branch, producing a completely linear commit history.
# Option A: Merge feature branch into main
git switch main
git merge feat/user-profile

# Option B: Rebase feature branch on top of latest main
git switch feat/user-profile
git fetch origin
git rebase origin/main

6. Resolving Merge Conflicts#

When Git cannot automatically resolve differing edits to the same lines, it flags a conflict and embeds markers directly in the file:

<<<<<<< HEAD
const API_URL = "https://api.internal.net/v1";
=======
const API_URL = "https://api.production.com/v2";
>>>>>>> feat/update-api

Resolution steps:

  1. Open the conflicted files and edit them to the desired final state, removing marker lines.
  2. Stage the resolved files: git add <filename>.
  3. Finalize: git commit (for merge) or git rebase --continue (for rebase).
  4. To abort at any time: git merge --abort or git rebase --abort.

7. Cherry-Picking Commits (git cherry-pick)#

Cherry-picking allows you to copy an individual commit from any branch and replay its exact diff as a brand new commit on your currently checked-out branch, without performing a full merge.

Mental Model: Imagine a colleague has five commits on an experimental branch, but only one of them fixes a critical bug. Instead of merging the unfinished branch or manually copying code, you "cherry-pick" just that specific commit hash directly into your production branch.

Common real-world use cases:

  1. Hotfixing Production: Port a fix from your active development branch directly into a release-v1.2 hotfix branch without releasing unfinished features.
  2. Salvaging Stale Work: Extract a useful helper module or test suite from a branch that was otherwise abandoned.
  3. Recovering Misplaced Commits: If you accidentally committed directly onto main, switch to your feature branch, cherry-pick the commit, and reset main.
# 1. Locate the commit SHA on the source branch
git log --oneline feat/experiments

# 2. Switch to the target destination branch
git switch main

# 3. Apply the commit to current HEAD
git cherry-pick a1b2c3d

# 4. Cherry-pick a range of commits (from A to B, exclusive of A)
git cherry-pick a1b2c3d..e4f5g6h

# 5. Apply changes to staging without auto-committing
git cherry-pick -n <commit-sha>   # -n / --no-commit

Handling cherry-pick conflicts:

# If changes conflict, edit files, stage resolutions, and continue:
git add <resolved-files>
git cherry-pick --continue

# Or cancel completely and return to your original state:
git cherry-pick --abort

8. Remote Workflows (Fetch, Pull, Push)#

Working with centralized remotes like GitHub or GitLab:

# Add or inspect remote servers
git remote -v
git remote add origin git@github.com:user/repo.git

# Download remote refs without modifying local files
git fetch origin

# Fetch and integrate into current branch
git pull origin main

# Push branch to remote and track upstream
git push -u origin feat/user-profile

9. Undoing Mistakes Safely#

Choose the right undo command based on which state the change is in:

# 1. Discard uncommitted changes in working directory
git restore path/to/file.js

# 2. Unstage a file from the staging area back to working directory
git restore --staged path/to/file.js

# 3. Amend the most recent commit (add missed files or fix message)
git commit --amend --no-edit

# 4. Revert a published commit safely by appending an inverted commit
git revert <commit-sha>

# 5. Soft reset: rewind commit pointer, keep staged edits
git reset --soft HEAD~1

# 6. Hard reset: discard commit, stage, and local changes (destructive)
git reset --hard HEAD~1

10. Stashing Work#

Save uncommitted changes temporarily to switch branches cleanly without committing:

# Stash current tracked changes with a descriptive label
git stash push -m "wip: experimental redis cache"

# Include untracked files in the stash
git stash push -u -m "wip: new files included"

# List stored stashes
git stash list

# Re-apply the most recent stash and remove it from stash list
git stash pop

# Inspect what's inside a stash without applying
git stash show -p stash@{0}

11. Quick Reference & Cheat Sheet#

# Inspection
git log --oneline --graph --decorate --all
git show <commit-sha>
git blame path/to/file.js

# Daily Workflow
git switch -c feat/my-feature
git add .
git commit -m "feat: description"
git push -u origin feat/my-feature

# Integration & Cherry-Picking
git merge feat/my-feature
git rebase main
git cherry-pick <commit-sha>

# Emergency recovery
git reflog
git reset --hard HEAD@{n}