Home / Alt manpages / git-gc(1)

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

Run git gc Safely: Reclaim Space Without Losing Recovery Paths

You will finish with a checked, repeatable way to run git gc in a local repository, see what it changed, and avoid the pruning choices that can remove recovery data. 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. You do not need 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

The path in the last line should be the repository you meant to clean. A bare repository has no working tree, but git gc can still maintain it. If git rev-parse fails, stop and fix the path rather than trying sudo.

Checkpoint

You have confirmed both the Git version and the repository root. Keep this terminal focused on that repository; a common error is running cleanup in a nearby clone.

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. The useful fields are count for loose objects, packs for pack files and garbage for 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 that 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. The important result is a successful exit from both commands. git fsck may report dangling objects without treating them as 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

Git 2.43 uses approximately 6,700 loose objects as the default gc.auto threshold and 50 non-kept packs as the default gc.autoPackLimit. Setting gc.auto to zero disables this automatic housekeeping heuristic, including the pack-limit check. Automatic mode may detach and continue in the background when the system supports it, so do not use its immediate return as proof that all work has completed.

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

6. Avoid the tempting destructive shortcuts

Do not use git gc --prune=now merely because the repository is large. It removes loose objects regardless of age and raises the risk of corruption if another process is writing concurrently. It can also remove unreachable commits that 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, which can be useful for a recovery window but can also allow the object database to grow indefinitely.

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

  • You confirmed the intended repository and installed Git version.
  • You recorded the object inventory and working-tree state before maintenance.
  • You used ordinary git gc or deliberately justified --auto.
  • You avoided --prune=now unless you had stopped writers and made a recovery copy.
  • git fsck --full --no-progress completed successfully after the run.
  • The working-tree status and important recovery paths remain understood.