Enabling Git FSMonitor and Untracked Cache: Speed Up git status on Massive Repositories

Git tutorial - IT technology blog
Git tutorial - IT technology blog

1. The Problem: When git status Bottlenecks Your Workflow

When working with monorepos or projects containing hundreds of thousands of files, terminal latency becomes a major pain point. You type git status and have to wait 5 to 10 seconds just to see the results. Repeating this command dozens of times a day breaks your concentration and significantly drags down productivity.

I previously ran into this issue on a repository with over 320,000 files (primarily a legacy PHP/Node.js codebase combined with submodules). Every time I checked a branch or staged a commit, Git took over 8 seconds just scanning for changes. Starting with Git 2.37+, two built-in features—Untracked Cache and FSMonitor (File System Monitor)—completely solve this problem. After enabling them, command execution time dropped from 8.24 seconds down to 0.14 seconds.

2. Why Does Default Git Scan So Slowly?

To optimize effectively, we first need to understand how Git checks for file changes on your disk.

Default Scanning Mechanism via lstat()

Every time you run git status, Git must compare the working tree with the index. It recursively traverses the entire directory tree and issues an lstat() system call on every single file. For a project with 300,000 files, your disk has to process that exact number of disk I/O operations. Response times are therefore completely bottlenecked by your storage drive’s read throughput.

Untracked Cache (core.untrackedCache)

This feature caches the mtime (modification time) of each directory. When checking for untracked files, if the parent directory’s mtime hasn’t changed, Git immediately skips the entire subtree inside it. As a result, Git avoids wasting I/O resources scanning deep into massive, static directories like node_modules or vendor.

FSMonitor (core.fsmonitor)

FSMonitor takes a completely different approach. Instead of having Git recursively scan everything itself, a background daemon listens for file system events from the operating system (FSEvents on macOS, ReadDirectoryChangesW on Windows, inotify on Linux). When you run git status, Git simply queries the daemon: “Which files have changed since the last check?” The daemon instantly returns a specific list of changed files. Git only needs to inspect those exact files instead of traversing the entire repository.

3. Step-by-Step Setup and Benchmarking

Step 1: Check Git Version and Compatibility

First, verify your installed Git version. You need Git 2.37.0 or newer to use the built-in FSMonitor without installing third-party tools like Watchman:

git --version

Next, check if your disk partition’s filesystem supports reliable mtime tracking for Untracked Cache:

git update-index --test-untracked-cache

If the last line outputs OK, your system is ready.

Step 2: Enable Untracked Cache

Run the following two commands inside your project root:

# Enable untracked cache configuration
git config core.untrackedCache true

# Populate initial cache data into the index
git update-index --untracked-cache

Step 3: Enable Built-in FSMonitor

Enable the built-in file system monitor process:

# Enable for current repository only
git config core.fsmonitor true

# Or apply globally across all repos on your machine
git config --global core.fsmonitor true

On your next Git command invocation, the background daemon git-fsmonitor--daemon will automatically start and track file changes throughout your session.

Step 4: Measure Real-World Performance (Benchmark)

Use the GIT_TRACE2_PERF environment variable to output detailed execution timings:

GIT_TRACE2_PERF=1 git status

Real-world benchmark results on a 320,000-file repository (PCIe 4.0 NVMe SSD):

  • Without optimizations: data: ... status: 8.241320 s (sequential scan across the entire disk)
  • Untracked Cache only: data: ... status: 3.110540 s (over 62% time saved)
  • Both enabled: data: ... status: 0.142010 s (near-instantaneous response)

Practical Considerations and Caveats

  • Network drives (NFS/SMB): FSMonitor cannot receive filesystem events over network shares. Use it only on locally attached storage (local SSD/NVMe).
  • WSL2 on Windows: If your code resides on a Windows drive (path /mnt/c/...), FSMonitor will bottleneck due to the 9P translation layer. Move your source code into the native Linux filesystem (e.g., /home/username/code) for peak performance.
  • Disabling when necessary: In rare cases of cache desynchronization, quickly disable it with: git config core.fsmonitor false.

4. Summary

The core.untrackedCache and core.fsmonitor configurations bring Git response times down to the millisecond range without requiring any complex third-party tools. For codebases with tens of thousands of files or more, these settings should be enabled by default right from day one.

Share: