Build and Check a Git Commit-Graph Safely
You will create a commit-graph in a Git repository, verify it against the object database, and understand what changed on disk. Git can use this extra index to answer parts of history traversal more quickly, especially when a repository has many commits. The graph does not replace commits, refs or packfiles.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes for a normal repository. You need Git 2.43.0 or a compatible Git installation and write access to the repository. The examples below use the installed git-man package version 1:2.43.0-1ubuntu7.3. Run these commands as the repository owner. Elevated privileges are not normally needed and can leave root-owned maintenance files behind.
1. Confirm the installed command
Start with read-only checks. This separates a command-version problem from a repository problem and does not change any files:
$ git --version
git version 2.43.0
$ git commit-graph -h
usage: git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]
or: git commit-graph write [--object-dir <dir>] [--append]
[--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]
[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]
The subcommands used here are write and verify. If your help output does not contain them, stop and read the manual for the Git version actually installed on that host.
2. Inspect the repository before writing
Change to the target repository and check that Git sees it as a worktree. These are ordinary, read-only commands:
$ cd /path/to/repository
$ git rev-parse --show-toplevel
/path/to/repository
$ git rev-parse --git-dir
.git
$ git config --get core.commitGraph || echo 'core.commitGraph is unset'
A repository can have an unset core.commitGraph; that is not an error. The default behaviour is to use commit-graphs when available. If the value is explicitly false, write prints a warning and returns success without writing a graph. That success status is a distraction trap: always inspect the expected location afterwards.
Checkpoint
You are in the intended repository, and you know whether a local configuration setting disables commit-graph use.
3. Write a graph for the repository
Run the basic write command first:
$ git commit-graph write
$ printf 'write status: %s\n' "$?"
write status: 0
For the usual repository layout, Git writes the graph below .git/objects/info/commit-graph. Check the file without assuming that every repository has the same layout:
$ git rev-parse --git-path objects/info/commit-graph
/path/to/repository/.git/objects/info/commit-graph
$ test -r "$(git rev-parse --git-path objects/info/commit-graph)" && echo 'commit-graph is readable'
commit-graph is readable
The command is based on commits found in packfiles. A repository with only loose objects, or a repository whose graph is disabled, may not produce the file you expect. Do not create an empty file by hand: it is a binary format with checks and object references.
Writing is a maintenance operation and can take time on a large repository, but it does not rewrite commits. It can replace or remove commit-graph data, so take care if another process is running repository maintenance at the same time. There is no useful manual undo for an interrupted write; let the command finish, then verify. If you need to remove a graph, use your normal Git maintenance procedure rather than deleting arbitrary files while Git is active.
4. Verify the graph against the object database
Verification reads the graph and checks its contents against the repository objects:
$ git commit-graph verify
$ printf 'verify status: %s\n' "$?"
verify status: 0
Success is normally quiet. A non-zero status means Git found a problem or could not read the graph. Capture the complete diagnostic, then check that the repository is not being modified by another Git process. Do not "fix" a verification failure by deleting the object database or running a broad cleanup.
If there is no graph to verify, Git may report that it cannot open the commit-graph file. That means the earlier write did not create one, often because there are no suitable packed commits or core.commitGraph is disabled. Re-run the inspection in step 2 before changing configuration.
Checkpoint
git commit-graph verify returns status 0. This is the useful completion test, not merely a successful write command.
5. Include all reachable commits when needed
The basic write operation considers packed commits. To build from commits reachable from every ref, provide the ref tips as commit IDs:
$ git show-ref -s | git commit-graph write --stdin-commits
$ git commit-graph verify
$ printf 'reachable graph status: %s\n' "$?"
reachable graph status: 0
--stdin-commits expects one hexadecimal object ID per line. Malformed or missing IDs are errors; non-commit objects can be ignored. Do not combine this option with --reachable or --stdin-packs, because those are alternative input modes.
--reachable is the shorter form when you want Git itself to walk from all refs:
$ git commit-graph write --reachable
$ git commit-graph verify
Use one mode at a time. Keep the explicit stdin form for scripts where you want the input set to be visible in the command pipeline.
6. Add changed-path data deliberately
Path history commands such as git log -- path/to/file can benefit from changed-path Bloom filters. Ask Git to compute them with --changed-paths:
$ git commit-graph write --reachable --changed-paths
$ git commit-graph verify
Verification may print progress, depending on the repository and whether standard error is connected to a terminal. The command may take considerably longer on a large repository. This option also influences future writes by recording that changed-path data is intended. To rewrite without storing it, use --no-changed-paths.
On this installed Git, the default commitGraph.generationVersion is 2. Avoid changing it just to make a write succeed. If several machines use different Git versions, also check their support for the graph and Bloom-filter format before sharing a repository between them.
7. Use split graphs only for a reason
A split graph stores layers below objects/info/commit-graphs:
$ git commit-graph write --reachable --split
$ git commit-graph verify
$ git rev-parse --git-path objects/info/commit-graphs
/path/to/repository/.git/objects/info/commit-graphs
The bare --split lets Git apply its merge rules. --split=no-merge keeps adding tip layers, while --split=replace replaces the existing chain with a newly written one. Those choices affect maintenance cost and disk contents, so do not add them automatically to a one-off repair command. A later split write can remove unused graph layers as part of its normal expiry behaviour.
If you are investigating a split-chain failure, git commit-graph verify --shallow checks only the tip graph. That is a narrower diagnostic, not proof that every layer is valid. Use plain verify for the final check.
Common failure boundaries
- Replace objects or grafts: Git disables commit-graph reading and writing when replace objects or commit grafts are active. Check that repository state before treating a missing graph as corruption.
- Wrong object directory:
--object-dir <dir>is for a known alternate object directory containinginfoandpack, not an arbitrary output folder. Git rejects a path that is not an absolute, known object directory. - Concurrent maintenance: do not run this alongside another process that is repacking or changing refs. Wait for the other operation, then write and verify again.
- Configuration surprises: inspect
core.commitGraphand anycommitGraph.*settings before assuming that an option's default applies.
Done means
- You confirmed the installed Git version and command syntax.
- You inspected the target repository and its commit-graph configuration.
- You wrote the graph using one deliberate input mode.
- You ran
git commit-graph verifyand received status 0. - You chose changed-path filters or split storage only when their trade-offs fit the repository.
- You left commits, refs and packfiles untouched.