How to abort a stash pop?

GitGit Stash

Git Problem Overview


I popped a stash and there was a merge conflict. Unlike the question that is listed as a duplicate, I already had some uncommitted changes in the directory which I wanted to keep. I don't just want to make the merge conflict disappear, but also to get my directory back to the state it was before the pop.

I tried git merge --abort, but git claimed no merge was in progress. Is there an easy way to abort a pop without destroying the changes I originally had in the directory?

Git Solutions


Solution 1 - Git

Simple one liner

I have always used

git reset --merge

I can't remember it ever failing.


Note: git reset --merge will discard any staged changes

Solution 2 - Git

My use case: just tried popping onto the wrong branch and got conflicts. All I need is to undo the pop but keep it in the stash list so I can pop it out on the correct branch. I did this:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Easy.

Solution 3 - Git

Ok, I think I have worked out "git stash unapply". It's more complex than git apply --reverse because you need reverse merging action in case there was any merging done by the git stash apply.

The reverse merge requires that all current changes be pushed into the index:

  • git add -u

Then invert the merge-recursive that was done by git stash apply:

  • git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1

Now you will be left with just the non-stash changes. They will be in the index. You can use git reset to unstage your changes if you like.

Given that your original git stash apply failed I assume the reverse might also fail since some of the things it wants to undo did not get done.

Here's an example showing how the working copy (via git status) ends up clean again:

 $ git status
# On branch trunk
nothing to commit (working directory clean)
 $ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
 $ git add -u
 $ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
 $ git status
# On branch trunk
nothing to commit (working directory clean)

Solution 4 - Git

Edit: From the git help stash documentation in the pop section:

Applying the state can fail with conflicts; in this case, it is not removed from the stash list. You need to resolve the conflicts by hand and call git stash drop manually afterwards.

If the --index option is used, then tries to reinstate not only the working tree's changes, but also the index's ones. However, this can fail, when you have conflicts (which are stored in the index, where you therefore can no longer apply the changes as they were originally).

Try hardcopying all your repo into a new dir (so you have a copy of it) and run:

git stash show and save that output somewhere if you care about it.

then: git stash drop to drop the conflicting stash then: git reset HEAD

That should leave your repo in the state it was before (hopefully, I still haven't been able to repro your problem)

===

I am trying to repro your problem but all I get when usin git stash pop is:

error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting

In a clean dir:

git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop

I don't see git trying to merge my changes, it just fails. Do you have any repro steps we can follow to help you out?

Solution 5 - Git

If you don't have to worry about any other changes you made and you just want to go back to the last commit, then you can do:

git reset .
git checkout .
git clean -f

Solution 6 - Git

OK, I think I have managed to find a work-flow that will get you back to where you need to be (as if you had not done the pop).

TAKE A BACKUP BEFOREHAND!! I don't know whether this will work for you, so copy your whole repo just in case it doesn't work.

  1. Fix the merge problems and fix all the conflict by selecting all the changes that come from the patch (in tortoisemerge, this shows up as one.REMOETE (theirs)).

    git mergetool

  2. Commit these changes (they will already be added via the mergetool command). Give it a commit message of "merge" or something you remember.

    git commit -m "merge"

  3. Now you will still have your local unstaged changes that you started originally, with a new commit from the patch (we can get rid of this later). Now commit your unstaged changes

    git add . git add -u . git commit -m "local changes"

  4. Reverse the patch. This can be done with the following command:

    git stash show -p | git apply -R

  5. Commit these changes:

    git commit -a -m "reversed patch"

  6. Get rid of the patch/unpatch commits

    git rebase -i HEAD^^^

from this, remove the two lines with 'merge' and 'reversed patch' in it.

  1. Get your unstanged changes back and undo the 'local changes' commit

    git reset HEAD^

I've run through it with a simple example and it gets you back to where you want to be - directly before the stash was popped, with your local changes and with the stash still being available to pop.

Solution 7 - Git

I solved this in a somewhat different way. Here's what happened.

First, I popped on the wrong branch and got conflicts. The stash remained intact but the index was in conflict resolution, blocking many commands.

A simple git reset HEAD aborted the conflict resolution and left the uncommitted (and UNWANTED) changes.

Several git co <filename> reverted the index to the initial state. Finally, I switched branch with git co <branch-name> and run a new git stash pop, which resolved without conflicts.

Solution 8 - Git

Some ideas:

  • Use git mergetool to split the merge files into original and new parts. Hopefully one of those is the file with your non-stash changes in it.

  • Apply the diff of the stash in reverse, to undo just those changes. You'll probably have to manually split out the files with the merge conflicts (which hopefully the above trick will work for).

I didn't test either of these, so I don't know for sure of they will work.

Solution 9 - Git

I could reproduce clean git stash pop on "dirty" directory, with uncommitted changes, but not yet pop that generates a merge conflict.

If on merge conflict the stash you tried to apply didn't disappear, you can try to examine git show stash@{0} (optionally with --ours or --theirs) and compare with git statis and git diff HEAD. You should be able to see which changes came from applying a stash.

Solution 10 - Git

If DavidG is correct that it didn't pop the stash because of the merge conflict, then you merely need to clean up your working directory. Quickly git commit everything you care about. (You can reset or squash the commit later if you're not done.) Then with everything you care about safe, git reset everything else that git stash pop dumped into your working directory.

