Repack a Git Repository Safely with git repack
You will finish with a smaller, packed Git object database, a verification check, and a clear choice between ordinary repacking and cleanup of unreachable objects. The examples match Git 2.43.0 from package git 1:2.43.0-1ubuntu7.3 and its matching git-man package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a repository you can maintain, enough free disk space for a temporary second pack, and a shell. These commands are normally unprivileged. Do not use sudo merely because the repository is large; fix ownership or permissions separately if Git cannot write its object directory.
Checkpoint
Work from the repository root, and make sure no fetch, push, commit or backup job is changing it while you repack.
1. Inspect the repository before changing it
Change to the repository and record its current object counts. This is read-only:
$ cd /path/to/repository
$ git status --short
$ git count-objects -v
git count-objects -v reports loose objects, objects already in packs, the number of packs, and the approximate packed size. A non-zero count is a reason to consider an incremental repack, not proof that anything is wrong. A clean status is useful evidence that you are operating on the intended checkout, but repacking affects the object database rather than tracked files.
Keep the output. You will compare it after the operation. If the repository is bare, omit git status --short; run the count command from its Git directory instead.
2. Run the normal incremental repack
Start with the least surprising form:
$ git repack
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to ... threads
Compressing objects: 100% (...), done.
Writing objects: 100% (...), done.
The exact progress lines vary with repository size and terminal output. Without -a, Git packs objects that are not already in a pack. Existing packs remain in place. This is a useful maintenance operation when a repository has accumulated loose objects but you do not need to consolidate all existing packs.
Run the count again:
$ git count-objects -v
count: 0
in-pack: 6
packs: 1
The numbers are repository-specific. Look for loose-object count falling and in-pack increasing, not for these exact values.
3. Consolidate packs only when you need to
Use -a when you deliberately want all reachable objects packed together. Add -d to remove existing packs that have become redundant and to run git prune-packed:
$ git repack -ad
This changes the object database and can require substantial temporary disk space. It does not rewrite commits or alter the working tree, but removing redundant pack files is not a step to run during concurrent fetches or pushes. Schedule it during a quiet maintenance window and keep a current repository backup.
Warning
-ad is a cleanup operation. If the repository contains objects you may need but that are not reachable from references, do not use it casually. Inspect first with:
$ git fsck --full --no-reflogs --unreachable
Reflogs can retain otherwise unreachable commits, so excluding them from this inspection is intentionally conservative only for finding objects outside the reflog view. Do not delete or expire reflogs as part of this guide.
4. Choose a policy for unreachable objects
The flags have different outcomes:
-a -dpacks referenced objects and removes redundant packs. Unreachable objects left behind can be removed by normal pruning rules.-A -dalso repacks all referenced objects, but loosens unreachable objects from existing packs instead of leaving them in an old pack to be removed immediately. A latergit gccan prune them according to its expiry rules.--cruft -dstores unreachable objects in a separate cruft pack. This is useful when you want unreachable data to remain subject to normal expiry rather than disappearing with a pack replacement.
Do not combine these choices by habit. The appropriate mode depends on whether recovery of abandoned commits matters to your retention policy. For a routine first pass, use plain git repack; for consolidation, establish that policy before using -ad or a cruft mode.
5. Limit resource use when necessary
Delta compression trades CPU and memory for smaller packs. Git 2.43.0 uses a default delta window of 10 and maximum delta depth of 50. Reduce the window or depth if a maintenance job competes with other workloads:
$ git repack -ad --window=5 --depth=25
--window-memory=512m adds a memory limit for the compression window. The manpage warns that actual use is multiplied by the number of pack-object threads, so set both deliberately on a constrained host:
$ git repack -ad --window=10 --window-memory=512m --threads=2
These values are examples, not universal tuning advice. Measure the job on a representative clone. -q suppresses progress, but it does not reduce the work; leave progress enabled for an interactive maintenance run.
6. Verify the result and recover if needed
After any repack, check reachability and compare object counts:
$ git fsck --full
$ git count-objects -v
count: 0
size: 0
git fsck --full should complete without errors. Counts, pack names and sizes vary. A successful repack does not prove that a backup is restorable, so test the backup separately.
If the command fails for lack of space or is interrupted, do not remove files from .git/objects/pack by hand. Git normally leaves the old pack available while a new pack is written. Free space, stop competing jobs, and rerun the command. If git fsck --full reports missing or corrupt objects, stop making changes and restore the repository from a known-good backup; do not try random combinations of git gc, git prune and repack flags.
Done means
- You recorded
git count-objects -vbefore and after the operation. - Loose objects were repacked without changing commits or the working tree.
- You used
-aand-donly after choosing an unreachable-object policy. - The repository was quiet during pack replacement and had enough free space.
git fsck --fullcompleted without errors.