I frequently use git stash and git stash pop to save and restore changes in my working tree. Yesterday I had some changes in my working tree that I had stashed and popped, and then I made more changes to my working tree. I'd like to go back and review yesterday's stashed changes, but git stash pop appears to remove all references to the associated commit.

I know that if I use git stash then .git/refs/stash contains the reference of the commit used to create the stash. And .git/logs/refs/stash contains the whole stash. But those references are gone after git stash pop. I know that the commit is still in my repository somewhere, but I don't know what it was.

Is there an easy way to recover yesterday's stash commit reference?

Note that this isn't critical for me today because I have daily backups and can go back to yesterday's working tree to get my changes. I'm asking because there must be an easier way!

Note for the future: If you don't want to lose your stashes each time you git stash pop, you can do git stash apply instead. It does the same thing, except it doesn't remove the reference to the applied stash.
– KevinJul 10 '13 at 17:12

This will show you all the commits at the tips of your commit graph which are no longer referenced from any branch or tag – every lost commit, including every stash commit you’ve ever created, will be somewhere in that graph.

The easiest way to find the stash commit you want is probably to pass that list to gitk:

Jaydel took the words out of my mouth. This post saved my job :) I would just like to add - remembering the date you worked on whatever you lost makes it easier to browse gitk for what you are looking for.
– Sridhar-SarnobatSep 4 '15 at 17:52

3

@Codey: Because PowerShell. I don’t know if MsysGit ships an AWK binary. Googling tells me that something like %{ $_.Split(' ')[2]; } should do the equivalent of the {print $3} in that awk command in PowerShell, but I don’t have a Windows system to test that, and you still need an equivalent for the /dangling commit/ part. Anyway, just run git fsck --no-reflog and look at the output. You want the hashes from the “dangling commit <commitID>” lines.
– Aristotle PagaltzisOct 2 '15 at 3:55

It's worth mentioning that the commit message will only have the string "WIP" if you didn't provide your own message when stashing (i.e. by doing git stash save "<message>").
– Samir AguiarJul 29 '16 at 1:19

7

If you know when the drop happened, you can use this one-liner to get the list of dangling commits by increasing time: git fsck --no-reflog | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ci %H" | sort the last entry is probably the one you want to stash apply.
– ris8_allo_zen0May 15 '17 at 9:31

Just wanted to mention this addition to the accepted solution. It wasn't immediately obvious to me the first time I tried this method (maybe it should have been), but to apply the stash from the hash value, just use "git stash apply ":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

When I was new to git, this wasn't clear to me, and I was trying different combinations of "git show", "git apply", "patch", etc.

Do note that this applies (duh!) the stash to the current working tree. If the tree is dirty, you might want to either use a temporary branch or stash first, apply the stash from the SHA-1, stash again and then pop the second to last stash (called stash@{1}).
– musiKkMar 24 '14 at 10:28

This lists all the objects in the .git/objects tree, locates the ones that are of type commit, then shows a summary of each one. From this point it was just a matter of looking through the commits to find an appropriate "WIP on work: 6a9bb2" ("work" is my branch, 619bb2 is a recent commit).

I note that if I use "git stash apply" instead of "git stash pop" I wouldn't have this problem, and if I use "git stash save message" then the commit might have been easier to find.

Why do people ask this question? Because they don't yet know about or understand the reflog.

Most answers to this question give long commands with options almost nobody will remember. So people come into this question and copy paste whatever they think they need and forget it almost immediately after.

I would advise everyone with this question to just check the reflog (git reflog), not much more than that. Once you see that list of all commits there are a hundred ways to find out what commit you're looking for and to cherry-pick it or create a branch from it. In the process you'll have learned about the reflog and useful options to various basic git commands.

Hi Robby. This is relevant if you were working, got side-tracked, and need to pick back up where you left off a couple weeks ago only to learn you can't find your stashed work -- it probably got lost somewhere in that other stuff you were doing. reflog is great if it's recent history, but not for long time gaps.
– emraginsJun 20 '17 at 20:30

1

Hey emragins, I agree, but this was exactly the OP's use case. I don't know for sure how the other commands being posted here would behave, but my geuss would be that they'd also stop working once the ref to his stashed commit gets cleaned up.
– RobbyDJul 20 '17 at 8:50

1

Hmm... the scenario above was what brought me to this question, and I know it was at least a couple weeks if not even closer to a month between when I (unknowingly) lost my stash and when I was able to recover it.
– emraginsJul 21 '17 at 23:44

What I came here looking for is how to actually get the stash back, regardless of what I have checked out. In particular, I had stashed something, then checked out an older version, then poped it, but the stash was a no-op at that earlier time point, so the stash disappeared; I couldn't just do git stash to push it back on the stack. This worked for me:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^ # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

In retrospect, I should have been using git stash apply not git stash pop. I was doing a bisect and had a little patch that I wanted to apply at every bisect step. Now I'm doing this:

is this an answer, or the continuation of the question?
– Alex BrownJan 15 '14 at 6:52

A bit of both. I found this page because I lost a stash and was trying to get it back. The use case for me is doing a bisect where I want to apply a change before testing at each step. I learned the hard way that you can't just pop, test, stash, bisect because that can leave a different commit on the stash, hence stash apply.
– BenJan 15 '14 at 12:50

Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).