Solution 11 - Git

If there were no staged changes before the git stash pop, as in the question, then the following two commands should work.

git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm

The first reverses any merges from the stash, successful or not. The second deletes any untracked files introduced by the stash.

From man git stash : The working directory must match the index. Which @DavidG points out, the stash pop will fail if any currently unstaged modified files conflict. As such, we shouldn't need to worry about unwinding merge conflicts beyond getting back to HEAD. Any remaining modified files are then unrelated to the stash, and were modified before the stash pop

If there were staged changes, I'm unclear on whether we can rely on the same commands and you may want to try @Ben Jackson's technique. Suggestions appreciated..

Here is a testing setup for all of the various cases https://gist.github.com/here/4f3af6dafdb4ca15e804

# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d
 
# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c

Solution 12 - Git

If you just have the stashed changes try this 1 liner. It removes every local change present.

git checkout -f

Solution 13 - Git

Use git reflog to list all changes made in your git history. Copy an action id and type git reset ACTION_ID

Solution 14 - Git

Try using if tracked file.

git rm <path to file>
git reset  <path to file>
git checkout <path to file>

Solution 15 - Git

I'm posting here hoping that others my find my answer helpful. I had a similar problem when I tried to do a stash pop on a different branch than the one I had stashed from. On my case I had no files that were uncommitted or in the index but still got into the merge conflicts case (same case as @pid). As others pointed out previously, the failed git stash pop did indeed retain my stash, then A quick git reset HEAD plus going back to my original branch and doing the stash from there did resolve my problem.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCasebashView Question on Stackoverflow
Solution 1 - GitKenn SebestaView Answer on Stackoverflow
Solution 2 - GitjmozView Answer on Stackoverflow
Solution 3 - GitBen JacksonView Answer on Stackoverflow
Solution 4 - GitDavidGambaView Answer on Stackoverflow
Solution 5 - Githugo der hungrigeView Answer on Stackoverflow
Solution 6 - GitagentgonzoView Answer on Stackoverflow
Solution 7 - GitpidView Answer on Stackoverflow
Solution 8 - GitasmeurerView Answer on Stackoverflow
Solution 9 - GitJakub NarębskiView Answer on Stackoverflow
Solution 10 - GitrobrichView Answer on Stackoverflow
Solution 11 - GithereView Answer on Stackoverflow
Solution 12 - Gitshubham chouhanView Answer on Stackoverflow
Solution 13 - GitFatih AcetView Answer on Stackoverflow
Solution 14 - GitxpioneerView Answer on Stackoverflow
Solution 15 - GitVictor CamachoView Answer on Stackoverflow