gity vs Git's Built-in fsmonitor: When to Pick Which
Git ships a native fsmonitor daemon. Here's what it actually covers, what's still missing, and when adding gity on top makes sense.
Git 2.37 quietly shipped a feature that solves most of what people install Watchman or gity for: a built-in fsmonitor daemon. You can enable it with one flag and it does roughly what you’d hope:
git config core.fsmonitor true
git update-index --fsmonitor
That’s it — git status now goes from seconds to milliseconds in any repo where you’ve enabled it. So why would anyone install a separate daemon? This piece walks through what the built-in daemon covers, what’s missing, and when adding gity on top makes sense.
What the built-in daemon does
git fsmonitor--daemon (the binary Git ships) is a competent fsmonitor v2 implementation. Per-platform it:
- Uses
FSEventson macOS. - Uses
inotifyon Linux. - Uses
ReadDirectoryChangesWon Windows. - Listens on a Unix domain socket (or named pipe on Windows) for v2 protocol queries.
- Tells Git which files changed since the last token.
For the canonical use case — “make git status fast in this one repo on my dev machine” — it’s all you need. No external install. Free out of the box.
What it doesn’t do
The native daemon is intentionally minimal. It handles fsmonitor and nothing else. Specifically:
1. No background prefetch
git fetch on a large repo touches the network and parses object headers. Doing it in the foreground when you start work each morning costs 30+ seconds. With git maintenance (a separate scheduler shipped in Git), you can schedule background prefetch — but you have to configure it yourself, and on every machine.
gity bundles this in. Registered repos get prefetch on the daemon’s CPU-aware scheduler with no extra configuration.
2. No background maintenance
Same story for git maintenance run --task=gc, repack, commit-graph. The built-in scheduler exists; integrating it is on you.
3. One daemon per repo
The built-in daemon services exactly one repo per process. If you have ten registered repos, you have ten daemon processes. Each one uses ~5 MB RSS and one file descriptor per watched subdirectory. For most people this is fine; for power users with dozens of large repos, the overhead adds up.
gity is a single daemon process that services any number of repos. The watcher pools, the cache, and the scheduler are all shared.
4. No multi-worktree cache sharing
If you have three worktrees of the same monorepo, the built-in daemon caches each one independently. After a git checkout switches the working tree, the cache for the new state has to warm up from scratch.
gity recognizes shared object stores across worktrees and replicates hot keys across them, so switching between feature branches stays instant.
5. No CI oneshot mode
In a CI runner, you want fast git status for one Git invocation, then you want the daemon to exit cleanly. The built-in daemon assumes long-lived sessions; spinning it up just to tear it down is awkward.
gity daemon oneshot <repo> is built for exactly this case.
6. No subscribe API
Editors like VS Code, IntelliJ, and Sublime poll git status to keep gutter decorations up to date. With the built-in daemon they still poll. With gity they can subscribe to a pub/sub channel and only re-render when something actually changed — a meaningful CPU saving on busy machines.
Performance: tied, mostly
For a single warm git status call, the two daemons are within milliseconds of each other. Both do the same fundamental work: pop file change events off an OS-native queue, compute a delta, hand it to Git. Any benchmark that shows one decisively faster is probably comparing different scenarios.
Where you may see a difference:
- Cold-start after reboot. gity’s persistent sled-backed cache lets it return an “all clean” response immediately after restart, if the repo hasn’t changed since shutdown. The built-in daemon always has to re-prime.
- High-frequency polling. gity’s memory-mapped fsmonitor cache returns responses with zero copies; the built-in daemon does one allocation per response. In aggregate (1000+ status calls per minute from a busy IDE), gity uses measurably less CPU.
For interactive use, neither difference matters. For an IDE that polls every 200ms across three open repos, the aggregate matters.
When to pick which
Stick with Git’s built-in fsmonitor if:
- You have a handful of repos, all of comparable size.
- You don’t need background prefetch or maintenance (or you’ve already wired up
git maintenance starton each machine). - You don’t run in CI / ephemeral environments.
- You want the absolute minimum surface area.
Add gity if:
- You have many repos, or one very large repo, or multiple worktrees.
- You want one tool to handle fsmonitor and prefetch and maintenance with one command.
- You run CI runners that need oneshot-mode acceleration.
- You want subscribe APIs for IDE integrations.
Coexistence
gity and the built-in daemon are mutually exclusive on a single repo — core.fsmonitor can be either true (built-in) or a path to a helper (e.g., gity). When you gity register a repo, gity sets the latter and you get the gity-managed pipeline. If you later run gity unregister, gity restores core.fsmonitor to whatever it was before.
You can mix-and-match across repos: gity-managed for your big monorepo, built-in for smaller repos. The two don’t conflict.
Try gity
cargo install gity
gity register ~/work/monorepo
That command:
- Stops Git’s built-in daemon for this repo (if running).
- Sets
core.fsmonitorto the gity helper. - Schedules prefetch + maintenance on the daemon’s idle scheduler.
If you decide gity isn’t worth it, gity unregister puts everything back. No commitment.
Frequently asked questions
Does Git have a built-in fsmonitor daemon now?
Yes, since Git 2.37. Set `core.fsmonitor true` (note: boolean, not a path) and Git starts a built-in daemon that watches the repo and answers fsmonitor v2 queries. It works on macOS, Linux, and Windows with no external dependency.
Why would I install gity if Git ships its own?
Three reasons: gity also runs background `git prefetch` and `git maintenance` on a CPU-aware scheduler, it shares cache between multiple worktrees of the same repo, and it has a `daemon oneshot` mode for CI. The built-in daemon does only the fsmonitor part.
Is there any downside to enabling Git's native fsmonitor?
Not really. It's a small daemon, it's safe to leave on, and it speeds up status by an order of magnitude. The only real cost is one daemon per repo that gets registered — if you have many repos, you may want a single shared daemon (which is what gity provides).