The following sentence can be found on many Git tutorials: "never use git reset --hard". That's a good reason behind: this command can delete 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

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

My idea was to switch 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 the grep utility to search for the commit message under the directory .git of the repository.

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

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

The Right Way to Find Deleted Commits

Of course Git creators know that this kind of issues can happen. For this reason they created the command reflog that stands for "reference log". After executing git reflog, you are presented with the list of the latest commits made in the local repository (not the remote one).

Post last updated on 2020/08/31