git gc: Garbage Collection
Over time, a Git repository accumulates loose objects — individual
blobs, trees, commits, and tags stored as separate files under
.git/objects/. It also accumulates reflog entries, stale
remote-tracking references, and fragmented pack files. Left unattended,
these can bloat your repository and slow down operations. git gc
(garbage collection) is Git's built-in housekeeping command that
cleans up all of this efficiently.
What git gc Does
Packs loose objects into efficient pack files using delta compression
Removes unreachable loose objects that are older than
gc.pruneExpire(default 2 weeks)Prunes old reflog entries that have expired beyond
gc.reflogExpire(default 90 days)Removes stale remote-tracking references that no longer exist on the remote
Repacks existing pack files to eliminate redundancy and improve access speed
Writes a commit graph (in newer Git versions) for faster reachability queries
Basic Usage
Running git gc without flags performs a standard cleanup. It runs
incrementally — it will skip tasks that don't need doing yet.
Running git gc
git gc
Example output
Enumerating objects: 1532, done. Counting objects: 100% (1532/1532), done. Delta compression using up to 8 threads Compressing objects: 100% (612/612), done. Writing objects: 100% (1532/1532), done. Total 1532 (delta 891), reused 0 (delta 0), pack-reused 0 Removing duplicate objects: 100% (1/1), done.
git gc --aggressive
The --aggressive flag instructs Git to spend considerably more CPU time on delta compression, potentially producing smaller pack files. It re-examines every object to find optimal delta chains rather than reusing existing ones. This can take minutes to hours on large repositories.
Aggressive garbage collection
git gc --aggressive
git gc --auto
Git automatically invokes git gc --auto as a background step after many write operations such as git commit, git merge, and git fetch. With --auto, gc checks whether thresholds have been exceeded before doing any work. If the repo is already tidy, it exits immediately.
Threshold-based auto gc
git gc --auto
The primary trigger is the gc.auto config value (default: 6700). When the number of loose objects exceeds this threshold, auto-gc kicks in and packs them. Set it to 0 to disable automatic gc entirely (not recommended for most workflows).
Disabling auto-gc (not recommended)
git config gc.auto 0
What gc CAN Remove
Unreachable loose objects older than
gc.pruneExpire(default: 2 weeks) — objects with no path from any ref, reflog, or stashRedundant pack files — older packs made obsolete by a fresh repack
Expired reflog entries — entries older than
gc.reflogExpire(default: 90 days for reachable, 30 days for unreachable)Stale temporary files — leftover MERGE_HEAD, ORIG_HEAD, and similar files from aborted operations
What gc CANNOT Remove
Reachable objects — any object that can be reached from a branch, tag, stash, or reflog entry is safe
Reflog entries within expiry — the reflog is a safety net; gc respects its TTL
Loose objects younger than 2 weeks — the grace period exists to prevent data loss from concurrent operations
Packed objects — objects already in a pack file are preserved during gc (only re-compressed)
Verifying Cleanup with count-objects
After running gc, use git count-objects -v to confirm the cleanup was effective. The -H flag formats sizes in human-readable units.
Before gc
git count-objects -vH # count: 8341 ← loose objects # size: 124.50 MiB ← space used by loose objects # in-pack: 0 # packs: 0 # size-pack: 0 bytes # prune-packable: 0 # garbage: 0 # size-garbage: 0 bytes
After git gc
git count-objects -vH # count: 0 ← loose objects cleaned up # size: 0 bytes # in-pack: 8341 ← now stored in a pack file # packs: 1 # size-pack: 42.10 MiB ← delta-compressed, much smaller # prune-packable: 0 # garbage: 0 # size-garbage: 0 bytes
Relevant Configuration
Config Key | Default | Description |
|---|---|---|
gc.auto | 6700 | Number of loose objects before auto-gc triggers; 0 disables |
gc.autoPackLimit | 50 | Number of pack files before auto-repack triggers |
gc.pruneExpire | 2.weeks.ago | Minimum age for unreachable objects to be pruned |
gc.reflogExpire | 90.days.ago | Expiry time for all reflog entries |
gc.reflogExpireUnreachable | 30.days.ago | Expiry for reflog entries on unreachable commits |
gc.worktreePruneExpire | 3.months.ago | Expiry for stale worktree admin files |
gc.bigPackThreshold | 0 | Packs larger than this are not repacked (0 = no limit) |
Setting gc configuration
# Prune unreachable objects immediately (no grace period) git config gc.pruneExpire now # Keep reflog for 180 days git config gc.reflogExpire 180.days.ago # Trigger auto-gc less frequently git config gc.auto 9999