Commit-Graphs, Multi-Pack Indexes, Maintenance, Garbage Collection, and Performance: Guided Hands-On Workflow and Core Operations
Generate a disposable repository with multiple packs, capture timings/object counts, write and verify commit-graph/MIDX structures, inspect pack storage, register isolated maintenance, and run safe repack/GC operations.
Learning objectives
- Measure commit/object/pack state before optimizing.
- Create several packfiles and validate them with verify-pack.
- Write/verify a MIDX and a changed-path commit-graph.
- Register maintenance without modifying real global configuration or OS scheduler state.
- Run explicit maintenance and non-pruning GC while verifying history invariants.
1. Create a disposable repository large enough to show storage transitions
The lab deliberately creates many small commits in batches. Each batch is repacked separately so the repository accumulates several packfiles before you create a multi-pack index.
Git Bash, Bash, or zsh
mkdir git-performance-lab
cd git-performance-lab
git init -b trunk repo
cd repo
git config user.name "Performance Lab"
git config user.email "performance-lab@example.invalid"
mkdir data
for i in $(seq 1 20); do
printf "seed=%s\n" "$i" > "data/file-$i.txt"
done
git add data
git commit -m "seed repository"
PowerShell setup alternative
New-Item -ItemType Directory git-performance-lab | Out-Null
Set-Location git-performance-lab
git init -b trunk repo
Set-Location repo
git config user.name "Performance Lab"
git config user.email "performance-lab@example.invalid"
New-Item -ItemType Directory data | Out-Null
1..20 | ForEach-Object { "seed=$_" | Set-Content "data/file-$_.txt" }
git add data
git commit -m "seed repository"
2. Capture a baseline before optimizing
git status --short --branch
git rev-parse HEAD
git rev-list --count HEAD
git count-objects -vH
git fsck --full
Record the current tip OID. Every maintenance operation in this lesson should preserve that commit and the branch history. Storage files may change; repository meaning should not.
3. Measure repeatably, but do not overinterpret tiny timings
Bash-family shells
time git rev-list --count HEAD
time git log --oneline -- data/file-1.txt >/dev/null
time git status --porcelain >/dev/null
PowerShell
Measure-Command { git rev-list --count HEAD | Out-Null }
Measure-Command { git log --oneline -- data/file-1.txt | Out-Null }
Measure-Command { git status --porcelain | Out-Null }
Run each command several times. The first run can include cold filesystem/page-cache costs; later runs can benefit from warm caches. This training repository is intentionally small, so “after” may not be faster even when an acceleration structure is working correctly.
4. Generate four history batches and create multiple packfiles
Git Bash / Bash / zsh
for batch in 1 2 3 4; do
for n in $(seq 1 30); do
printf "batch=%s item=%s\n" "$batch" "$n" >> "data/file-$(( (n % 20) + 1 )).txt"
git add data
git commit -m "batch $batch change $n" >/dev/null
done
git repack -d
git count-objects -vH
done
PowerShell
1..4 | ForEach-Object {
$batch = $_
1..30 | ForEach-Object {
$n = $_
$file = ($n % 20) + 1
"batch=$batch item=$n" | Add-Content "data/file-$file.txt"
git add data
git commit -m "batch $batch change $n" | Out-Null
}
git repack -d
git count-objects -vH
}
git repack -d in this disposable lab packs new loose
objects and removes redundant packs/loose duplicates that the new
pack makes unnecessary. Because earlier packs already contain older
objects, the batches can leave several packs.
5. Inspect pack count and verify each pack
git count-objects -vH
ls .git/objects/pack/
for idx in .git/objects/pack/*.idx; do
git verify-pack "$idx"
done
PowerShell pack verification alternative
git count-objects -vH
Get-ChildItem .git/objects/pack
Get-ChildItem .git/objects/pack/*.idx | ForEach-Object {
git verify-pack $_.FullName
}
verify-pack validates the pack index and associated
pack. With -v it can also show object types, compressed
sizes, offsets, and delta-chain depths. Do not parse its verbose
human output as a long-term application protocol unless the script
is explicitly tied to the documented format/version.
6. Write and verify a multi-pack index
git multi-pack-index write
git multi-pack-index verify
git count-objects -vH
The number of logical commits/objects does not change. The MIDX adds a lookup structure across the packs. Current Git can also write incremental/version-2 MIDX layers, but those newer formats have mixed-version compatibility considerations; this mandatory lab uses the broadly supported basic write/verify path.
7. Write a commit-graph with changed-path information
git commit-graph write --reachable --changed-paths
git commit-graph verify
git log --oneline -- data/file-1.txt >/dev/null
git rev-list --count HEAD
The commit-graph records reachable commits plus optional changed-path Bloom filters. It should not alter HEAD, refs, commit contents, or working-tree files.
8. Run explicit maintenance tasks one at a time
git maintenance run --task=commit-graph
git maintenance run --task=loose-objects
git multi-pack-index verify
git commit-graph verify
Passing --task makes the requested task explicit and
avoids relying on implicit strategy configuration during a teaching
lab.
9. Register maintenance using an isolated config file
Normal git maintenance register uses the user's global
Git configuration. The lab avoids changing your real global config
by supplying a disposable config file:
git maintenance register --config-file ../maintenance-demo.config
git config --file ../maintenance-demo.config --get-all maintenance.repo
git config --show-origin --get maintenance.strategy
git config --show-origin --get maintenance.auto
Current Git registration records the repository and, when no maintenance strategy was already configured, uses the incremental strategy for background-maintenance-style operation. It also disables foreground auto-maintenance for the registered repository. Exact configuration details should be verified on the installed Git version.
10. Understand scheduler integration without modifying your machine scheduler
git maintenance start installs user-level scheduled
maintenance through a platform scheduler. Current Git supports
scheduler choices such as systemd timers or cron on Linux, launchctl
on macOS, and Task Scheduler on Windows. That changes user-level
system configuration, so it is not required in this
lab.
# Inspection only: see what the current repository registered.
git config --file ../maintenance-demo.config --list --show-origin
# Optional on a disposable machine/profile only:
# git maintenance start --scheduler=auto
11. Demonstrate incremental repack through maintenance
git multi-pack-index write
git maintenance run --task=incremental-repack
git multi-pack-index verify
git count-objects -vH
The task uses the multi-pack-index mechanism to consolidate smaller packs gradually. A later expire step can remove packs that the MIDX no longer references. The exact pack count may vary because the selection is size-dependent.
12. Run GC only with pruning disabled in this disposable lab
BEFORE=$(git rev-parse HEAD)
git gc --no-prune
AFTER=$(git rev-parse HEAD)
test "$BEFORE" = "$AFTER"
git fsck --full
git count-objects -vH
gc --no-prune can still reorganize packs, refs, and
auxiliary structures, but it does not prune loose unreachable
objects. The branch tip must remain unchanged.
13. Compare measurements after maintenance
git rev-list --count HEAD
git count-objects -vH
git commit-graph verify
git multi-pack-index verify 2>/dev/null || echo "MIDX may have been replaced/removed by later GC"
time git rev-list --count HEAD
time git log --oneline -- data/file-1.txt >/dev/null
time git status --porcelain >/dev/null
A later full GC may consolidate pack layout enough that a MIDX is unnecessary or regenerated differently. Treat the absence of a previously written acceleration file as an implementation outcome to re-measure—not as history loss.
14. Challenge — choose the narrowest operation
- You have many loose objects but one healthy pack. Which evidence command comes first?
- You have many packs but do not want an all-into-one repack. Which maintenance mechanism is designed for gradual consolidation?
- Path-history queries are expensive. Which auxiliary structure can add changed-path Bloom filters?
- You want to validate pack storage without changing it. Which command?
- You want maintenance registration without touching your real global config in a lab. Which register option?
15. Cleanup
cd ../..
pwd
rm -rf git-performance-lab
PowerShell equivalent:
Set-Location ../..; Remove-Item -Recurse -Force
git-performance-lab.
16. Knowledge check
Question 1. What state should remain unchanged when you write a MIDX or commit-graph?
Question 2. Why is one timing run insufficient?
Question 3. What does
git verify-pack validate?
Question 4. Why was git gc --no-prune used in the
lab?
Question 5. Why is git maintenance start optional
here?
17. Summary
You measured object storage, created multiple packs, verified them, added MIDX and commit-graph acceleration, registered isolated maintenance state, ran explicit maintenance tasks, and demonstrated non-pruning GC. The key invariant was that optimization changes representation, not repository meaning.
Authoritative references
git-count-objects
git-repack
git-verify-pack
git-multi-pack-index
git-maintenance
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.