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 status takes 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
Where is status spending its time?If index refresh dominates, Git is checking tracked files, so look at timestamps being touched, filters and filesystem speed. If the untracked scan dominates, large unignored or ignored directories are being walked. If submodule status dominates, each submodule is being checked like a separate repository.Which region is largest?refreshTracked-file checkstimestamps, filters, diskread_directoryUntracked scanbig directoriessubmodule statusPer-submodule workignore=dirtyfix the biggest region first β€” the others are usually small

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
Causes and their fixesUnignored generated directories are fixed with ignore patterns. Ignored but huge directories are fixed with the untracked cache. Timestamp churn is fixed by finding the tool touching files. Slow disks are fixed by moving the repository to local storage. Submodule overhead is reduced with ignoreSubmodules. Sheer tree size is handled with sparse checkout and fsmonitor.CauseFixgenerated dir not ignoredlist grows huge.gitignore entryhuge ignored dirsstill walkeduntracked cachetimestamps touchedrefresh every runfind the toolnetwork driveslow stat callslocal diskmany submodulesone scan eachignoreSubmodulestree is just bigeverything slowsparse + fsmonitormost slow status reports turn out to be the first row

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.

The diagnosis loopMeasure status several times, read the trace2 regions, fix the largest one, then measure again. Repeat until status is fast enough, and record the cause so others recognise it.Measure3 runs, take the laterTraceGIT_TRACE2_PERFFix largestone cause at a timeRe-measuresame commandsRecordcause + fixone cause at a time, or you will not know which change helped

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.