Home / Alt manpages / git-gc(1)

  • git-gc(1)
  • User command
  • linux

Run git gc Without Losing Your Recovery Window

Run git gc when a repository feels bloated, and you can shrink it without wiping the recovery paths you would want after a bad rebase. This guide targets Git 2.43.0, supplied here by the git-man package version 1:2.43.0-1ubuntu7.3.

Allow about ten minutes for a normal repository, longer for a large monorepo. You need a shell and write access to the repository, not sudo. Do not run these commands while another process is writing to the same repository, such as an active fetch, rebase, commit, IDE background operation or server job.

1. Confirm the repository and Git version

Change to the working tree you intend to maintain, then confirm that Git has identified the repository. These checks are read-only:

$ cd /path/to/repository
$ git --version
git version 2.43.0
$ git rev-parse --show-toplevel
/path/to/repository
  • Check the last line. It should be the repository you meant to clean, not a nearby clone.
  • Bare repositories count too. A bare repository has no working tree, but git gc can still maintain it.
  • If git rev-parse fails, stop. Fix the path rather than reaching for sudo.

Checkpoint

You have confirmed both the Git version and the repository root. Keep this terminal focused on that repository.

2. Inspect the current state and object inventory

Record the working-tree state before maintenance. Garbage collection does not commit or rewrite files in your working tree, but this check makes unrelated changes visible:

$ git status --short
$ git count-objects -vH
count: 42
size: 168.00 KiB
in-pack: 1200
packs: 1
size-pack: 1.20 MiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes

Your counts will differ. Three fields matter here.

  • count is the number of loose objects.
  • packs is the number of pack files.
  • garbage is files Git cannot use.

A large loose-object count or many packs can justify maintenance, but size alone is not proof that aggressive repacking will help. If git status --short prints changes, note them before continuing: do not discard them as part of this guide.

3. Run the normal maintenance pass

For an ordinary one-off cleanup, run the default command:

$ git gc

Successful operation normally returns to the prompt without a report. Git may compress loose objects, consolidate packs, pack references, expire eligible reflog entries, prune old unreachable objects and update the commit graph. In Git 2.43, unreachable objects are stored in cruft packs by default when that feature is enabled by the command or configuration.

The default prune grace period is two weeks. That delay is a recovery boundary: commits made unreachable by an amend, reset or rebase may remain available through reflogs until they expire. A normal run does not mean every apparently unused object disappears.

Checkpoint

If the command returned a non-zero status, save the complete error and stop. Do not add --force as a reflex: that option tells Git to run despite a possible concurrent git gc, it does not repair a failed repository.

4. Verify the result

Check the inventory again and confirm that the repository is structurally readable:

$ git count-objects -vH
$ git fsck --full --no-progress
Checking connectivity: 100% (1200/1200), done.
Checking objects: 100% (1200/1200), done.

The exact counts and progress lines vary. What matters is a successful exit from both commands. git fsck may report dangling objects without that meaning corruption. A dangling object can still be useful recovery material, so do not delete it manually just to make the output shorter.

Run the status check once more:

$ git status --short

It should show the same tracked and untracked work you observed before maintenance. If repository files changed unexpectedly, stop and investigate before using the clone further.

5. Use automatic mode for scripts and hooks

git gc --auto is a conditional check. It exits without doing work when Git's housekeeping thresholds have not been reached:

$ git gc --auto
$ printf 'exit status: %s\n' "$?"
exit status: 0
  • Default loose-object threshold: Git 2.43 uses approximately 6,700 loose objects as the default gc.auto value.
  • Default pack-count threshold: 50 non-kept packs, the default gc.autoPackLimit.
  • Turning it off: setting gc.auto to zero disables this automatic housekeeping heuristic, including the pack-limit check.
  • It can run in the background. Automatic mode may detach and continue when the system supports it, so an immediate return is not proof that all work has completed.

Porcelain commands can invoke this mode themselves. If a hook or wrapper runs git gc --auto, the pre-auto-gc hook may also run. Review repository hooks before treating automatic maintenance as side-effect-free.

6. Avoid the tempting destructive shortcuts

Warning

Do not use git gc --prune=now merely because the repository is large. It removes loose objects regardless of age, raises the risk of corruption if another process is writing concurrently, and can remove unreachable commits you expected to recover from a recent reflog.

Do not set gc.pruneExpire=now in a general-purpose configuration unless you have a specific, tested retention policy. The value never suppresses pruning, useful for a recovery window but able to let the object database grow indefinitely.

Warning

There is no undo command for objects that have been pruned. Before any non-default pruning, make a verified backup or a fresh clone, stop all writers, and record the relevant reflog entries. If recovery matters, use the backup or clone rather than hoping a later git fsck can recreate deleted objects.

7. Treat --aggressive as a measured exception

git gc --aggressive recomputes deltas with a larger search window and depth. It can take much longer, use more CPU and memory, and produce little or no useful improvement for a normal development repository. The manual recommends performance benchmarking before using it.

Only consider it after a mass import, unusual history rewrite or a measured storage or performance problem. Record the before-and-after output from git count-objects -vH, and run the same workload before deciding that the extra cost helped. If the command is competing with developers, CI or a hosting service, schedule it during a maintenance window.

Done means

  • Confirmed the intended repository and installed Git version.
  • Recorded the object inventory and working-tree state before maintenance.
  • Used ordinary git gc or deliberately justified --auto.
  • Avoided --prune=now unless you had stopped writers and made a recovery copy.
  • Ran git fsck --full --no-progress successfully after the job.
  • Kept the working-tree status and recovery paths understood.