Measured against git

The numbers below are real hyperfine runs of both CLIs on one machine.

Large files & media

The workload mkit is built for: big, incompressible files and small edits to them. Content-defined chunking means a small edit costs the changed chunk, not the whole file — on disk, on the wire, and in wall-clock time.

Time, end to end

Wall-clock time for whole CLI invocations, mean of repeated runs. Lower is better.

commit a 1 MiB change to the 100 MiB file

mkit 5.0× faster

Append 1 MiB to the already-committed 100 MiB file, then add + commit the new version.

mkit
409 ms
git
2.04 s

mkit wins by ~5.0×: content-defined chunking re-hashes the file but stores only the changed chunks, so the second version costs about a megabyte. git re-compresses and stores the whole 101 MiB blob again.

add + commit one 1 GiB file

mkit 3.6× faster

Same shape at 1 GiB, 3 runs each.

mkit
5.12 s
git
18.5 s

mkit wins by ~3.6×. First ingest scales linearly for both tools; mkit’s wall clock is I/O + BLAKE3.

add + commit one 100 MiB file

mkit 2.8× faster

A single 100 MiB file of incompressible bytes (a stand-in for video or other compressed media).

mkit
769 ms
git
2.15 s

mkit wins by ~2.8×: the file splits into ~1,600 content-defined chunks, each hashed with BLAKE3 and barrier-synced from a thread pool, while git’s SHA-1 + zlib pass stays CPU-bound. mkit’s flush cost is constant per commit, not per chunk.

Bytes on disk

Repository directory size (du -k .mkit vs .git) after the same operations. Lower is better.

one 100 MiB file, one commit

Repository size after the first commit of the 100 MiB file.

mkit
102.5 MiB
git
112.5 MiB

Roughly even: incompressible input means zlib buys git nothing, so both stores hold roughly the content plus bookkeeping (the gap is mostly filesystem allocation, not format).

growth after a 1 MiB change

Additional repository bytes after appending 1 MiB to the 100 MiB file and committing the second version.

mkit
1.1 MiB
git
112.1 MiB

mkit stores ~1.1 MiB: the appended megabyte, one re-cut boundary chunk, and a fresh manifest. git’s loose store duplicates the whole ~112 MiB blob until git gc repacks it back to ~zero growth, so mkit’s store is incremental by construction while git’s is dense only after a maintenance pass.

Bytes on the wire

What a push sends after a small edit to a large file the remote already holds. Delta-on-the-wire encodes the changed chunk against the version the remote has, instead of re-uploading it whole. Lower is better.

push a 16-byte edit to a 2 MiB file

47× smaller push

Edit 16 bytes in the middle of a 2 MiB FastCDC-chunked file the remote already holds, then push the new commit. Bytes counted on the wire.

whole
71.0 KiB
delta
1.5 KiB

The chunk delta is 93 bytes; the rest of the ~1.5 KiB is the new manifest, tree, commit, and packmap node, versus re-sending the whole ~71 KiB re-cut chunk. Delta is a transfer encoding only — it is used only when it beats the raw chunk, and every reconstructed object is re-verified against its hash before storage.

Everyday operations

The routine git operations on ordinary trees, where the honest verdict is roughly even. mkit keeps pace while signing every commit and flushing every object to disk, neither of which git does by default.

Time, end to end

Wall-clock time for whole CLI invocations, mean of repeated runs. Lower is better.

add + commit 100 small files

mkit 1.8× faster

100 files of 10 KiB random bytes each, staged and committed in one shot.

mkit
166 ms
git
296 ms

mkit wins by ~1.8× while making every commit crash-durable (git does not fsync loose objects by default). Durability is batched behind two fixed full flushes, then renamed into place — git’s core.fsyncMethod=batch design, on by default.

re-add an unchanged 100 MiB file

mkit 1.2× faster

touch the committed file (mtime changes, bytes don’t) and run add again — a pure re-hash.

mkit
147 ms
git
174 ms

Close to a tie, mkit a hair ahead: the changed mtime invalidates both tools’ stat caches, so both re-read and re-hash 100 MiB in well under 200 ms and write nothing new.

init an empty repository

about even

mkit init vs git init in a fresh directory.

mkit
13.0 ms
git
13.5 ms

status with an unchanged 100 MiB file

about even

mkit status / git status in a clean repo holding the committed 100 MiB file, stat cache warm.

mkit
15.1 ms
git
14.6 ms

A tie. An unchanged file is proven clean by one stat call against the index stat cache — O(stat), no read, no hash, the same trick git plays.

Bytes on disk

Repository directory size (du -k .mkit vs .git) after the same operations. Lower is better.

100 small files, one commit

Repository size after committing 100 × 10 KiB of random bytes (1,000 KiB of content).

mkit
1.2 MiB
git
1.3 MiB

Effectively a tie — both store roughly the content plus per-object overhead.

Methodology & caveats

date: 2026-07-08
commit: eb5508b0
machine: Apple M4 Max, 16 cores, 128 GB RAM, APFS SSD, macOS 26.5.1
versions: mkit (development build, cargo build --release) · git 2.50.1 (Apple Git-155) · hyperfine 1.20.0
harness: scripts/bench-vs-git.sh — hyperfine with --warmup and per-command --prepare resetting a temp directory to a clean state between runs; 3 runs for the 1 GiB case, hyperfine defaults elsewhere; results from --export-json. Sizes via du -k.
workload: Random (incompressible) bytes, standing in for already-compressed media like video. Compressible source code would flatter git’s zlib store and is not what these benchmarks measure.
  • Signed vs unsigned: every mkit commit is Ed25519-signed; the git side runs unsigned, as git defaults to. Signing costs mkit well under a millisecond per commit, but the comparison is asymmetric.
  • Durability: mkit batches each command’s object writes behind two fixed full flushes plus per-file barriers (SPEC-OBJECTS §10.1), so a commit is durable when the command returns; git does not fsync loose objects by default. Per-object flushing is available via the durability.objects = per-object config key.
  • One machine, one filesystem, one day. Ratios on spinning disks, network filesystems, or Linux will differ — flush cost in particular is hardware-dependent.
  • Both tools were run through their CLI end to end (process spawn included), with stock configuration: no git core.fsmonitor, no mkit tuning.
← back