By admin , 29 April 2026

Performance vocabulary

"Performance at scale" can mean many things: clone time, log/blame speed, commit throughput, working tree size handling, network bandwidth efficiency, or scaling to thousands of concurrent contributors. Git and Mercurial have evolved on different fronts.

Clone and fetch

Git's pack files use aggressive delta compression; clones are typically efficient. Mercurial uses bundle files with similar compression. For repositories under 1 GB, both clone in a minute or two over a typical connection.

For larger repositories, Git's partial clone (--filter=blob:none) and shallow clone (--depth=1) provide significant speedups. Mercurial's narrowclone and streamclone serve a similar purpose but are less integrated into common workflows.

Local operations

Both systems perform local operations entirely from disk. Mercurial's pure-Python core was historically slower for some operations - hg log on million-commit repos took noticeably longer than git log. The Rust extensions (rust-cpython bindings, plus the rewriting effort in hgrust) have closed most of the gap.

# Benchmark: log on a million-commit repo
time git log --oneline | wc -l       # ~5-10 seconds
time hg log --template '{rev}\n' | wc -l  # ~10-20 seconds (varies)

Working tree size

Both systems do file-tree updates by walking trees and applying changes. For a checkout of a 100k-file repo, Git typically takes a few seconds; Mercurial similar. The bottleneck on most platforms is filesystem operations, not the VCS.

For monorepo scale (millions of files), neither system handles full checkouts gracefully. Sparse checkout (Git) and narrow checkout (Mercurial) become essential.

Memory usage

Mercurial's Python runtime imposes a memory floor higher than Git's C core - a few hundred MB for large operations versus Git's lower baseline. On modern laptops this is rarely a concern.

Repository storage

Both use content-addressed storage with delta compression. Git's pack files are repacked aggressively (git gc); Mercurial's revlogs are continuously compact. Comparable repositories tend to be within 10-20% of each other in size.

Concurrent operations

Git's index uses file locks; concurrent git status and git commit can serialise. Mercurial uses similar locking. For high-concurrency CI scenarios, both benefit from per-job clones.

Server-side scaling

Git servers (GitHub, GitLab, Gitea) routinely host repositories with hundreds of thousands of contributors. Optimisations include reachability bitmaps, multi-pack indexes, and protocol v2 (Git 2.18+).

Mercurial server scaling is less battle-tested at the same end of the curve - largely because the largest projects have not chosen Mercurial. The systems that have used Mercurial at extreme scale (Mozilla, Meta) built custom infrastructure.

Monorepo scale

Microsoft (Windows in Git via VFS for Git / Scalar) and Meta (Sapling, originally Mercurial-derived) faced the same problem: hundreds of GB of source, millions of files. Both built custom client-side virtualisation (only files you touch are materialised). The base VCS was less determinative than the engineering investment.

# Git with sparse checkout and partial clone
git clone --filter=blob:none --sparse https://example.com/monorepo.git
cd monorepo
git sparse-checkout init --cone
git sparse-checkout set apps/myapp shared/utils

# Mercurial with sparse and narrow
hg clone --narrow --include 'apps/myapp' --include 'shared/utils' \
  https://example.com/monorepo

Sapling and Scalar

Meta's Sapling is essentially "Mercurial reimagined for monorepos". It speaks Git over the wire and Mercurial-style commands locally. Microsoft's Scalar wraps Git with similar virtualisation. Both demonstrate that scaling beyond ordinary VCS performance requires more than choosing the "right" tool.

The pragmatic conclusion

At ordinary scale, performance is not a deciding factor. At extreme scale, neither off-the-shelf tool suffices. Pick the VCS by team, ecosystem, and tooling; invest in scale-out solutions when you actually face that problem.