Skip to content

Scale, serving and tooling

Git keeps several optional files next to its objects that make large repositories fast. None of them hold new information; each is a cache of something Git could compute from objects, and Git falls back to computing it when the file is missing. This page also covers serving transfers and Git’s standalone tools.

.git/objects/info/commit-graph indexes a set of commits by parents, root tree, commit date and generation number in a compact indexed table. Without it, each step of a history walk finds, decompresses and parses a commit object; with it, a step is an array lookup.

A commit’s generation number is one more than its parents’ highest. A commit can’t be an ancestor of a commit with a lower or equal generation, so walks can stop as soon as they pass below the target’s generation instead of visiting the whole excluded history. Newer files can also store corrected commit dates: the greater of the commit’s date and one more than every parent’s corrected date. These remain ordered even when commit clocks disagree.

Optional changed-path Bloom filters can rule out changes to a path relative to the first parent. A positive answer can be a false positive and requires comparison; merge filters do not rule out differences from other parents. Git writes a standalone graph during git gc by default unless gc.writeCommitGraph disables it. Default git maintenance run writes split chains, as does its explicit commit-graph task. Reading an existing graph is enough to benefit. Girt attaches valid graphs to repository object readers by default, honoring core.commitGraph=false; unusable graphs fall back to object reads, and object verification is available explicitly.

girtPartialSingle/split reading and writing, explicit verification, default indexed history and first-parent Bloom queries; opening overhead and automatic GC writing remain. Remaining work is tracked in #492.API docs

A quiet-window comparison on 82,500 commits found a 351-commit range taking 28.7 ms after opening validation improvements, versus 113.8 ms before and 16.1 ms for Git log. Ancestry took 27.0 ms versus 118.8 ms before and 9.54 ms for Git. These warm process totals are 1.78 and 2.83 times Git; opening still dominates at about 19–20 ms. The timing issue and opening-cost follow-up link raw measurements and memory evidence. This is progress, with remaining opening cost, rather than Git parity.

Repositories collect many packs, roughly one per fetch, and an object lookup checks each pack’s index in turn. A multi-pack index (.git/objects/pack/multi-pack-index) is one index across all packs, so a lookup is a single binary search however many packs there are.

girtPartialissue #517

A reachability bitmap stores, for selected commits, one bit per object in a pack saying whether it is reachable from that commit. “Which objects does this client need?” becomes bitwise operations (reachable from the wants, minus reachable from the haves) instead of a graph walk. Bitmaps make serving clones and fetches fast, and speed up counting objects and repacking.

girtNot yetissue #518

Status checks every tracked file’s stat data and scans every directory for untracked files. On a monorepo that takes seconds. fsmonitor (core.fsmonitor=true) asks a file-watcher daemon which paths changed since the last query, so Git only checks those. The untracked cache (core.untrackedCache), an index extension, remembers directory listings so finding new files doesn’t rescan unchanged directories. Together they make status take milliseconds.

girtNot yetissue #519

The server side of transfer runs git-upload-pack for fetch and clone and git-receive-pack for push: advertise refs, negotiate, build a pack, or receive one and apply ref updates. A Rust forge, a jj server or self-contained test fixtures need this.

girtNot yetissue #520

git clone --filter=blob:none downloads every commit and tree but no file contents. The repository records the remote as a promisor, and any later read of a missing blob fetches it on demand. Large repositories clone in a fraction of the time. Everything that reads objects has to know a missing object may be promised rather than lost.

girtNot yetissue #521

A bundle (git bundle create repo.bundle --all) is one file holding a pack plus a list of refs: a portable snapshot of some or all of a repository. You can clone or fetch from it like a remote. It is used to move repositories without a network and for bundle URIs, where a server points clients at a prebuilt bundle on a CDN to download first, then fetches the rest.

girtNot yetissue #523

git fsck checks a repository’s integrity: every object parses and hashes to its ID, every ref points at an existing object, and every object reachable from a ref is present. It also reports unreachable (“dangling”) objects.

girtPartialPack verification and connectivity checks on fetch; no whole-repository check.issue #524

git grep searches file contents in the working tree, the index, or any commit’s tree, limited by pathspecs. By default it searches tracked files, including tracked files that match .gitignore; ignore rules only matter with --untracked. Searching a commit reads blobs straight from the object database, without a checkout.

girtNot yetissue #525

git archive --format=tar v1.0 exports a tree as a tar or zip file, leaving out paths with the export-ignore attribute. Release tooling uses it to build source tarballs.

girtNot yetissue #526

git bisect binary-searches history for the commit that introduced a bug. You mark one commit good and one bad; Git checks out a commit halfway between, you test it and mark it, and after about log₂(n) steps it names the first bad commit. It is mostly history-walk logic plus a little state in .git/BISECT_* files.

girtNot yetissue #527

rerere (“reuse recorded resolution”, rerere.enabled=true) records how you resolved a merge conflict under .git/rr-cache/ and resolves the same conflict automatically next time, which helps when rebasing a long-lived branch repeatedly.

girtNot yetissue #528

A ref refs/replace/<id> makes Git transparently use another object wherever <id> is read, for example to stitch an imported old history onto a newer one. Grafts (.git/info/grafts) are the older, deprecated form. Where they are used, a tool that ignores them shows different history from Git.

girtNot yetissue #529

Hooks are programs Git runs at set points: pre-commit and commit-msg before a commit, post-checkout after checkout, pre-push before a push. They live in .git/hooks/ or the directory in core.hooksPath, and a non-zero exit from a pre- hook stops the operation. Tools that commit or push on a user’s behalf may need to run a repository’s hooks the way Git does.

girtNot yetissue #530

git gc --auto runs after many commands and repacks when there are more than gc.auto loose objects (6700 by default) or gc.autoPackLimit packs (50). git maintenance schedules tasks such as writing the commit-graph, prefetching and incremental repacking. Both decide when the individual operations (repacking, packing refs, pruning) should run.

girtPartialgc.auto applies to packing refs only; no policy for repacking or pruning.issue #531