git stash blunder: git stash pop and ended up with merge conflicts

131,393

Solution 1

See man git merge (HOW TO RESOLVE CONFLICTS):

After seeing a conflict, you can do two things:

  • Decide not to merge. The only clean-ups you need are to reset the index file to the HEAD commit to reverse 2. and to clean up working tree changes made by 2. and 3.; git-reset --hard can be used for this.

  • Resolve the conflicts. Git will mark the conflicts in the working tree. Edit the files into shape and git add them to the index. Use git commit to seal the deal.

And under TRUE MERGE (to see what 2. and 3. refers to):

When it is not obvious how to reconcile the changes, the following happens:

  1. The HEAD pointer stays the same.

  2. The MERGE_HEAD ref is set to point to the other branch head.

  3. Paths that merged cleanly are updated both in the index file and in your working tree.

  4. ...

So: use git reset --hard if you want to remove the stash changes from your working tree, or git reset if you want to just clean up the index and leave the conflicts in your working tree to merge by hand.

Under man git stash (OPTIONS, pop) you can read in addition:

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.

Solution 2

I had a similar thing happen to me. I didn't want to stage the files just yet so I added them with git add and then just did git reset. This basically just added and then unstaged my changes but cleared the unmerged paths.

Solution 3

If, like me, what you usually want is to overwrite the contents of the working directory with that of the stashed files, and you still get a conflict, then what you want is to resolve the conflict using git checkout --theirs -- . from the root.

After that, you can git reset to bring all the changes from the index to the working directory, since apparently in case of conflict the changes to non-conflicted files stay in the index.

You may also want to run git stash drop [<stash name>] afterwards, to get rid of the stash, because git stash pop doesn't delete it in case of conflicts.

Solution 4

Note that Git 2.5 (Q2 2015) a future Git might try to make that scenario impossible.

See commit ed178ef by Jeff King (peff), 22 Apr 2015.
(Merged by Junio C Hamano -- gitster -- in commit 05c3967, 19 May 2015)

Note: This has been reverted. See below.

stash: require a clean index to apply/pop

Problem

If you have staged contents in your index and run "stash apply/pop", we may hit a conflict and put new entries into the index.
Recovering to your original state is difficult at that point, because tools like "git reset --keep" will blow away anything staged.

In other words:

"git stash pop/apply" forgot to make sure that not just the working tree is clean but also the index is clean.
The latter is important as a stash application can conflict and the index will be used for conflict resolution.

Solution

We can make this safer by refusing to apply when there are staged changes.

That means if there were merges before because of applying a stash on modified files (added but not committed), now they would not be any merges because the stash apply/pop would stop immediately with:

Cannot apply stash: Your index contains uncommitted changes.

Forcing you to commit the changes means that, in case of merges, you can easily restore the initial state( before git stash apply/pop) with a git reset --hard.


See commit 1937610 (15 Jun 2015), and commit ed178ef (22 Apr 2015) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit bfb539b, 24 Jun 2015)

That commit was an attempt to improve the safety of applying a stash, because the application process may create conflicted index entries, after which it is hard to restore the original index state.

Unfortunately, this hurts some common workflows around "git stash -k", like:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

If you "git commit" between steps (3) and (4), then this just works. However, if these steps are part of a pre-commit hook, you don't have that opportunity (you have to restore the original state regardless of whether the tests passed or failed).

Solution 5

git restore --staged  name-of-file-that-has--merge-conflict
Share:
131,393

Related videos on Youtube

Chirag Patel
Author by

Chirag Patel

I work on Rails, Javascript and lately PHP. Enjoy building stuff in general

Updated on September 11, 2021

Comments

  • Chirag Patel
    Chirag Patel over 2 years

    I did a git stash pop and ended up with merge conflicts. I removed the files from the file system and did a git checkout as shown below, but it thinks the files are still unmerged. I then tried replacing the files and doing a git checkout again and same result. I event tried forcing it with -f flag. Any help would be appreciated!

    chirag-patels-macbook-pro:haloror patelc75$ git status
    app/views/layouts/_choose_patient.html.erb: needs merge
    app/views/layouts/_links.html.erb: needs merge
    # On branch prod-temp
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   db/schema.rb
    #
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #       unmerged:   app/views/layouts/_choose_patient.html.erb
    #       unmerged:   app/views/layouts/_links.html.erb
    
    chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
    error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
    chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
    warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
    
    • VonC
      VonC almost 9 years
      Note: restoring the state before the git stash apply/pop should be easier with Git 2.5 (Q2 2015), since the working tree now needs to be clean: see my answer below
  • phils
    phils over 12 years
    In fact, even after you drop a stash, it's still possible (albeit more difficult) to retrieve it again, because the changeset still exists in the repository. stackoverflow.com/search?q=git+recover+dropped+stash
  • nalply
    nalply over 12 years
    I didn't understand the answer but ended up doing exactly what is described here by finding it out by myself... :)
  • tanascius
    tanascius over 12 years
    @nalply: is that good or bad? You are welcome to improve my answer, where you didn't understand it in the first place ...
  • nalply
    nalply over 12 years
    I think that source code revisioning is a complex problem domain. It is easy to get confused. I still think that your answer is good because it reconfirmed my approach.
  • sinelaw
    sinelaw over 11 years
    This seems to be better than using reset --hard because it doesn't overwrite your files (except the ones with merge problems). Thanks!
  • Drew Noakes
    Drew Noakes almost 11 years
    I didn't want to stage the files just yet so I added them -- doesn't add stage content from the working tree to the index? I don't think I understand why your answer works from the description.
  • Aaron
    Aaron almost 11 years
    git add does stage them but git reset, which I do immediately after, unstages them. Essentially it clears the unmerged paths and returns me to my normal working tree by faking git out.
  • bambams
    bambams about 10 years
    You don't need to git add if you're going to git reset. The git reset effectively "undoes" the git add. git reset (--mixed <- default) effectively does not touch the working directory so exactly what was in your working directory, merge conflicts and all, are left alone. The index (and technically the branch head) is reset though (without a ref they get reset back to HEAD, which probably means no change for the branch head, and effectively undoes any git add done to the index, as well as clearing the unmerged paths state).
  • artless noise
    artless noise about 10 years
    The sequence, edit/resolve, git reset and git stash drop works well. It does what git stash pop would have done with no conflicts. It does seem the git add is not needed; although it maybe useful it you have many files with conflicts. As each is resolved, they can be added and git status keeps track of them.
  • Olga
    Olga almost 10 years
    I was looking for something like git stash pop --continue after conflicts are merged. Last abstract helped me a lot =)
  • Thor84no
    Thor84no almost 9 years
    Not only did it help me a lot to realise that the stash hasn't been removed as I assumed it had, but this explains why my stash kept growing even when I was certain I hadn't been forgetting to retrieve things from it.
  • Patrick M
    Patrick M over 8 years
    "Applying the state can fail with conflicts; in this case, it is not removed from the stash list." This is the most important part of the post, in my opinion. Consider editing your answer to put it up front along with a the words DON'T PANIC in large, friendly letters. (+1 already though.) Thanks.
  • user3613932
    user3613932 about 4 years
    Ran into the same issue. Simply call the git mergetool, and then do pop the stack once.
  • joanis
    joanis over 2 years
    This seems like a useful alternative solution, but can add an introduction explaining what effect this has exactly? There are several options one might want, and this one won't always be the right one.