Remove Duplicate Loose Git Objects with git prune-packed

After a repack, loose object files sit around that already live inside the new pack, and git prune-packed clears out exactly those duplicates. You will identify loose Git objects that are also present in a pack file, review the exact removals, and delete only those redundant loose copies. Allow about ten minutes for one repository. You need Git installed, access to the repository's object directory, and enough time to check a dry run before making changes. The examples use Git 2.43.0 from Ubuntu package git-man 1:2.43.0-1ubuntu7.3, which is the version installed on this machine.

Safety boundary: git prune-packed removes files from the object database. It does not remove pack files, commits, branches or tags, but an accidental deletion of some other object can damage a repository. Keep a current clone or backup, and run the dry run first. Normal repository maintenance does not require sudo; using root can create ownership problems in the repository.

1. Check the repository before pruning

Choose the repository explicitly. Replace the placeholder path with a directory containing the .git directory, or with a worktree whose Git directory is configured normally:

$ repo=/path/to/repository
$ git -C "$repo" rev-parse --show-toplevel
/path/to/repository
$ git -C "$repo" --version
git version 2.43.0

The command works on the Git object directory, not on ordinary files in the working tree. An uncommitted change is not itself a reason to stop, but record the state if other maintenance is happening at the same time. A repository backup is the useful recovery measure because pruning has no undo option.

Checkpoint: the first command must print the repository you intended to maintain. If it fails, stop and fix the path or repository access before continuing.

2. Measure the current object store

Use count-objects to establish a baseline:

$ git -C "$repo" count-objects -v
count: 12
size: 48
in-pack: 1842
packs: 1
size-pack: 912
prune-packable: 12
garbage: 0
size-garbage: 0

The numbers in your output will differ. count is the number of loose objects, while in-pack counts objects in pack files. A non-zero prune-packable value is a useful indication that loose objects duplicate packed objects, but it is not a replacement for reviewing the command's own dry-run output. If count is already zero, there is normally nothing for this command to remove.

3. Review the dry run

Run the exact operation with --dry-run:

$ git -C "$repo" prune-packed --dry-run
rm -f .git/objects/5f/60b54cc021d732002912e2b64e3fb2c7edb50e
rm -f .git/objects/7f/634a0857f84f67bff813dcff739a9b985e3ebb

Each line identifies a loose object file that is also in a pack. The command does not delete anything in this mode. An empty result means that no duplicate loose objects were found in the object directory it searched. Do not treat an empty result as evidence that the repository has no unreachable objects: pruning packed duplicates and finding unreachable objects are different jobs.

If the list contains an object that you are investigating, stop and preserve the repository before doing anything else. The command is intended for housekeeping after packing, not for deciding which historical objects are safe to discard.

For a script or a quiet check, add --quiet:

$ git -C "$repo" prune-packed --dry-run --quiet
$ printf 'exit status: %s\n' "$?"
exit status: 0

--quiet suppresses the progress or removal display. It does not turn the operation into a dry run, so keep --dry-run present while checking.

4. Remove only the listed duplicates

Once the dry-run paths are expected and your backup or clone is available, run the real command:

$ git -C "$repo" prune-packed
rm -f .git/objects/5f/60b54cc021d732002912e2b64e3fb2c7edb50e
rm -f .git/objects/7f/634a0857f84f67bff813dcff739a9b985e3ebb

The output is a progress display made of removal commands. It is not a shell script that you should copy into another directory. The packed copies remain in the pack file, so normal object lookup should continue to work. Do not run rm yourself and do not delete the .idx or .pack files as part of this task.

If the command reports a permission error, stop rather than changing ownership blindly. Check the repository and object-directory permissions with your administrator or run the maintenance as the account that owns the clone. Elevated privileges are not normally needed.

5. Verify the result

Measure the object store again:

$ git -C "$repo" count-objects -v
count: 0
size: 0
in-pack: 1842
packs: 1
size-pack: 912
prune-packable: 0
garbage: 0
size-garbage: 0

The loose-object count and pruneable count should have fallen for the objects shown by the dry run. The pack count and packed-object count should remain. Finish with a repository integrity check that reads the object database:

$ git -C "$repo" fsck --full
Checking connectivity: 1842, done.

fsck can report existing dangling or unreachable objects in an older repository. That is separate from this command's work. Treat missing or corrupt objects as a stop condition, restore the repository from the backup or clone, and investigate before allowing further maintenance.

Common traps

Done means