11

I accidentally executed git stash pop twice getting me one stash behind of where I wanted to be. How do I undo the last pop? I do want the first pop but not the second one so reset --hard HEAD won't do it for me.

amphibient
  • 29,770
  • 54
  • 146
  • 240

2 Answers2

14

"Undoing" git stash pop is kind of painful unless you have the raw commit-IDs for your stashes listed somewhere (e.g., on your screen).

The git stash documentation has directions (at the end) for recovering dropped stashes. These are the instructions you want, as pop is simply "apply and then drop". That means if you recover both stashes, you can then use git reset --hard to restore everything, git stash pop (or—safer since it won't "drop"—git stash apply) the one stash you wanted to use, and then verify everything.

If you can find and restore both stashes, that's probably how I'd do it.

If you can find just the second stash (the one you want to "un-apply"), you can attempt to reverse-apply it.

Here's the "incantation" from the documentation:

git fsck --unreachable |
grep commit | cut -d\  -f3 |
xargs git log --merges --no-walk --grep=WIP

When you run this you'll get a list of commits that represent each w commit of each "stash bag". Let's say it dumps out something like this:

Checking object directories: 100% (256/256), done.
Checking objects: 100% (66/66), done.
commit 2783bc8cf98192acc3de647d6cbff2c1a2aecca5
Merge: 222c4dd 8466342
Author: ...
Date:   Wed Feb 12 17:38:13 2014 -0700

    WIP on branch: 222c4dd add clobber-reg example

commit e9fc3cc8e7864813b54bb1281c845297a16b1b47
Merge: 222c4dd d790e1f
Author: ...
Date:   Wed Feb 12 17:28:00 2014 -0700

    WIP on branch: 222c4dd add clobber-reg example

The date line is useful here as it's the time the stash was made. It's pretty hard to tell those two stashes apart, isn't it? Save the raw SHA-1 IDs somewhere, and run git stash show -p on each one. When you find a valuable one, give it a name:

$ git tag recover-exp-1 e9fc3cc8e7864813b54bb1281c845297a16b1b47
$ git tag recover-exp-2 ...

Once you're sure which ones are the right recovered ones, you're good to go in terms of doing things like git reset --hard and then git stash apply. You can now apply by the tag names made above:

$ git reset --hard   # ouch, all gone now (maybe "git stash save" first)
$ git stash apply recover-exp-3 # that turned out to be the right one

When all is saved and committed the way you want it, you can delete the various "recover" tags. (Note, you can use any name you like; there's nothing special about recover-exp-, that's just something I made up here.)

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Never mind. I discovered it is a PIA. So I just did `reset —hard` and sucked up the redo of the last change set, which was luckily not much. – amphibient Feb 18 '14 at 05:17
  • A bit too hard, I just did a `git stash` to save everything and reset at the same time, and then I did a `git stash apply `, where SHA was shown on screen while popping as something like `Dropped refs/stash@{0} (4f5...)` – mxmlnkn Mar 14 '18 at 22:53
2

I don't believe you can easily undo the last pop. You'll likely just have to deal with the conflicts at this point if there's stuff you need from the first pop.

In the future if you want to avoid problems like this you can commit on local branches instead of using stashes. It's more cumbersome, but more resilient.

quickshiftin
  • 66,362
  • 10
  • 68
  • 89