Chapter 1.3☕ 18 min read

The 3 Areas — Working Dir → Staging → Repo

Staging ek shopping cart hai — checkout se pehle decide karo kya lena hai.

01The Three Areas — Understanding the Model

Git manages your files across THREE distinct areas, not just one. Understanding these three areas is the single most important mental model for using Git correctly.

Working Directory: the actual files on your disk that you edit. Your code editor sees these. This is where you do your work.

Staging Area (Index): an intermediate zone where you prepare the next commit. Like a shopping cart — you choose what goes in before checkout.

Repository (.git): permanent storage of all committed snapshots. The history. Once something is here, it is safe.

The flow is simple: git add moves changes from working → staging. git commit moves changes from staging → repository. git checkout moves from repository → working.

Why staging exists: you don't always want to commit EVERY change. Staging lets you craft commits carefully — selecting only the changes that belong together.

# The 3 areas visualized:
#
#   Working          Staging          Repository
#   Directory        Area (Index)     (.git)
#
#   [edit files] --> [git add] -----> [git commit]
#   [your code]      [shopping cart]  [permanent history]
#
#   <-- [git checkout] <-- <-- [already stored]
#   <-- [git restore]

# You can have DIFFERENT content in each area!
echo "version 1" > app.js     # Working dir has v1
git add app.js                # Staging has v1
echo "version 2" > app.js     # Working dir has v2
                              # Staging STILL has v1
                              # Repository has nothing yet
The staging area is what makes Git different from simpler tools. Without staging, every commit would include ALL changes — even the half-finished ones. Staging lets you say "I want THIS change in the commit, but not THAT change." It's like choosing which items to put on the conveyor belt at checkout.
02File States — Untracked, Modified, Staged, Committed

Every file in your project is in one of 4 states from Git's perspective:

  • Untracked: new file that Git doesn't know about yet. git add to start tracking it.
  • Modified: tracked file that has been changed but NOT staged. Working dir differs from staging.
  • Staged: file is marked to go in the next commit. Staging area differs from repository.
  • Committed: file is safely stored in your local repository. All three areas match.

The lifecycle: Untracked → (git add) → Staged → (git commit) → Committed → (edit) → Modified → (git add) → Staged → ...

A file can be BOTH staged AND modified at the same time! If you git add a file then edit it again, the new edit is NOT staged.

# Untracked — Git doesn't know about this file
echo "new file" > new.txt
git status
# ?? new.txt  (untracked)

# Staged — file is ready to commit
git add new.txt
git status
# A  new.txt  (staged, green)

# Modified — tracked file changed but not staged
echo "change" >> new.txt
git status
# AM new.txt  (staged AND modified — two versions exist!)

# Committed — safely stored in history
git add new.txt
git commit -m "add new.txt"
git status
# nothing to commit, working tree clean
03Shopping Cart Analogy

Think of Git like a grocery store. Working directory = shelves. Staging area = cart. Repository = fridge at home.

You browse shelves (edit files). You choose what goes in the cart (git add). You take it home (git commit).

You DON'T have to buy everything on the shelves. You select only what you need RIGHT NOW.

This is why git add . (add everything) is often wrong — you're putting items in the cart without checking.

git add -p (partial staging) = picking individual items from a shelf instead of the whole shelf.

The cart (staging) lets you review your selection BEFORE committing. git diff --staged = checking your cart.

# The shopping cart in action
echo "bug fix" >> app.js        # on the shelf
echo "debug log" >> app.js      # on the shelf
echo "secret key" >> .env       # on the shelf
echo "TODO: fix later" >> app.js # on the shelf

# BAD: add everything to cart without checking
git add .    # includes debug log, secret key, TODO

# GOOD: carefully select what goes in the cart
git add app.js                  # wait, this adds EVERYTHING in app.js

# BEST: partial staging — pick individual changes
git add -p app.js
# Stage this hunk? [y/n/s/e/?]
# y = yes, add to cart
# n = no, leave on shelf
# s = split into smaller pieces

# Review your cart before checkout
git diff --staged    # see exactly what's in the cart
git commit -m "fix: handle null response in login"
💡 Pro Tip: The most common beginner mistake: using git add . blindly. This stages ALL changes, including debug code, temporary files, and half-finished features. Always review what you're staging with git diff --staged before committing. Craft your commits like you craft your code — with intention.
04The Dual State — Staged AND Modified Simultaneously

