Topic 0.2
The Three Trees: Working Directory, Staging Area, Repository
In one line
Every Git operation moves changes between exactly three places — the working directory, the staging area, and the repository — and this one model explains almost every confusing Git command you'll ever run.
Think of it like this
Packing a box to ship. The WORKING DIRECTORY is your entire room, full of stuff, some of it ready to go and some not. The STAGING AREA is the box itself, where you've deliberately placed the specific items you've decided to ship right now. The REPOSITORY is the sealed, shipped package — a permanent, recorded snapshot of exactly what was in that box at that moment.
Key ideas
- 01
The WORKING DIRECTORY is the actual files on your disk, exactly as you see them in an editor — this is where you make edits, and Git constantly compares this against the other two trees to figure out what's changed.
- 02
The STAGING AREA (also called the INDEX) is a holding area where you place EXACTLY the changes you want in your next commit —
git add <file>moves a specific change from the working directory into staging, and critically, you can stage only SOME of your changes, leaving others for a later commit. - 03
The REPOSITORY is the permanent, committed history —
git committakes whatever is currently in the staging area and seals it into a new, permanent snapshot with a unique ID, an author, a timestamp, and a message. Once committed, that exact snapshot exists forever in the project's history (barring deliberate history rewriting, Phase 5). - 04
git statusis the single most useful command for seeing exactly where every file currently sits across these three trees — which files are modified but not staged, which are staged and ready to commit, and which are untracked entirely. Running it constantly, especially before committing, is a genuinely universal habit among experienced Git users. - 05
This three-tree model is WHY
git addexists as a separate step fromgit commitat all — a design choice that confuses many beginners coming from simpler tools. It exists specifically so you can build a commit deliberately, piece by piece, rather than being forced to commit every single change in your working directory all at once.
Code & diagrams
Every Git command you'll learn moves changes between exactly these three places.
Watch git status change as a file moves through each tree.
mkdir -p ~/scratch/git-demo && cd ~/scratch/git-demo
git init
# Nothing tracked yet
echo "hello" > notes.txt
git status
# notes.txt shows as "Untracked"
# Move it into the staging area
git add notes.txt
git status
# notes.txt now shows as "Changes to be committed"
# Seal it into the repository
git commit -m "Add notes.txt"
git status
# "nothing to commit, working tree clean" — all three trees now match
# Edit it again — see it reappear as unstaged
echo "more text" >> notes.txt
git status
# notes.txt shows as "Changes not staged for commit"Explain it without notes
Why does Git require a separate git add step instead of just committing every change in the working directory directly?
A file shows up in git status as 'Changes not staged for commit.' What tree is it in right now, and what command moves it to the next one?
Practice
Create a new file, run git status after each step (before adding, after adding, after committing) and read the exact wording Git uses at each stage.
Make TWO separate, unrelated changes to two different files, then stage and commit only ONE of them — confirm with git status that the second change is still sitting, untouched, in the working directory afterward.
Trade-offs
- ↔
The staging area's flexibility is genuinely powerful but adds a real extra step compared to tools that commit everything directly — for a solo project where you always want to commit every change together anyway,
git commit -a(which stages and commits all tracked-file changes in one step) is a reasonable shortcut, though it's worth understanding the three-tree model fully before leaning on shortcuts that skip a step of it.
Done when you can
I can name all three trees and explain what moves a change from one to the next.
I understand why git add exists as a separate step from git commit.
I can read git status output and know exactly which tree a given file's changes are sitting in.