25

I have a git tree like

                 A---B---C topic
                /
           D---E---F---G master     <--

I would like to remove topic and all objects on it.

I note the SHA ID of topic, then type:

git branch -D topic
git gc                                   #  <-- I also tried prune here...
git checkout -b temp <SHA1 ID of topic>

After the last command I expect to get an error (something like "Non-existent object ID..." or somth. like that). However there is no error and gitk shows the same tree structure as above??

What am I missing - I thought gc/prune are supposed to delete all unreachable objects?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Alan
  • 291
  • 3
  • 3
  • 2
    VonC's answer explains the facts of the matter. If you want to know the "philosophical" reason, it's simply that git tries very very hard not to let you accidentally delete anything. `git gc` by itself is intended to be a cleanup/repacking operation. You have to say something a bit stronger to get it to potentially delete recent work. – Cascabel May 21 '10 at 17:32

2 Answers2

29

Just the gc prune is often not enough to get rid of the extra objects in the repo. If commits are still referenced in the reflog, it won't consider those objects unreachable and hence ripe for pruning.

Here's what worked for me:

git reflog expire --expire=now --all
git gc --aggressive --prune=now
git repack -a -d -l

This will make some changes to your repo's history, and may well present difficulties if others are depending on the branches you blow away.

You may have to re-clone your repository to actually see a difference in its size.

maxschlepzig
  • 35,645
  • 14
  • 145
  • 182
Duke
  • 7,070
  • 3
  • 38
  • 28
  • 1
    I had to use `git reflog expire --expire=now --all`. Note the added "expire". – Russell Silva Oct 26 '11 at 15:44
  • Tested it - and the repack step was not necessary. – maxschlepzig Apr 19 '12 at 16:31
  • 5
    *Sigh* When could we have a powerful versioning system where the usual tasks don't take a PhD to get them done? – Diego Sevilla Apr 19 '12 at 17:03
  • 6
    @DiegoSevilla Finding old objects and deleting them is not a common operation. One of the strengths of git is not being able to delete things without really, really trying. – wadesworld May 08 '12 at 22:28
  • 2
    Man, I'm with @DiegoSevilla on this. I'm a basic git user, and I simply want to create a possible throw-away branch to try out something crazy. I'm 99% sure I don't want to keep it, and I'd like to delete it when done. Isn't that a common workflow? But git says "If you branch it, you keep it!" (Unless you like hoop-jumping.) Ick. – Matthew Cornell Jun 04 '13 at 12:51
  • 1
    is the `git repack -a -d -l` really necessary? what it does? – akavel Jul 12 '13 at 10:16
  • 3
    @MatthewCornell, most of the time, you shouldn't care about running `git gc`. Want to try a new feature? Great, make a branch, and commit away. That feature didn't work out? Great, delete the branch. But then a week goes by, and you think, "Hm, maybe that thing I tried made sense." Because the git objects are still there, you can resurrect your branch. But if it's been longer than the default period (90 days), git will automatically run gc, and the objects from your test branch will be deleted. Creating and deleting branches is easy. Losing work is hard. – Chris Mar 17 '14 at 21:26
6

Note May 2010: As mentioned by Jakub, if your branch was merged, topic would still be reachable.

Here, let's suppose there was no merge.
Then, as mentioned in the ProGit book and detailed in this SO question:

git gc --prune=now

should be enough (you should call directly git prune). You can control that with a git count-objects -v.
Edit April 2012: maxschlepzig in the comments confirms that extra steps might be required, as detailed in Duke's answer (but without the git repack).
So instead of a git gc --prune now:

git reflog expire --expire=now --all
git gc --aggressive --prune=now
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    "Unreachable" is actually even stronger than you imply here. As far as `git-gc` is concerned, an object is reachable if it's reachable from a reflog - and reflogs take a long time to expire. For example, you could've merged the branch to master, realized it was bad and reset master back to the previous position, and the commit would be considered reachable until the reflog entry expired (default 90 days). – Cascabel May 21 '10 at 17:30
  • 3
    Also, it probably goes without saying, but be super-extra-careful using `--prune=now`. It'd be awful to realize just after hitting enter that some other important commit got wiped away. – Cascabel May 21 '10 at 17:37
  • `git gc --prune=now` is not enough - see Duke's answer. – maxschlepzig Apr 19 '12 at 16:25
  • Note to self: don't forget remote branches: http://stackoverflow.com/questions/11255802/delete-remove-binary-file-from-git-repository-is-still-large – VonC Jun 29 '12 at 06:28