The most confusing Git state: a file can be BOTH staged AND modified simultaneously.

This happens when: (1) you edit a file, (2) you git add it, (3) you edit it AGAIN before committing.

Now the staging area has version 2, but the working directory has version 3. Repository has version 1.

git status shows: MM file.txt (left M = staged, right M = modified in working dir).

git diff shows working vs staging (the changes NOT yet staged).

git diff --staged shows staging vs repository (the changes that WILL be committed).

If you commit NOW, only the staged version goes in. The latest edit stays in working dir.

# Create the dual state
echo "v1" > file.txt && git add . && git commit -m "v1"  # Committed: v1

echo "v2" > file.txt     # Working dir: v2, Staging: v1, Repo: v1
git add file.txt         # Working dir: v2, Staging: v2, Repo: v1

echo "v3" > file.txt     # Working dir: v3, Staging: v2, Repo: v1
                         # ALL THREE AREAS HAVE DIFFERENT CONTENT!

git status -s
# MM file.txt
# || └─ right M = modified in working dir (v3 vs v2)
# |└── left M = staged (v2 vs v1)

git diff              # working vs staging (v3 - v2)
git diff --staged     # staging vs repo (v2 - v1)

# Commit now → only v2 goes in! v3 is left behind!
git commit -m "update to v2"

# v3 is still in your working dir, unstaged
git status
# modified: file.txt
The dual state catches everyone off guard. You run git add, then you keep coding, then you commit — but the commit only includes what was STAGED, not what you typed after. This is why git status and git diff --staged are your best friends. Always check before you commit. The left column in git status -s is staging, the right column is working dir. Two different worlds.
05Moving Between Areas — The Complete Map

git add <file> = move from working to staging (stage changes)

git commit = move from staging to repository (create snapshot)

git restore --staged <file> (or git reset HEAD <file>) = move from staging back to working (unstage)

git restore <file> (or git checkout -- <file>) = discard working dir changes (DANGEROUS — data loss)

git checkout <commit> -- <file> = move from specific repository commit to working dir

git reset --soft HEAD~1 = move last commit back to staging (undo commit, keep changes staged)

git reset --mixed HEAD~1 = move last commit back to working dir (undo commit, unstage)

Understanding these movements is the KEY to mastering Git.

# Moving between areas — the complete map
#
# Working Dir  --git add-->  Staging  --git commit-->  Repository
#     ^                          |                          |
#     |                          |                          |
#     +-- git restore            +-- git restore --staged    +-- git reset
#     (discard changes)          (unstage)                  (undo commit)
#
# Practical examples:

# Unstage a file (staging → working)
git add wrong-file.txt
git restore --staged wrong-file.txt   # modern way
# or: git reset HEAD wrong-file.txt   # old way

# Discard working dir changes (PERMANENT!)
echo "oops" > important.txt
git restore important.txt   # DANGER: "oops" is GONE
# or: git checkout -- important.txt   # old way

# Undo last commit but keep changes staged
git reset --soft HEAD~1

# Undo last commit and unstage changes
git reset --mixed HEAD~1   # same as: git reset HEAD~1
💡 Git Commands — Old vs New: Git 2.23+ introduced git restore and git switch to replace overloaded commands. git checkout did too many things. Now: git restore handles discarding/unstaging, git switch handles branches. The old commands still work, but the new ones are clearer. Use git restore --staged instead of git reset HEAD, and git restore instead of git checkout --.

Lo kar liya — Key Points:

  • ✅ Git has 3 distinct areas: Working Directory (your files), Staging Area (shopping cart), Repository (permanent history)
  • ✅ Every file is in one of 4 states: Untracked, Modified, Staged, or Committed
  • git add moves changes from working to staging, git commit moves them from staging to repository
  • ✅ A file can be BOTH staged AND modified — if you edit after adding, the new edit is NOT staged
  • git diff shows unstaged changes (working vs staging), git diff --staged shows staged changes (staging vs repo)
  • ✅ Staging exists so you can choose WHAT to commit — not every change has to go in
  • git restore --staged unstages, git restore discards working dir changes (dangerous!)
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase