Recovering lost commits from a `git reset --hard`

So, if you're like me (more recently than I'd like to admit), you've probably decided that your repo was a bit fubar'd and figured git reset --hard should solve your problems, right?

But what's that? Those files you thought you committed are now gone! Fret not, it might not be the end of the world yet.

The saving grace for me has usually been:

git fsck --lost-found

For uncommitted changes, run this command and git will create a new dir in your repo at ./.git/lost-found and you might be able to find them in an other directory under lost-found.

If you've already committed, but not pushed your commits anywhere, running git fsck --lost-found will still create the lost-found directory, but instead it will just contain the SHAs of any commits you reversed. So, for example, running git reset --hard HEAD~2 will leave two SHAs in your lost-found directory.

To actually recover anything usable, just use the obvious-once-you-know-it git show command:

# git show 6e1928148d0dbe972bb4a1211d4250ef69f28a00
commit 332c5b715b893e17808075147a6fbb7bef035913
Author: Redacted User <user@redacted>
Date:   Fri Sep 30 06:11:31 2016 -0400

    Add Dockerfile

diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..ed65fc0
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,3 @@
+FROM httpd:2.4
+COPY . /usr/local/apache2/htdocs/

and right there, you can see the diff of that commit's changes, from which you can either create a patch and recover your files, or just replicate the changes in your workspace.

As some Stack Overflow users have pointed out in the questions on this topic, git reset while often very, very convenient, is usually a Bad Idea ™, especially with things like HEAD~2. For winding back through your history, better to use rebase or just do a checkout to your specific commit (you'll go into detached HEAD) then branch -m your way to a new branch.

Hope that helps!


comments powered by Disqus