Wednesday, November 13, 2013

git: I want my stash back

TL;DR - it's a good idea to throw experimental changes on a branch instead of stashing them.

Today I stashed some changes, then popped them out, then decided they were a failure and wiped them out, then (later) wanted them back.

git stash makes a commit, and commits are not deleted for thirty days, so there had to be a way to get them back.

git fsck finds lost references. But only ones that are good and thoroughly lost, not stashed or listed in a reflog. To find all the references that are not in the history of some named commit, try

git fsck --unreachable > temp_file

Stick the output into a temp file because this takes a long time.

Then to find the commit I was looking for:

cat temp_file | grep commit | cut -d ' ' -f 3 | xargs git show --name-only

cat temp_file reads the temp file
grep commit chooses only the commits out of all the unreachable objects found by git fsck
cut -d ' ' -f 3 prints only the third field, using space as a delimiter. This gives me the commit hash
xargs puts the input lines on the end of the argument list
git show prints information about any object it git; for commits it shows the git log output and the diff
--name-only narrows the diff output to only the changed filenames

That gave me a whole slew of commit descriptions, opened in less the same way git log works. I searched for the filename of interest

(forward slash is the less command for search; push n to go to the next one)
and then moved up (arrow key) to see the description of that lost stash-entry commit, along with its commit hash.

commit 2b16061dba6ba8e529e56f53544c84ba432ed7be
Author: Jessitron <jessitron>
Date:   Wed Nov 13 11:06:19 2013 -0600

    index on develop: 776a776 Debug logging for claiming


Finally, I can check that out and create a temporary branch, which is what I should have done in the first place.

git checkout commit_hash
git branch crazy-changes

Now these experimental changes can hang out, out of my way and easily reachable, until I'm good and done with them and delete the branch.

git branch -d crazy-changes

Question: if I can only find this with fsck --unreachable, that implies that this commit is still recorded somewhere. Anyone know where that is?


  1. Also there's a less hardcore way. Both Eclipse and IDEA maintain local history of files independently from VCS. So if you use one of them and remember required file, IDE can show you all recent changes to it.

  2. I would imagine that it's in .git/objects.