In many Git tutorials it's written: "never use git reset --hard". And there is a good reason: this command deletes commits, and, if you don't have pushed them to a remote repository, your changes are lost (at least, if you don't know where to find them).

A Little Story

This happened to me some years ago, when I was a Git newbie. There was a bug on a software so I created a new local branch from the master and started to fix it. In the meantime, a colleague of mine asked me for a quick workaround to continue his work. So I switched back to the master and added a couple of temporary commits.

After a week, the state of the repository was this:

Git history

The bug was fixed, the temporary commits could be removed and the branch merged to the master. Easy to say, easy to do, easy to mess.

My idea was to move to the master, delete the temporary commits and then merge the fix branch. Unfortunately when I run...

$ git reset --hard HEAD^^

...I was on the wrong branch. The good commits were gone. Panic!

Where Have They Gone?

What I've learned from this experience is that deleted commits are still there, at least until you run git gc or git prune. The problem is to find a way to bring them back. What I did at the time was to use grep to search for the commit message under the directory .git of the repository.

In this way I've discovered that in the directory .git/logs/refs/<branch-name>, in the logs are also recorded the hashes for every commit. With hashes it has been easy to checkout the second commit (going in a 'detached HEAD' state) and verify that nothing was miss

At that point, I've created a new branch (with git checkout -b new_fix) and carefully executed the original plan, this time without surprises.

I love it when a plan comes together!

- John "Hannibal" Smith