Diagnosing a slow git status Jump to heading
βGit is slowβ usually means git status is slow, because status runs constantly: before commits, in shell prompts, inside editors. The causes differ widely β a node_modules directory not covered by .gitignore, a working tree on a network drive, dozens of submodules, a line-ending filter rewriting every file, an index invalidated by a tool that touches timestamps β and each has a different fix. Guessing wastes time; Gitβs trace2 output says where the time goes. This page measures status, reads the trace, and maps each common cause to its fix, within large repository performance.
When to use this approach Jump to heading
git statustakes more than a second, or got slower recently.- Status is fast for colleagues but slow on one machine.
- Editors or shell prompts lag in one repository.
- You want evidence before enabling caches, as in using fsmonitor and the untracked cache.
Step 1 β Measure consistently Jump to heading
Run status several times and take the later runs; the first may include filesystem cache warm-up. Note the tree size so you know what βslowβ means here.
for i in 1 2 3; do /usr/bin/time -f '%e s' git status --porcelain >/dev/null; done
git ls-files | wc -l # tracked files
git status --porcelain --ignored | grep -c '^!!' # ignored entries reported Step 2 β Read the trace2 breakdown Jump to heading
GIT_TRACE2_PERF reports time per region. The regions that matter for status are index refresh, untracked-file scanning and submodule status.
GIT_TRACE2_PERF=1 git status >/dev/null 2>"$TMPDIR/status.trace"
grep -E 'region_leave' "$TMPDIR/status.trace" | awk -F'|' '{gsub(/ /,"",$7); print $7, $(NF-1), $NF}' | sort -k1,1nr -t' ' | head -n 10 Step 3 β Fix untracked scanning Jump to heading
The most common cause: a large directory of generated files β dependencies, build output, caches β that Git walks to find untracked files. If it is not ignored, status lists it; if it is ignored but very large, Git may still read it.
git status --porcelain | awk '{print $2}' | cut -d/ -f1-2 | sort | uniq -c | sort -rn | head
git check-ignore -v node_modules build .cache 2>/dev/null Add missing entries to .gitignore, and enable the untracked cache. Shared ignore patterns belong in the repository; personal ones in .git/info/exclude.
Step 4 β Fix slow index refresh Jump to heading
Refresh compares each tracked fileβs metadata with the index. It becomes slow when the filesystem is slow (network drives, virtual machine shares), when something rewrites file timestamps (some sync tools, antivirus, build systems), or when a clean or smudge filter has to run on many files.
git status >/dev/null; git status >/dev/null # second run should be faster if timestamps are stable
git config --get-regexp '^filter\.' ; git check-attr -a -- "$(git ls-files | head -n 1)"
git config core.autocrlf If the second run is no faster, something keeps touching files. If filters are listed, check they are needed for this repository. Line-ending normalisation is better done once with attributes, as in standardising line endings with gitattributes.
Step 5 β Fix submodule overhead Jump to heading
Status checks each submodule like a separate repository. With many submodules that dominates. If you rarely edit submodules, tell status not to inspect their working trees.
git submodule foreach --quiet 'echo $sm_path' | wc -l
git config diff.ignoreSubmodules dirty # still reports new commits, skips working-tree scans
time git status >/dev/null Step 6 β Shrink the tree or add caches Jump to heading
When the tree is genuinely large and none of the above applies, reduce the work: check out only what you need, and let fsmonitor track changes.
git sparse-checkout set --cone services/billing libs/common
git config core.fsmonitor true
git config core.untrackedCache true
git config feature.manyFiles true Step 7 β Confirm and record the result Jump to heading
Re-run the measurement and trace, and record what changed so the same diagnosis is faster next time β especially when the fix was a team-wide ignore pattern or setting.
for i in 1 2 3; do /usr/bin/time -f '%e s' git status --porcelain >/dev/null; done
git diff --stat -- .gitignore A team-wide check for configuration drift is in auditing local Git configuration drift.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Why is status fast for my colleague but slow for me? Jump to heading
Usually something local: a working tree on a synced or network folder, antivirus scanning, a global filter or core.autocrlf setting, or a large untracked directory only you have. Compare git config --show-origin --list output.
Does git status -uno help? Jump to heading
It skips untracked scanning entirely, which is fast but hides new files you may forget to add. Prefer fixing ignore patterns and enabling the untracked cache.
Is a slow status a sign of a corrupt repository? Jump to heading
Rarely. Corruption produces errors, not slowness. Run git fsck if you see errors; for slowness, trace.
Related Jump to heading
- Large Repository Performance β the parent topic.
- Using fsmonitor and the Untracked Cache β the caching fixes in detail.
- Enabling the Commit-Graph and Multi-Pack-Index β the history side of performance.
- Measuring Repository Growth over Time β seeing slowdowns coming.