Benchmarks git client implementations against a clone of torvalds/linux:
| Runner | Implementation description |
|---|---|
git-cli |
Subprocess to system git |
libgit2-ffi |
bun:ffi bindings to system libgit2 |
gitoxide |
gix CLI (Rust) |
isomorphic-git |
Pure JS over node:fs |
ziggit |
Pure Zig implementation (Coming Soon) |
Operations measured:
- Current branch: Resolve
HEADto a short branch name. - Status: Worktree and index status (porcelain).
- Log (100): Walk the 100 most recent commits from
HEAD. - Tracked files: Enumerate all paths tracked in the index.
- Changed files: Name-only diff between
HEAD~1andHEAD. - Read 25 blobs: Read 25 fixed file blobs at
HEADby path.
gitonPATH(used by thegit-clirunner and the clone script).gixonPATHfor thegitoxiderunner (install viacargo install gitoxide).libgit2shared library installed system-wide for thelibgit2-ffirunner (e.g.,apt install libgit2-devorbrew install libgit2). SetGIT_BENCH_LIBGIT2=/path/to/libgit2.soif auto-detection fails.
If a runner is missing dependencies, its results are reported as err to make the missing requirement obvious.
Note
The isomorphic-git runner is limited to operations current-branch and status due to the Linux kernel pack files exceeding the maximum size it can read into a single Buffer (>2 GB). This limitation of the pure-JS implementation is itself a benchmark result.
bun install
bun run bench:clone # Clone torvalds/linux (~5 GB)
bun run bench # Run benchmarks and write to lib/bench/results.json
bun run dev # Start the dashboard at http://localhost:3000Environment overrides:
REPO_DIR: Path to the cloned repository (defaults to.git-bench-repos/linux).SAMPLES: Samples per operation (defaults to5).GIX_BIN:gixexecutable path (defaults togixonPATH).GIT_BENCH_LIBGIT2: Explicit path tolibgit2.sofor the FFI runner.
Each runner runs one warmup iteration, followed by SAMPLES timed iterations of each operation. Setup tasks (like opening the repository or loading JS modules) run outside the timed region to avoid skewing the results. The dashboard displays the median time per operation; the underlying JSON also records the mean, min, max, and sample count.
The libgit2-ffi runner includes minimal bindings (initialization, opening the repository, and resolving HEAD). The remaining operations are stubbed; you can add bindings in scripts/runners/libgit2-ffi.ts to implement them.
