Skip to main content

How To Recover Lost Git Branches

Daniel, at work, ran into a problem of accidentally removing a branch he had just created and made a commit to, thus loosing the days work. This was actually the fault of our internal scripts to manage the branching and merging policy we've set up. By "internal" I mean that I wrote them and it was my fault his whole day of work was gone, so that left it up to me to figure out how to repair the situation and salvage the current commit back from the ether. I thought it might be good to document, in the case that anyone else needs to do this.

This works in the case of branch A existing and branch B being removed after a single commit on it and branch B being from A. This means we know commit A and we need to find an unnamed commit, what was B, to recover it.

I can demonstrate the recovery process with a simple transcript.

ironfroggy:/tmp ironfroggy$ mkdir A
ironfroggy:/tmp ironfroggy$ cd A
ironfroggy:/tmp/A ironfroggy$ git init
Initialized empty Git repository in .git/
ironfroggy:/tmp/A ironfroggy$ cat >> test
a b c
ironfroggy:/tmp/A ironfroggy$ git add test
ironfroggy:/tmp/A ironfroggy$ echo "commit 1" | git commit -m test
Created initial commit 5b2401e: test
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 test
ironfroggy:/tmp/A ironfroggy$ cat >> test
1 2 3
ironfroggy:/tmp/A ironfroggy$ git add test
ironfroggy:/tmp/A ironfroggy$ echo "commit 2" | git commit -m test
Created commit 08217dc: test
1 files changed, 1 insertions(+), 0 deletions(-)
ironfroggy:/tmp/A ironfroggy$ git reset --hard HEAD^
HEAD is now at 5b2401e... test
ironfroggy:/tmp/A ironfroggy$ git reflog show master
5b2401e... master@{0}: reset --hard HEAD^
08217dc... master@{1}: commit: test
ironfroggy:/tmp/A ironfroggy$ git log master
commit 5b2401e38d400c3039a53a036f2d98f75d544056
Author: Calvin Spealman
Date: Sun Dec 2 13:27:25 2007 -0500

test
ironfroggy:/tmp/A ironfroggy$ git log 08217dc
commit 08217dc6ef8f8117d6c9e4bca6fe7f18f78559b6
Author: Calvin Spealman
Date: Sun Dec 2 13:28:01 2007 -0500

test

commit 5b2401e38d400c3039a53a036f2d98f75d544056
Author: Calvin Spealman
Date: Sun Dec 2 13:27:25 2007 -0500

test
ironfroggy:/tmp/A ironfroggy$ git merge 08217dc6ef8f8117d6c9e4bca6fe7f18f78559b6
Updating 5b2401e..08217dc
Fast forward
test | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
ironfroggy:/tmp/A ironfroggy$ cat test
a b c
1 2 3


The red line is the dangerous move that lost your commit. Now, nothing is actually removed from the repository, except for when you perform a garbage collection, so I knew we could recover this somehow. After a short time looking through the docs and asking a question or two on IRC, I arrived at the solution. There are logs kept on the changes that happen to refs (or branches), so I could use that to see the log of when that commit happened. You can see that and the commit the follows when the reset occurs and undoes our commit. The commit id is in the short version, but if we look at the log of that commit, we get the full ID and can simply merge it back into our branch. A very clean solution, indeed.

For Daniel This Means...

He didn't loose his whole days work, but he should be doing local commits more often so that any problems with our scripts can't show up in the first place. At least the work was recovered, and in short time. He is saved, for one more day at least, from being a disgruntled co-worker.

For Git This Means...

I'd love to contribute, so I'm thinking the git-fsck command needs something that can do this for you. Some operation to locate child commits would be really useful in these situations. Once again, I'm very happy with the move to Git.

Comments

jnareb said…
Actually the post is not how to recover lost git branches (you would lost branches together with reflog after doing 'git branch -D [branchname]'), but how to recover lost history (like for example 'git reset --hard HEAD^'). To recover lost branches you would need 'git fsck --lost-found'...
Ahsan said…
Thanks man, This post saved me 3 days of hard work !
Anonymous said…
Even better, if you don't know the commit's hash code, you can access it via HEAD@{1}, or even master@{yesterday}.
Anonymous said…
I owe you a beer
Holy crap, thank you thank you!
Anonymous said…
@jnareb: woah, thank you for sharing, it saved my night!

Popular posts from this blog

Why I Switched From Git to Microsoft OneDrive

I made the unexpected move with a string of recent projects to drop Git to sync between my different computers in favor of OneDrive, the file sync offering from Microsoft. Its like Dropbox, but "enterprise."

Feeling a little ashamed at what I previously would have scoffed at should I hear of it from another developer, I felt a little write up of the why and the experience could be a good idea. Now, I should emphasize that I'm not dropping Git for all my projects, just specific kinds of projects. I've been making this change in habit for projects that are just for me, not shared with anyone else. It has been especially helpful in projects I work on sporadically. More on why a little later.

So, what drove me away from Git, exactly?

On the smallest projects, like game jam hacks, I just wanted to code. I didn't want to think about revisions and commit messages. I didn't need branching or merges. I didn't even need to rollback to another version, ever. I just …

Respect and Code Reviews

Code Reviews in a development team only function best, or possible at all, when everyone approaches them with respect. That’s something I’ve usually taken for granted because I’ve had the opportunity to work with amazing developers who shine not just in their technical skills but in their interpersonal skills on a team. That isn’t always the case, so I’m going to put into words something that often exists just in assumptions.
You have to respect your code. This is first only because the nature and intent of code reviews are to safeguard the quality of your code, so even having code reviews demonstrates a baseline of respect for that code. But, maybe not everyone on the team has the same level of respect or entered a team with existing review traditions that they aren’t acquainted with.
There can be culture shock when you enter a team that’s really heavy on code reviews, but also if you enter a team or interact with a colleague who doesn’t share that level of respect for the process or…

CARDIAC: The Cardboard Computer

I am just so excited about this.


CARDIAC. The Cardboard Computer. How cool is that? This piece of history is amazing and better than that: it is extremely accessible. This fantastic design was built in 1969 by David Hagelbarger at Bell Labs to explain what computers were to those who would otherwise have no exposure to them. Miraculously, the CARDIAC (CARDboard Interactive Aid to Computation) was able to actually function as a slow and rudimentary computer. 
One of the most fascinating aspects of this gem is that at the time of its publication the scope it was able to demonstrate was actually useful in explaining what a computer was. Could you imagine trying to explain computers today with anything close to the CARDIAC?

It had 100 memory locations and only ten instructions. The memory held signed 3-digit numbers (-999 through 999) and instructions could be encoded such that the first digit was the instruction and the second two digits were the address of memory to operate on. The only re…