The Three States
Working Directory, Staging, Repository
Why it matters
Git has three states for your files. Understanding this model is the key to knowing what each command does and why.
Key concepts
- Working Directory — Your actual files on disk
- Staging Area — Files queued for the next commit (index)
- Repository — Permanent history stored in .git/
- Git Objects — Blobs (files), trees (directories), commits, tags
The idea
The Shipping Analogy
Think of Git as a shipping warehouse:
1. Working Directory (Your Desk) Where you do actual work. Files here can be modified freely. Git doesn’t care about changes until you stage them.
2. Staging Area (The Loading Dock) Items you’ve decided to ship. You’re selecting which boxes go on the truck. You can add/remove items before the truck leaves.
3. Repository (The Warehouse Archive) Once committed, items are archived permanently. Can’t be changed, only added to.
flowchart TD
work["Working Directory: edit files"]
stage["Staging Area (Index)"]
repo["Repository (.git/)"]
work -->|git add| stage
stage -->|git commit| repo
stage -->|unstage| work
Why Two Steps?
The staging area lets you craft precise commits. Changed 10 files but only want to commit 3? Stage just those 3. This creates cleaner, more meaningful history.
Walkthrough
File States
flowchart TD
working["Working Directory: untracked, modified, unchanged files"]
staged["Staging Area (Index): selected changes"]
committed["Repository (.git/): committed snapshot"]
working -->|git add selected changes| staged
staged -->|git commit| committed
Commands for Each Transition
# Working → Staging
git add <file> # Stage specific file
git add . # Stage all changes
git add -p # Stage parts of files (interactive)
# Staging → Working (unstage)
git restore --staged <file> # Remove from staging
git reset HEAD <file> # Alternative (older style)
# Working → Discard
git restore <file> # Discard working changes
git checkout -- <file> # Alternative (older style)
# Staging → Repository
git commit -m "message" # Commit staged changes
Git Objects (What’s in .git/)
Git stores four types of objects:
| Object | Purpose |
|---|---|
| blob | File contents (compressed) |
| tree | Directory listing (pointers to blobs) |
| commit | Snapshot + metadata + parent pointer |
| tag | Named pointer to a commit |
Key takeaways
- Three states: Working → Staging → Repository
- Staging lets you craft precise commits
- Commits are permanent snapshots
- All Git data lives in the .git folder
Dos & don’ts
✅ DO
- Use staging strategically: Commit related changes together
- Use
git add -p: Stage specific parts of files - Review before committing:
git diff --stagedshows what’s staged
❌ DON’T
- Don’t delete .git/: That’s your entire history!
- Don’t mix unrelated changes in one commit: Keep commits focused
Going deeper
Content-Addressable Storage: Git is a content-addressable filesystem. Files are stored by their SHA-1 hash. If two files have identical content, they’re stored once. This makes Git space-efficient.
Plumbing vs Porcelain: Git has low-level “plumbing” commands (hash-object, cat-file, update-index) and high-level “porcelain” commands (add, commit, status). You use porcelain; Git uses plumbing internally.
Common mistakes
Confusing staged and committed:
Staged ≠ saved. If you git add but don’t git commit, your changes aren’t in history yet.
git status shows the difference.
Editing staged files:
If you git add file.txt then edit file.txt again, the new edits are NOT staged.
You need to git add file.txt again to stage the latest version.