222

I stashed some local changes before doing a complicated merge, did the merge, then stupidly forgot to commit before running git stash pop. The pop created some problems (bad method calls in a big codebase) that are proving hard to track down. I ran git stash show, so I at least know which files were changed. If nothing else, I guess this is a lesson to commit more.

My question: is it possible to undo the stash pop without also undoing the merge?

nren
  • 2,729
  • 3
  • 17
  • 11
  • 2
    You're not supposed to be allowed to `git stash pop` without committing first. What did you do to achieve that? – C. K. Young Jul 01 '11 at 04:18
  • Not sure to be honest (this was yesterday). The merge didn't commit on its own because there were conflicts. I was somehow able to run stash pop after that. – nren Jul 01 '11 at 04:44
  • 1
    I did this just know using git version 1.7.9.msysgit.0. I had unstaged files and the stash pop just merged everything in. – PandaWood Nov 20 '12 at 01:11
  • 1
    I was able to run ``git stash pop`` after staging the changes (I did not commit though) with 2.25.0.windows.1 version of git – Artyom Gevorgyan Apr 07 '20 at 10:47
  • If you **indexed** your changes and lost them as you ran ``stash pop/apply`` before making a commit, you can fire ``git fsck --lost-found``. This command will iterate through the dangling blobs (actual files for those not familiar with git terminology) that were staged but not committed anywhere (therefore dangling), and put them under _.git/lost-found/_ directory, where you can ``git show`` them and see if these are the files that you are looking for. – Artyom Gevorgyan Apr 09 '20 at 11:26

3 Answers3

78

Try using How to recover a dropped stash in Git? to find the stash you popped. I think there are always two commits for a stash, since it preserves the index and the working copy (so often the index commit will be empty). Then git show them to see the diff and use patch -R to unapply them.

Community
  • 1
  • 1
Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
  • 6
    Wow that worked. I was able to find the stash commits with `git fsck --no-reflog | awk '/dangling commit/ {print $3}'` (from the link), and I just manually found the problem from that diff. Thanks! – nren Jul 01 '11 at 05:01
  • 1
    the fsck outputs a huge list. Its tedious to git show every SHA1 out there. How do you do this ? – meson10 Oct 06 '13 at 03:22
  • 5
    @meson10: Unfortunately stashes are kept in a reflog, which would be the obvious way (if they were a real branch) to look at the history of popped stashes. Also let me suggest that a downvote + request for help is not the best strategy. – Ben Jackson Oct 06 '13 at 05:16
  • 2
    It took me a bit of mangling to get it right. Here is the result of my work: `git diff -p ${STACH_SHA1}~1 ${STASH_SHA1} | patch -R -p1`; I tried with `git show` as suggested but its output was not good for patch; also I had to provide the `-p1` option to patch in order to strip the `a/..` and `b/..` element that `git diff` puts in front of the files otherwise it would not resolve the paths from the repository root. SUGGESTION: be cautious and commit the mess in a separate branch before playing with patch. – acorello Feb 14 '17 at 14:45
  • @BenJackson In your answer "always" means both ``stash pop`` and ``stash push`` will trigger a commit that would save the changes to index and working directory, right? – Artyom Gevorgyan Apr 07 '20 at 12:20
  • I have found the answer to my question asked here in the comments. ``stash save`` indeed makes a snapshot of (index, working tree, and if -u flag is activated, then also the untracked files), which can be shown with ``git log refs/stash``. ``stash pop/apply`` doesn't do anything like that, at least no sign of it doing so in the manpages. – Artyom Gevorgyan Apr 09 '20 at 11:21
  • `git patch -R = git: 'patch' is not a git command. See 'git --help'` – Jamie Hutber Aug 11 '21 at 20:44
43

From git stash --help

Recovering stashes that were cleared/dropped erroneously
   If you mistakenly drop or clear stashes, they cannot be recovered through the normal safety mechanisms. However, you can try the
   following incantation to get a list of stashes that are still in your repository, but not reachable any more:

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

This helped me better than the accepted answer with the same scenario.

kachar
  • 2,310
  • 30
  • 32
  • 15
    Note that a lot of solutions that involve searching for "WIP" are relying on the default stash messages. If you give your stashes explicit messages they may not contain WIP. – Ben Jackson Jun 18 '14 at 05:19
  • 1
    thanks. I added the option --oneline to the log command to improve the readability. – Venom Mar 01 '17 at 09:42
  • This only helps you to find the SHA of the stash commit. But if integrated with @basilikode comment from the accepted answer (git diff SHA~1 SHA | patch -R), it works fine. I recommend to use path --dry-run first to check. – Jarek C May 14 '20 at 12:54
3

If your merge was not too complicated another option would be to:

  1. Move all the changes including the merge changes back to stash using "git stash"
  2. Run the merge again and commit your changes (without the changes from the dropped stash)
  3. Run a "git stash pop" which should ignore all the changes from your previous merge since the files are identical now.

After that you are left with only the changes from the stash you dropped too early.

markus
  • 2,955
  • 2
  • 20
  • 13