Why the index is slow
Even with sparse checkout, the index by default contains an entry per file in the entire repo — a million entries on a monorepo, even if only a thousand are present in the working tree. Reading and writing this on every command is expensive. The sparse index (Git 2.37+) replaces excluded directories with a single tree entry, shrinking the index by 100x or more.
Enabling
git sparse-checkout init --cone --sparse-index
git config index.sparse true
git update-index --sparse
Requires cone mode — non-cone patterns cannot be summarized as trees.
How it works
Each excluded directory is represented in the index as one entry of mode 040000 (tree) with the SHA of its committed tree. Index version 4 prefix-compression layers on top. Operations that need to expand a directory (e.g., editing a file inside it) trigger a partial expansion automatically.
Inspecting
git ls-files --sparse | head
git ls-files -t | grep ^S | head
GIT_TRACE2_PERF=1 git status 2>&1 | grep sparse
Performance numbers
On a real-world monorepo with 4M files, the Microsoft Office team reported git status dropping from 3 seconds to under 200ms after enabling sparse index. Index file size dropped from 350MB to 5MB.
Compatibility
Many commands are sparse-aware: status, add, commit, diff, checkout, reset, restore, stash, ls-files. Some still expand transparently when needed. Hooks and external tools that read .git/index directly may not understand the format — keep them on the latest libgit2 (1.5+) or use git ls-files to enumerate.
Forcing expansion
git update-index --no-sparse # expand to full index
git update-index --sparse # back to sparse
Common mistakes
Trying to enable the sparse index in non-cone sparse-checkout mode — refused. Using older third-party Git GUIs that read the index without sparse support — they may render incorrectly. Forgetting that adding a directory back to the cone re-expands its index entries.
Related
See "Sparse checkout for monorepos" and "Git in a monorepo".