Git prune: Remove Unreachable Objects Safely
Understand Git's low-level object-pruning command, preview unreachable objects, control expiration, protect objects with additional heads, and distinguish pruning from integrity checking and general maintenance.
Advanced
What `git prune` actually removes
Git can retain objects after they stop being reachable from refs. That retention is useful for recovery, but eventually unreachable objects can be removed. `git prune` is the low-level pruning command: it removes eligible unreachable objects from the object database and also invokes `git prune-packed` for loose objects that are already present in packs. In ordinary repository use, the official documentation recommends using `git gc` instead of invoking `git prune` directly.
git prune -n -v --expire=nowQuick check
What is the primary purpose of `git prune`?
Why unreachable does not mean immediately deletable
Deleting a branch can make a commit unreachable from current refs while the object remains in the repository. Reflogs and other retention mechanisms are important in real repositories because they can preserve recovery paths. `git prune` should therefore not be treated as a command that simply deletes everything reported as interesting by `git fsck`. Before destructive pruning, inspect reachability and retention deliberately.
git fsck --unreachable --no-reflogs
git reflog expire --expire=now --all
git fsck --unreachable --no-reflogsQuick check
Why can an object remain present after its branch is deleted?
Preview first with `-n`
`-n` (or `--dry-run`) reports what would be pruned without removing it. `-v` makes the preview explicit by listing candidate objects. This is the safest form to demonstrate the effect before performing destructive cleanup.
git prune -n -v --expire=nowQuick check
What does `git prune -n -v --expire=now` do?
Expiration controls eligibility
`--expire=<time>` controls how old an object must be before it is pruned. Using `--expire=now` is deliberately aggressive: an otherwise eligible unreachable object can be removed immediately. A normal expiration policy can leave a recovery window instead. Do not copy `--expire=now` into a real repository merely because it makes a demonstration deterministic.
git prune -n -v --expire=now
git prune -n -v --expire=neverQuick check
What does `--expire=now` change?
Additional heads can protect objects
The command accepts optional `<head>` arguments. These extra object names are treated as heads when determining reachability, so objects reachable from them are protected from pruning during that invocation. This is a low-level mechanism for carefully defining what should remain reachable; it is not a substitute for making a durable ref when you actually want to preserve history.
git prune -n -v --expire=now <head>Quick check
What is the effect of supplying an additional `<head>` to `git prune`?
The remaining pruning controls
The official synopsis also exposes `--progress` and the argument separator `--`. `--progress` requests progress reporting. `--` stops option parsing so following arguments are treated as object names rather than options. These controls do not change which objects are reachable; they change reporting or argument interpretation.
git prune -n -v --progress --expire=now
git prune -n -v --Quick check
What is the purpose of `--` in the `git prune` command line?
Packed unreachable objects are a separate case
`git prune` removes unreachable unpacked objects. Unreachable objects that are already packed remain in their pack; the official documentation points to `git repack` when those packed unreachable objects must also be dealt with. `git prune` also removes unreachable entries from `.git/shallow`. This is another reason not to equate pruning with complete object repacking.
Quick check
What happens to an unreachable object that is already inside a pack?
`git prune` versus nearby commands
`git fsck` investigates object validity and connectivity; `git prune` removes eligible unreachable objects; `git gc` orchestrates repository housekeeping and is the normal high-level interface for maintenance. `git repack` reorganizes object packs, while `git pack-refs` reorganizes ref storage. These commands can appear together in maintenance workflows, but they have different ownership and destructive effects.
git fsck --unreachable --no-reflogs
git prune -n -v --expire=now
git gc --no-prune
git repack -ad
git pack-refs --allQuick check
Which command is the normal high-level maintenance interface rather than the low-level direct pruning operation?
Practice what you learned
Use the dedicated Git code-completion exercise for this lesson.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.