gity vs Git's `untrackedCache`

Git's untrackedCache speeds up status by remembering untracked-file lists. Here's what it does, what it doesn't, and why fsmonitor is the bigger win.

  • #untrackedcache
  • #git
  • #comparison

When to pick gity

  • You want full status acceleration including IDE polling, CI, and worktrees
  • You need background prefetch and maintenance scheduling
  • You manage multiple repos and want a single tool

When to pick untrackedCache

  • You're not allowed to install new binaries
  • You want zero-dependency, zero-extra-process optimisation
  • Always enable it (even with gity!) — it stacks with fsmonitor

TL;DR

untrackedCache is a Git feature that caches the list of untracked files between status calls. It’s not really a competitor to gity — they handle different parts of the same problem.

  • untrackedCache: speeds up the untracked-file part of git status by caching the listing per directory.
  • gity / fsmonitor: speeds up the tracked-file part by knowing exactly which files changed.

Use both. Always.

How untrackedCache works

When you run git status, Git has to know about two categories of files:

  1. Tracked files: those in the index. Compare each one’s stat() to the cached index entry.
  2. Untracked files: those in the working tree but not in the index. Walk every directory and list them.

Without untrackedCache, Git rebuilds the untracked-file list from scratch every time. In a repo with lots of node_modules, target/, build/, or dist/ directories, that’s a lot of readdir() syscalls.

With untrackedCache, Git records the stat() of each directory. On the next call, if a directory’s stat() hasn’t changed, Git trusts that its children haven’t changed either and skips the walk.

Result: untracked-file scanning becomes nearly free for unchanged directories.

git config core.untrackedCache true
git update-index --untracked-cache

What it doesn’t do

untrackedCache doesn’t help with tracked files at all. If you have 250,000 tracked files and just typed git status, Git still calls lstat() on every one of them. That’s where fsmonitor wins.

untrackedCache also doesn’t help with git diff, git fetch, or any other operation. Its scope is exactly git status and the untracked-file enumeration within it.

Stacking with gity

The two features stack:

  • gity (fsmonitor) tells Git which tracked files changed → Git skips the tracked-file walk.
  • untrackedCache tells Git which directories haven’t changed → Git skips the untracked-file walk.

Together: a warm git status on a 250k-file monorepo returns in ~12 ms instead of 8 seconds. Without untrackedCache, the same call takes ~25 ms — still very fast, but you can have both for free.

gity register does not auto-enable untrackedCache for you (we don’t want to silently change your Git config beyond fsmonitor). Enable it yourself, or use feature.manyFiles=true which enables it as part of a bundle.

When to pick which

This isn’t really a “pick one” decision. The recommendation is:

git config feature.manyFiles true   # enables untrackedCache + index v4 + skipHash
gity register .                     # enables fsmonitor + maintenance

Two commands, both stack, no overlap. This is the configuration we ship as gity’s recommended setup for any large repo.

Frequently asked questions

Should I enable untrackedCache?

Always. `git config core.untrackedCache true` is free, safe, and stacks with fsmonitor. It caches the untracked-file list per directory between status calls. There's no scenario where leaving it off is correct in a repo over a few thousand files.

Is untrackedCache an alternative to gity?

No — it's a complement. untrackedCache only handles untracked files; fsmonitor (which gity provides) handles tracked files. Together they cover both paths. Use both.

Does `feature.manyFiles` cover this?

Yes. `git config feature.manyFiles true` enables `core.untrackedCache`, `index.version=4`, and `index.skipHash` together. It's the easy way to get untrackedCache plus other large-repo optimizations.