Skip to content
masterclass Buddy

Git · Command

git gc

git gc does housekeeping on your local repository. It compresses objects into packfiles, throws away unreachable data once it has aged enough, and tidies refs, reflogs, rerere records and worktree metadata so the repository takes less disk space and runs faster.

Last updated

How it works

When you run it, git gc triggers several maintenance steps one after another. It runs git repack to gather loose objects and small packs into packfiles, and by default it puts unreachable objects into a separate cruft pack. It prunes unreachable objects older than a grace period (2 weeks by default), runs pack-refs, expires old reflog entries, cleans up rerere data and stale worktrees, and can rewrite the commit-graph. Many everyday porcelain commands call git gc --auto for you. That version only does real work once the repository passes certain thresholds, so running it by hand is rarely needed.

Syntax

git gc [--aggressive] [--auto] [--[no-]detach] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]

Parameters

NameTypeDescription
--aggressiveflagOptimizes much harder at the cost of far more time. It throws away existing deltas and recomputes them with a larger window and depth.
--autoflagDoes nothing unless the configured thresholds show that housekeeping is needed.
--[no-]detachflagRuns in the background (or not), overriding gc.autoDetach.
--[no-]cruftflagTurns on or off storing expiring unreachable objects in a cruft pack instead of as loose objects. On by default.
--max-cruft-size=<n>bytesUpper size limit for new cruft packs. Overrides gc.maxCruftSize.
--expire-to=<dir>pathWrites a cruft pack of the pruned objects into this directory. Only has an effect together with --cruft.
--prune=<date>datePrunes loose objects older than this date. The default is 2 weeks ago, set by gc.pruneExpire.
--no-pruneflagPrunes no loose objects at all.
--quietflagHides all progress output.
--forceflagRuns even if another gc may already be running on the repository.
--keep-largest-packflagMerges every pack except the largest non-cruft pack, .keep packs and cruft packs into one pack. gc.bigPackThreshold is ignored when this is used.

Key points

  • The --auto flag is a cheap check. It quits right away unless thresholds such as gc.auto (about 6700 loose objects) or gc.autoPackLimit (50 packs) have been exceeded.
  • Unreachable objects that are waiting to expire go into a single cruft pack by default rather than being written out as many loose files.
  • gc is cautious about what it deletes. Anything reachable from branches, tags, the index, remote-tracking branches, reflogs or any other ref under refs/* survives.
  • Unreachable loose objects are only removed after a grace period. You can change it per run with --prune=<date> or permanently with gc.pruneExpire.
  • Reflog entries left behind by amends and rebases (no longer reachable from the tip) expire after 30 days by default. Ordinary entries expire after 90 days.
  • To avoid rewriting a huge pack every time, use --keep-largest-pack or set gc.bigPackThreshold. Only the smaller packs then get merged.

Common mistakes

  • --prune=now removes the safety grace period. If another Git process is writing to the repository at the same moment, its new objects can be deleted.
  • --aggressive is not a free upgrade. It is much slower, and the docs advise against it unless you have benchmarked it on your repository.
  • A note made with git notes does not count as a reference. Objects that only a note points to can still be pruned.
  • If an earlier background auto-gc left a gc.log file, later --auto runs just print that log and stop until it is more than gc.logExpiry old (1 day by default).

Example: Inspect, clean up and re-inspect a repository

#!/usr/bin/env bash
set -euo pipefail

# Before: count loose objects and packs
git count-objects -v

# Standard cleanup; unreachable objects younger than 2 weeks are kept
git gc

# Cheap check that only does work if thresholds are exceeded
git gc --auto --quiet

# Keep the big pack and only consolidate the smaller ones
git gc --keep-largest-pack

# Turn off automatic gc for this repository (e.g. during a bulk import)
git config gc.auto 0

# After: compare the numbers
git count-objects -v

This shows a normal gc, a threshold-gated auto run and a run that keeps the largest pack, plus how to disable auto-gc, with object counts printed before and after so you can see the effect.

When to use it

After a bulk import

You loaded a large history with git fast-import or a migration tool. The packs it produced are not well optimized, so you run git gc once to rebuild them properly.

Reclaiming space after history rewrites

Large blobs were removed from history. Once the reflogs and backup refs that still point at them are gone and the grace period has passed, git gc deletes the objects and the repository shrinks.

Avoiding surprise background work

On a big repository, run git gc yourself at a convenient time so that auto-gc does not start in the middle of something important.

Interview questions

QWhat is the difference between git gc and git gc --auto, and who calls the second one?

Plain git gc always does the full set of housekeeping steps. git gc --auto checks gc.auto (loose object count) and gc.autoPackLimit (pack count) first and stops if neither is exceeded. Common porcelain commands that create objects run it automatically, and once it is triggered it also handles reflogs, rerere data and worktrees.

Follow-up: How do you turn auto-gc off completely? Set gc.auto to 0. That disables the loose-object heuristic and every other --auto heuristic, including gc.autoPackLimit.

QWhy doesn't git gc delete an unreachable object right away?

By default it only prunes unreachable objects older than 2 weeks (gc.pruneExpire). This protects against concurrent processes that have written an object but have not referenced it yet. Git also keeps anything newer than the prune date plus everything reachable from it, and it refreshes an object's mtime when a command re-adds it.

Follow-up: Is this a complete guarantee? No. The docs say the protections fall short of a full solution, so running commands concurrently still carries a small risk of corruption.

QYou deleted a branch containing a large file and ran git gc, but the disk usage didn't drop. Why?

gc keeps every object that is still referenced from anywhere: reflogs, the index, remote-tracking branches or any other ref under refs/*. The deleted branch's commits are probably still in reflogs, and unreachable objects also wait out the 2-week grace period, now inside a cruft pack.

Follow-up: How would you reclaim the space right away on a repository nothing else is touching? Expire the reflogs (for example git reflog expire --expire-unreachable=now --all) and then run git gc --prune=now, accepting that this is only safe when no other process is writing.

  • git-repack
  • git-prune
  • git-reflog
  • git-rerere
  • git-maintenance
  • git-commit-graph
  • git-fast-import
  • git-count-objects

Source: Git - git-gc Documentation. Checked 2026-11-02.