By admin , 29 April 2026

Linear tools, exponential repos

Git was originally tuned for the Linux kernel — large by 2005 standards but tiny by today's. Modern repos can hold millions of files, hundreds of gigabytes of history, and tens of thousands of refs. Many Git operations were O(working tree size) or O(history) by default, and at scale they became visibly slow. Performance work since 2018 has added optional features that turn many operations into O(changed) rather than O(total).

Where time goes

Common slow paths:

  • git status walks the working tree to detect changes.
  • git log, git blame, and merge-base calculations walk commit graphs.
  • git fetch negotiates with the server over many ref changes.
  • git gc repacks every object, even unchanged ones.
  • The index is read and written many times per command, and grows linearly with tree size.

Measuring

Before tuning, measure. Trace2 emits structured events for every Git invocation:

GIT_TRACE2_PERF=1 git status
GIT_TRACE2_EVENT=/tmp/trace.json git status
git -c trace2.eventTarget=/tmp/trace git fetch

See "Measuring Git performance with Trace2" for analysis.

The performance toolbox

Modern Git provides:

  • commit-graph: precomputed reachability data.
  • changed-path Bloom filters: skip irrelevant commits in log -- path.
  • multi-pack-index: one lookup index across many packs.
  • reachability bitmaps: O(1) set operations on huge histories.
  • fsmonitor: filesystem change notifications instead of stat walking.
  • partial clone and sparse index: shrink local data.
  • geometric repack: avoid full repack costs.
  • protocol v2: efficient ref negotiation.
  • git maintenance: keep all of this fresh in the background.

Quick wins

git config feature.manyFiles true
git config core.fsmonitor true
git config core.untrackedCache true
git config index.version 4
git maintenance start

For most users, this trio cuts git status from seconds to milliseconds on repos with hundreds of thousands of files.

Common mistakes

Tuning before measuring. Enabling features without understanding them — for example, core.fsmonitor=true requires Git 2.37+ for the built-in daemon; older versions need an external one. Skipping git maintenance start, leaving the commit-graph and MIDX stale.

Related

See every page in this section. Start with "Measuring Git performance with Trace2".