Introduction
Git stores objects in two formats: loose (one file per object under .git/objects/xx/yyyy...) and packed (many objects in a single .pack file with a companion .idx). Packs are far more efficient on disk and on the wire.
Layout
.git/objects/
00/ ... loose objects, named by sha minus first two chars
pack/
pack-<hash>.pack # the data
pack-<hash>.idx # offset index
pack-<hash>.rev # reverse index (Git 2.31+)
Why packs
- One file per object is brutal on filesystems with millions of files.
- Packs apply delta compression: store similar blobs as a base plus a diff.
- Packs use zlib in addition to deltas.
- Smart fetch/push transfer pack data directly.
Triggering packing
git gc # routine maintenance
git gc --aggressive # heavier delta search
git repack -a -d -f # recreate one pack from all objects
git fetch # also can produce packs
Auto-gc fires when the repo accumulates too many loose objects; tune with gc.auto.
Inspecting packs
ls .git/objects/pack
git verify-pack -v .git/objects/pack/pack-<hash>.idx | head
git count-objects -v
verify-pack -v shows each object's type, size, packed size, and whether it is a delta against another object.
Multi-pack indexes
For very large repos, multiple packs can be unified by a single index:
git multi-pack-index write
git config core.multiPackIndex true
Reachability bitmaps
Bitmaps speed up reachability queries (used by clone and fetch on hosting servers):
git repack -adb # build bitmap
git config repack.writeBitmaps true
Bitmaps are most useful when serving many clones or when running large git rev-list queries.
Object compression details
A delta in a pack stores a base object reference and an instruction stream. The base may itself be a delta. Git limits delta chains via pack.depth (default 50). The chosen base is usually a similar blob, often a previous version of the same file.
Geometric repacking
Maintaining a single huge pack is expensive; rewriting it on every gc is wasteful. Modern Git supports geometric repacking, which keeps a chain of packs of geometrically increasing size and only repacks the small ones:
git repack --geometric=2 -d --write-bitmap-index
git config maintenance.incremental-repack.enabled true
git maintenance run --task incremental-repack
This makes routine maintenance bounded: each gc only touches the smallest packs. Combined with multi-pack indexes and reachability bitmaps, geometric repack is the recommended setup for large or busy repositories.
Common mistakes
Manually deleting a .pack file to reclaim space, breaking the repo. The pack contains many reachable objects; use git gc --prune instead. Running git gc --aggressive on a schedule; it is expensive and rarely improves over a normal gc. Keeping millions of loose objects (after a botched recovery) and then doing git status on a slow filesystem; pack first. Finally, transferring packs by copying files instead of using git clone --bare; you may miss the .idx or skip newer features like the multi-pack index.