grit://cooking/dogfood← what’s cooking
Wednesday, October 28, 2026 · Windows 11 10.0.26200

Dogfood on win-x64: Large-monorepo engineer

6 repos · 33 commands · 0 broken · 8 slow · 4 filed

Monorepo persona on win-x64: built main 22ec3d0 and ran a 120k-file daily loop (add/commit/status/diff/stash/switch/sparse), git/git and cargo at depth, 100k refs, 2x1 GiB binaries, untracked/ignored-heavy trees and Windows-specific cases (locked file, case collisions, CRLF, unicode names). Speed and memory are mostly at or better than git; all 6 fixes re-verified as fixed. Found 4 new bugs: a git-visible UNTR interop warning, add reporting mtime-only changes as staged, 6-10x slowness of clean/status --ignored walks, and a 13-25x cold loose-object read gap (gc/fsck) on Windows.

os
Windows 11 10.0.26200 · x86_64
machine
win-x64 self-hosted worker (Intel i5-12400, 4 logical CPUs visible, 16 GB RAM, NTFS, Defender real-time protection on)
versions
grit none on PATH; built from main: grit 0.5.23 · main 22ec3d07 · git version 2.55.0.windows.5 (system config: core.autocrlf=true, core.symlinks=false, core.fscache=true)
repositories6
repofilescommits.gitnotes
git/git (local clone)4,85782,605323 MB
git/git + 100k loose refs4,85782,605349 MB50k branches + 51k tags
rust-lang/cargo3,07823,58882 MB
scratch/mono-120k120,000751 MBgenerated pkg/mod/f tree, autocrlf=true, plus 60k untracked + 60k ignored files in later tests
scratch/bin-2x1GiB20222,049 MB
scratch/lg-30k-loose30,000110 MB31.5k loose objects, used for gc/fsck cold-read tests
commandsgrit vs. system git, wall time
commandrepogritgitgrit/gitresultnotes
grit clone <local git/git>git/git1.87 s1.66 s1.1×ok
grit status (clean)git/git256 ms355 ms0.7×ok
grit log -- builtin/log.cgit/git582 ms610 ms1.0×ok
grit blame diff.cgit/git1.63 s1.18 s1.4×ok
grit revs --count HEADgit/git730 ms743 ms1.0×ok1.75x git RSS
grit merge-base v2.0.0 v2.40.0git/git82 ms451 ms0.2×ok
grit log --since=2024-01-01git/git332 ms154 ms2.2×ok
grit gc (already packed)git/git1.35 s9.30 s0.1×ok
grit repack -fgit/git33.82 s36.50 s0.9×okpack 154.3 vs 149.8 MiB; git fsck --strict clean except upstream badFilemode
grit clone https://github.com/rust-lang/cargorust-lang/cargo27.43 s43.24 s0.6×okgit RSS is wrapper process only
grit fetch (200 behind)rust-lang/cargo631 ms837 ms0.8×ok
grit add (120k new files)scratch/mono-120k213.70 s367.50 s0.6×ok
grit commit (120k staged)scratch/mono-120k8.60 s65.24 s0.1×ok
grit status (clean)scratch/mono-120k310 ms169 ms1.8×ok
grit status (5000 touched)scratch/mono-120k999 ms468 ms2.1×ok
grit diff --stat (5000 touched)scratch/mono-120k832 ms871 ms1.0×ok
grit add (5000 touched)scratch/mono-120k3.63 s9.37 s0.4×okreports mtime-only files as staged: #2241
grit commit (5000 staged)scratch/mono-120k9.63 s3.22 s3.0×slow3.0x; commit of already staged files does ~2 ms/file of extra work (cf. #1884)
grit commit (1 file, auto-stage)scratch/mono-120k627 ms181 ms3.5×slow3.5x, known #1884
grit switch base (18k files differ)scratch/mono-120k5.33 s6.46 s0.8×ok
grit switch wide (first run after commit)scratch/mono-120k70.83 s8.66 s8.2×slowone-off cold run; repeated at 6.2 s vs git 8.4 s; not reproducible
grit stash / stash pop (3000 edits)scratch/mono-120k8.42 s4.99 s1.7×okpop 765 ms vs 1916 ms, 48 MB vs 89 MB
grit reset --hard (cone sparse, 300 visible)scratch/mono-120k235 ms180 ms1.3×ok
grit status --ignored (60k untracked + 60k ignored)scratch/mono-120k2.78 s468 ms5.9×slow5.9x, filed #2242
grit clean --dry-run (60k untracked + 60k ignored)scratch/mono-120k6.05 s597 ms10×slow10x, 5.1 s kernel time, filed #2242
grit rebase --onto (1 commit, 18k files)scratch/mono-120k9.01 s16.86 s0.5×okresulting tree identical to git's; first run on fresh clone 15.5 s vs 21.2 s
grit add / commit / status / switch / diff --stat / gc (2 x 1 GiB blob)scratch/bin-2x1GiB20.24 s27.36 s0.7×okadd 1 GiB; status modified 847 vs 2316 ms; diff --stat 2.1 GB vs 2.6 GB RSS; gc 11.8 vs 11.6 s, RSS 2.1 GB equal to git's pack-objects
grit branch (50k branches, 100k refs)git/git + 100k loose refs1.64 s4.31 s0.4×okfull listing 1.8 s with ReadToEnd; my first harness reading line-by-line events inflated it to 210 s, harness artifact
grit clone <local, 100k refs>git/git + 100k loose refs13.10 s92.90 s0.1×ok
grit status (100k refs)git/git + 100k loose refs263 ms30 ms8.8×slow8.8x but sub-300 ms absolute; same as the no-refs repo (256 ms), git hit its fast path
grit gc pack-refs + reflog expire (100k refs)git/git + 100k loose refs18.89 s59.21 s0.3×okfirst 20k-ref gc outlier (86 s) did not reproduce on retry (7 s)
grit gc (31.5k fresh loose objects)scratch/lg-30k-loose142.83 s10.59 s13×slow13x, filed #2243; same in reverse order
grit fsck (31.5k fresh loose objects, cold)scratch/lg-30k-loose39.16 s1.38 s28×slow28x cold; warm re-run 2.5 s; filed #2243
worked5
  • ›Memory at 120k files is consistently below git for add, commit, status, diff, stash and rebase; all 6 previously fixed issues hold on Windows.
  • ›Locked-file switch on Windows fails with a clear message and leaves HEAD, index and tree unchanged (git half-switches).
  • ›autocrlf / eol attributes / case-collision clone / unicode, emoji and CJK filenames / read-only file and dir<->file transitions all interoperate with git; json output well-formed.
  • ›Large-binary lifecycle (2 x 1 GiB) at parity with git including gc/repack RSS; repack -f matches git in time and size.
  • ›Many-refs listing, clone and pack-refs faster than git on NTFS; grit rebase --onto produced the identical tree to git.
problems9
  • ›#2240 filed: grit writes a UNTR index extension (ident 'Location <backslash path>, system unknown') for repos >= ~5k files; git warns 'untracked cache is disabled' on every status.
  • ›#2241 filed: grit add (human and --json) reports mtime-only changes as Staged/modified and counts them.
  • ›#2242 filed: clean --dry-run 10x and status --ignored 6x slower than git on 60k untracked + 60k ignored files (kernel time dominated).
  • ›#2243 filed: cold reads of freshly written loose objects 13-28x slower than git (gc 143 s vs 10.6 s; fsck 39 s vs 1.4 s); explains ~9.5 min background gc --auto on 130k loose objects.
  • ›Not filed (dup #1884): grit commit of already-staged 5000 files takes 9.7 s vs git 3.2 s; single-file commit 3.5x slower.
  • ›Not filed (minor): grit loose objects are ~39% larger than git's (37.7 MB vs 27.1 MB for 120k small blobs, same zlib level 1 header); disk impact small on NTFS.
  • ›Not filed (minor): grit config --system help says /etc/gitconfig on Windows; grit config has no list/--show-origin form and error 'key does not contain a section: list' is confusing.
  • ›Not filed: Windows timing noise. Several first-touch runs (switch wide 70 s, rebase 131 s, 20k-ref gc 86 s) were 5-15x slower than identical warm repeats and not reproducible; likely Defender scanning of just-written files.
  • ›Observed that #1814 (switch/reset --hard ignoring cone sparse) looks fixed on main: switch/reset kept exactly 300 files in a cone checkout; not verifying it formally since it is open.
bugs filed4
#2240 #2241 #2242 #2243already reported: #1884 #1702 #1814 #1859
next time
  • ›Find the root cause of #2243 with Process Monitor: compare CreateFile access masks, share modes and number of opens per loose object between git and grit; try reading with FILE_FLAG_SEQUENTIAL_SCAN or parallel reads, and recheck background gc --auto at 130k loose objects.
  • ›Profile the Windows directory walk behind #2242: DirEntry metadata vs per-path stat; recheck status/clean/add on trees with 500k files and deep nesting; also check #2173 long paths.
  • ›Library angle: write a grit-lib program that opens the 120k repo and computes status/diff/tree-walk with RSS, compare with the CLI, and look at API docs for walk/status entry points.
  • ›Server-side flow (grit serve + checkout/checkin/integrate/slice) on Windows with 1M-path snapshots, and concurrent checkouts.
  • ›Cold-vs-warm methodology: add a Defender exclusion-free control (copy via robocopy then wait for scan idle) to separate OS noise from grit regressions; repeat 120k-file `grit commit` with staged files to localise the 2 ms/file extra work behind #1884.