GitGarbage Collection (git gc)

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

Bash
git gc

Example output

Text
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

Bash
git gc --aggressive
Warning
Never run `git gc --aggressive` on a repository that other people are actively using. The operation rewrites pack files in place and can cause errors for concurrent Git processes. Reserve it for a one-time cleanup when you have exclusive access to the repository. Additionally, the gains from `--aggressive` are often marginal and rarely justify the time cost on an ongoing basis.
Tip
For most repositories, a plain `git gc` produces pack files nearly as good as `--aggressive` but runs much faster. Only consider `--aggressive` after importing a large foreign repository (e.g., converting from SVN/Mercurial) where the existing object graph is already sub-optimal.
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

Bash
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)

Bash
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 stash

  • Redundant 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

Bash
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

Bash
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

Bash
# 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
Note
On a busy team repository with many contributors, `git gc` is usually triggered automatically and rarely needs manual intervention. Manual gc is most useful after large import operations, after removing a long history of large files, or when diagnosing repository size problems.