Git: working tree vs index vs repository¶
Mental model¶
Git has three distinct storage areas forming a pipeline: working tree (edit) -> index (stage) -> repository (commit). Data flows left to right through explicit commands.
What it looks like¶
"I save my file and commit." People think of two states: edited and committed. The index is invisible to most workflows.
What it really is¶
- Working tree: your actual files on disk. The directory you edit with your editor. Not managed by Git until you stage.
- Index (staging area): a binary file at
.git/indexthat lists every tracked file with its path, mode, and blob SHA. It represents what will go into the next commit. - Repository: the
.git/directory — the object store (blobs, trees, commits, tags), refs, config, hooks. The permanent record.
Why it seems confusing¶
Most tools hide the index. GUIs show "modified" and "committed" but
gloss over "staged." People think "save" means "commit" and miss that
staging is an explicit intermediate step. The index also serves double
duty: it is the staging area AND a cache for working tree status
(speeding up git status).
What actually matters¶
git add: copies file content from working tree to index.git commit: records the current index as a tree object in the repository.git diff: compares working tree vs index (unstaged changes).git diff --staged: compares index vs HEAD (staged changes).- The index enables partial commits: stage some files, commit them, leave other modifications uncommitted.
git stashsaves both index and working tree state, then resets both to HEAD.
Common mistakes¶
- Running
git commitand expecting all modified files to be included (only staged files are committed — usegit commit -ato auto-stage tracked files, but this skips new untracked files). - Editing a file after
git addand not re-adding — the commit will contain the version from when you last ranadd. - Ignoring
git diff --stagedbefore committing (you may commit more or less than intended). - Thinking
git resetis dangerous —git reset HEAD filejust unstages; the working tree is untouched.
Small examples¶
# See three-way state
git status
# "Changes to be committed" = index vs HEAD (staged)
# "Changes not staged" = working tree vs index
# "Untracked files" = in working tree, not in index
# Stage specific changes interactively
git add -p # choose hunks to stage
# Compare the three areas
git diff # working tree vs index
git diff --staged # index vs HEAD
git diff HEAD # working tree vs HEAD (both combined)
# The index is a real file
ls -la .git/index
# binary file, updated on every git add
One-line summary¶
Git moves data through three areas — working tree (edit), index (stage), repository (commit) — and the index is the often-invisible middle step that enables precise control over what gets committed.