15

I have some commits created by git subtree that I want to have garbage collect (more that any practical purpose just to understand what and why can get collected).

I have already checked that these commits are not referenced the following ways:

# In any reflog
> git reflog --all --no-abbrev-commit | grep <hash>
(no output)

# In any branch, local or remote
> git branch --contains <hash>
(no output)
> git branch -r --contains <hash>
(no output)

# In any tag
> git tag --contains <hash>
(no output)

# In the current index
> git rev-list HEAD | grep <hash>
(no output)

# In references from filter-branch
> ls .git/refs/original/
(the folder does not exist)

These are the place that git gc documentation lists that could contain references.

Still the given commits still exist after git gc.

Am I missing something? Or is there any git plumbing command that checks all this references?

Maic López Sáenz
  • 10,385
  • 4
  • 44
  • 57

2 Answers2

20

Every time I want to delete loose objects, I use the following commands:

rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
William Seiti Mizuta
  • 7,669
  • 3
  • 31
  • 23
  • 1
    Excellent, what was missing was the repacking. Even unreachable objects will not be disposed if packed with reachable objects. So the `repack` separates them and then `git prune` or `git gc` will properly dispose them. – Maic López Sáenz Feb 21 '13 at 19:52
  • Even when using `git prune`, my repository still had loose objects. If you experience this, `git gc` doc indicates that it tries *very hard* to be safe and keeps any possible references. Make sure to clean your /refs, /logs, FETCH_HEAD and other cache you might find in your .git folder. Then re-run `git gc --prune=now` will do the trick. – jsgoupil May 28 '14 at 19:05
6

Commits (or objects in general) aren't actually deleted until they've been unpacked into loose objects and left that way for at least 2 weeks. You can use git gc --prune=now to skip the 2 week delay.

Normally what happens is git will pack your objects together into a packfile. This provides much better compression and efficiency than having loose objects. This typically happens whenever a git gc is executed. However, if an object is unreferenced, then git gc will unpack it back into a loose object.

Once unpacked, git gc will automatically prune old loose unreferenced objects. This is controlled by the --prune=<date> flag, which defaults to 2 weeks ago, so it prunes any old unreferenced object older than 2 weeks. By specifying --prune=now, you're asking git gc to prune any objects that are older than right now, which basically means to prune any unreferenced objects that exist.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347