By admin , 29 April 2026

The staging area, demystified

The index (a.k.a. cache, staging area) lives at .git/index as a binary file describing what the next commit will contain. It is not a tree — it is a flat sorted list of path entries with stat info, mode, and SHA. Operations like git add, git rm, and git mv update the index; git commit turns it into a tree object.

Inspecting

git ls-files --stage
git ls-files --debug
git diff --cached         # index vs HEAD
git diff                  # working tree vs index

Index versions

Git supports several index versions. Version 2 was historic; version 3 added skip-worktree (for sparse checkout); version 4 (default in 2.20+) prefix-compresses paths for big trees. Set with index.version:

git config index.version 4
git update-index --index-version 4

Stat caching

The index records device, inode, ctime, mtime, size for every entry. git status uses this to skip files whose stat info matches; only on stat mismatch does it read content. This is why huge repos benefit from core.fsmonitor (see "Fsmonitor: faster working tree queries").

Sparse index

Large monorepos can shrink their index by representing whole directories as a single entry (a tree SHA) rather than every contained file. Enable with sparse-checkout in cone mode:

git sparse-checkout init --cone
git sparse-checkout set apps/web libs/shared
git config core.sparseCheckoutCone true
git config index.sparse true

See "The sparse index: operating without a full index".

Three-way merging in the index

During a conflicted merge, the index holds three stages per conflicting path: stage 1 (ancestor), 2 (ours), 3 (theirs).

git ls-files -u                    # unmerged paths
git checkout-index --stage=2 -- file
git checkout-index --stage=3 -- file

Common mistakes

Believing git add stages files "permanently" — it stages a snapshot. Re-edit and re-add. Confusing index 0 (resolved) with stages 1/2/3 (conflicting). Hand-deleting .git/index is recoverable (git reset), but breaks any in-progress operation.

Performance levers

Large indexes are slow to read/write. Levers: index.version=4, core.untrackedCache=true, core.fsmonitor=true, sparse index, and feature.manyFiles=true which sets sensible defaults at once.

Related

See "Configuring index.version for performance" and "Feature.manyFiles configuration".