539

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?

Flip
  • 6,233
  • 7
  • 46
  • 75
Casebash
  • 114,675
  • 90
  • 247
  • 350
  • As for your uncommited changes: were these changes already in the index? – jørgensen Dec 16 '11 at 01:47
  • Can you post the version of git you are using. – Tinman Nov 12 '12 at 05:27
  • Did git split your files into `>>>>>`, `=====`, `<<<<<` for merges? – asmeurer Nov 15 '12 at 08:35
  • 3
    See also: [git stash blunder: git stash pop and ended up with merge conflicts](http://stackoverflow.com/q/2840816/425313) – Brad Koch Apr 18 '13 at 17:45
  • Relevant info from the [related question](http://stackoverflow.com/q/2840816/425313): If a conflict occurs, the stash is not dropped from the stash list. – here Jul 10 '14 at 04:07
  • 3
    The accepted answer looks complicated. I think it's pretty good general practice to never do something like attempt `git stash pop` on an unclean working dir. In which case you may simply `git reset --hard` and your stash is still intact. (This is more or less what @BradKoch's linked topic suggests) – Steven Lu May 28 '15 at 19:04
  • Possible duplicate of [Undo git stash pop that results in merge conflict](https://stackoverflow.com/questions/22207256/undo-git-stash-pop-that-results-in-merge-conflict) – Ciro Santilli OurBigBook.com Sep 21 '17 at 08:42
  • 1
    @StevenLu, I agree, but the issue can occur in a clean working dir if you're stashing the changes in order to move them to a different branch. The stash conflicts with commits that exist on the new branch that didn't exist on the old one. – Jake Stevens-Haas Dec 16 '19 at 23:22
  • @Casebash, it's been awhile since this was asked, would you consider revisiting your accepted answer? `git` has progressed enough in the last decade that there is a one-liner solution given in this post: https://stackoverflow.com/a/60444590/4271922. – Kenn Sebesta Aug 05 '21 at 14:11
  • @KennSebesta: I've accepted it for now - I'll test it next time I run into this issue – Casebash Aug 09 '21 at 02:32

16 Answers16

693

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. Also, as noted by @Saroopashree Kumaraguru in the comments, the stash contents won't be lost and can be re-applied later.

Antoine Leclair
  • 17,540
  • 3
  • 26
  • 18
Kenn Sebesta
  • 7,485
  • 1
  • 19
  • 21
  • 117
    Give this person a medal – Phil Young Dec 16 '20 at 15:07
  • 6
    Best one I don't know why people are not giving this single line ans – Saransh Dhyani Dec 31 '20 at 06:48
  • 4
    What happens to the previously stashed content if you do this? Is it put back on the stash or is it lost? – Adam Parkin Apr 01 '21 at 17:52
  • 2
    It is put back on the stash. – Kenn Sebesta Apr 01 '21 at 18:35
  • 11
    @AdamParkin When the `git stash pop` is not successful because of merge conflicts, then the stash contents will automatically be stored in the stash instead of deleting it – Saroopashree Kumaraguru Jun 18 '21 at 14:28
  • 2
    IT WORKS! But -- How is this different than `git merge --abort` ? During the bad stash pop/apply git even says "auto-merging...conflict...auto-merging..." and then there's no merge in progress to abort, but there IS one to reset? Ahhh. – DWR Jul 06 '21 at 23:30
  • 1
    I am getting: "fatal: Cannot do a keep reset in the middle of a merge." using git reset --keep – Berni Nov 22 '21 at 09:20
  • 15
    This note really needs to be larger. Not losing staged changes was my whole point why I looked for this =/ – Simon Kohlmeyer Feb 21 '22 at 18:54
  • @SimonKohlmeyer see where you're coming from, but I respectfully disagree in this context. The note is for an edge case which I have never encountered in 15 years of using git. It is important for a small class of people, though, which is why I added it to my answer. However, giving it the same font unnecessarily scares people who are not intimately familiar with git and able to parse what "staged changes" are. Keeping it small lets people know that it's generally safe to ignore. – Kenn Sebesta Nov 17 '22 at 22:04
364

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.

jmoz
  • 7,846
  • 5
  • 31
  • 33
  • 34
    So the stash that you want stays in the stash list until you have a successful pop? – Ryan Clark Feb 01 '16 at 21:36
  • 90
    This is not an answer for original question as it would wipe local changes which were not committed. – Dmitry Feb 23 '17 at 02:52
  • 18
    @RyanClark See [DavidG's answer](https://stackoverflow.com/a/13338764/4213607) below. Basically, yes, it stays in the stash list. – fkorsa Sep 04 '17 at 08:44
  • 6
    I think the vast majority of users who find themselves in this situation will find this solution to be ideal. I can't imagine a situation where I have uncommitted changes in my working directory before attempting to `stash pop` into it. That sounds like a recipe for disaster. – Shadoninja Apr 15 '19 at 16:36
  • 8
    Nice. After reading this I looked at git stash pop docs and it says "Applying the state can fail with conflicts; in this case, it is not removed from the stash list.". So, this is why the stash is able to be re-popped after a reset / checkout. – Brady Holt Jul 10 '19 at 18:27
  • 2
    Wipe out all the local changes _you want to keep_. Easy. XD – Scott Anderson Feb 25 '21 at 10:15
  • 1
    Don't do this or you will lose all uncommitted changes in the directory. Misleading upvotes !!!! – Vaibhav Shukla Aug 26 '21 at 11:48
67

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)
Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
53

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?

DavidGamba
  • 3,503
  • 2
  • 30
  • 46
  • Try stashing changes to a different file. – asmeurer Nov 15 '12 at 08:33
  • Trying to stash to a different file didn't work (see new repro steps). I just can't repro the issue... – DavidGamba Jan 23 '13 at 15:13
  • 1
    This solution does not work if there are uncommitted changes in the working directory. – here Jul 10 '14 at 04:06
  • @here This is not a real solution, this is just to show that I can't reproduce the problem the OP has and that he hasn't provided any steps to get to where he is at. – DavidGamba Jul 22 '14 at 21:13
  • @DavidG -- [maybe this?](https://gist.github.com/here/4f3af6dafdb4ca15e804), comments appreciated :). – here Jul 24 '14 at 02:08
  • 1
    Actual scenario is: 1) Change file A. 2) Stash changes 3) Make Conflicting change in file A and commit (e.g. change same line) 4) Change file B 5) Do 'git stash pop'. Now you have conflict and local changes. Generally they will be in different files, but you will never know which non-conflicting modified files from stash and which are local unstaged changes. – Dmitry Feb 23 '17 at 02:58
  • This only helped me to remove some of my stahed files, which is certainly not what I intended. Do not try this(git stash drop) if you don't want to lose some of your srashed files – megalucio Oct 17 '18 at 18:53
8

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
hugo der hungrige
  • 12,382
  • 9
  • 57
  • 84
5

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.

7) 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.

agentgonzo
  • 3,473
  • 3
  • 25
  • 30
4

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.

pid
  • 11,472
  • 6
  • 34
  • 63
3

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.

asmeurer
  • 86,894
  • 26
  • 169
  • 240
3

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

git checkout -f

shubham chouhan
  • 580
  • 7
  • 8
3

Merge --abort only when you merge other branch code and it has conflict.

git merge --abort

If stash pop has conflict, you can use:

git reset --merge
Leon Zhang
  • 41
  • 3
2

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.

Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
2

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.

robrich
  • 13,017
  • 7
  • 36
  • 63
2

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
here
  • 2,790
  • 25
  • 30
1

Try using if tracked file.

git rm <path to file>
git reset  <path to file>
git checkout <path to file>
xpioneer
  • 3,075
  • 2
  • 16
  • 18
1

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

Fatih Acet
  • 28,690
  • 9
  • 51
  • 58
-2

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.