views:

680

answers:

2

Coming from svn, just starting to become familiar with git.

When a branch is deleted in git, is it removed from the history?

In svn, you can easily recover a branch by reverting the delete operation (reverse merge). Like all deletes in svn, the branch is never really deleted, it's just removed from the current tree.

If the branch is actually deleted from the history in git, what happens to the changes that were merged from that branch? Are they retained?

+4  A: 

Branches are just pointers to commits in git. In git each commit has a complete source tree, it is a very different structure from svn where all branches and tags (by convention) live in separate 'folders' of the repository alongside the special 'trunk'.

If the branch was merged into another branch before it was deleted then all of the commits will still be reachable from the other branch when the first branch is deleted. They remain exactly as they were.

If the branch is deleted without being merged into another branch then the commits in that branch (up until the point where the forked from a commit that is still reachable) will cease to be visible.

The commits will still be retained in the repository and it is possible to recover them immediately after the delete, but eventually they will be garbage collected.

Charles Bailey
Thanks for the answer. Could you clarify what you mean by "each commit has a complete source tree"? As I understand it, each commit in git is a set of deltas that refer back to a parent commit, not an entire tree.
Ken Liu
Nope, each commit is the state of the tree at a given point. The deltas are only computed later on for displaying and rebasing and whatnot, but the commit id is the hash of the entire tree.
ben
@Ken Liu: A commit contains pointers to zero or more parent commits, a tree object and some metadata about the commit. The commit, therefore uniquely identifies both a couple source tree and, when viewed against its parent(s), the changes that it introduced.
Charles Bailey
Got it. It sounded to me like each commit contained an entire source tree instead of pointers into another data structure.
Ken Liu
@Ken Liu: It depends on exactly what you been by 'contain', but yes, essentially each commit contains a complete tree. In the object database objects are indexed by id so objects are shared between all the objects (trees and commits) that reference them so the implied storage overhead isn't as bad as it initially sounds. git also has an efficient storage optimization (pack files) which make even more efficient usage of disk space.
Charles Bailey
+2  A: 

In Git branches are just pointers (references) to commits in DAG (graph) of commits. This means that deleting branch removes only reference to commits, which might make some commits in DAG unreachable, thus invisible. But all commits that were on deleted branch would be still in repository, at least until unreachable commits would get pruned (e.g. using git gc).

Note that git branch -d would refuse to delete branch if it cannot be sure that deleting it wouldn't leave unreachable commits. You need to use stronger git branch -D to force deletion of branch, if it might leave unreachable commits.

Note also that unreachable commits, if they are present, are only those commits between last tip of deleted branch and either the commit that got merged to other existing branch, any tagged commit, or the branching point; whichever later. For example in the following situation:

----O----*----*----/M----*    <-- master <-- HEAD
     \            /
      \--.----.--/--x---y     <-- deleted branch

only commits 'x' and 'y' would get unreachable after deleting branch.

If you operated on deleted branch within gc.reflogExpire period, default 90 days, you would have last tip of deleted branch recorded in HEAD reflog (see git reflog show HEAD, or git log --oneline --walk-reflogs HEAD). You should be able to use HEAD reflog to recover delted pointer. Note also that in this case unreachable commits in just deleted branch would be protected from pruning (removing) within gc.reflogExpireUnreachable period, which by default is 30 days.

If you can't find tip of just deleted branch in reflog for HEAD, you can try to use git fsck to find "unreachable commit <sha1>", and examine those (via git show <sha1> or git log <sha1>) to find tip of deleted branch.

Independent on how you find tip of deleted branch, you can undo deletion, or rather re-create just deleted branch using

git branch <deleted-branch> <found-sha1-id>

Note however that reflog for a branch would be lost.

Jakub Narębski