Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`git stash` during a merge conflict

We've done something bad.

We ran git stash save during a merge conflict, and now we can't restore our work.

Things we've tried:

git pull -Xours origin master
git stash apply --index

And:

 git pull origin master
 git stash save --keep-index "merge conflicts"
 git stash apply stash@{1}

Please help!

like image 765
steven_moy Avatar asked Jan 25 '12 19:01

steven_moy


People also ask

Can you stash merge conflicts?

Yes, we can get merge conflict while applying stash. Let's see it in action. Let's create a file, add some content to it and commit it. Please note we must have a commit before we can use git stash the first time.

How do I resolve merge conflicts in stash?

There's no magic remedy for such merge conflicts. The only option for developers is to edit the file by hand and keep what they want and dispose of what they don't want. Once they merge and save the file, they will have effectively resolved the git stash conflict.

Can I stash a merge in progress?

The in-progress merge is stored in the index and work-tree. Given that git stash makes two commits out of these two, you would think it would be just the right thing—except that the in-progress merge state cannot be stored in a commit: it contains metadata that git will not write into a tree.

What happens if you get a conflict during a merge?

Merge conflicts happen when you merge branches that have competing commits, and Git needs your help to decide which changes to incorporate in the final merge. Git can often resolve differences between branches and merge them automatically.


3 Answers

The issue seems to be that git stash doesn't save a reference to the branch you were trying to merge in. During a merge, this is stored in a ref named MERGE_HEAD.

To fix it and get back to your previous state, you need to find the revision (let's pretend it's d7a9884a380f81b2fbf002442ee9c9eaf34ff68d) you were trying to merge in, and set MERGE_HEAD to it after you apply the stash.

Then you can apply the stash (with --index to re-stage everything that was staged before), and set your MERGE_HEAD:

git stash apply --index
git update-ref MERGE_HEAD d7a9884a380f81b2fbf002442ee9c9eaf34ff68d
like image 116
Evan Krall Avatar answered Oct 18 '22 02:10

Evan Krall


I did the same thing today, and took a different approach (after trial and error) to get back to the state just prior to stashing so I could continue resolving conflicts and complete the merge.

First, after unstashing the partial merge in the destination branch, I captured a list of the files with remaining conflicts (text file or editor tab). This is just the list of unstaged files after unstashing, as the files with conflicts already resolved would have been staged prior to stashing.

$ git status
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   myproject/src/main/java/com/acme/package3/Class3.java
#   modified:   myproject/src/main/java/com/acme/package3/Class4.java
#

Next, I created a patch and reset the branch back to the pre-merge state:

$ git diff HEAD > ~/merge-with-resolved-conflicts.patch
$ git reset --hard HEAD

Then I created a temporary branch (derived from the merge destination branch), and applied the patch:

$ git checkout -b my-temp-branch
$ git apply ~/merge-with-resolved-conflicts.patch
$ git commit -a -m "Merge with resolved conflicts"

So the HEAD of my-temp-branch now contains everything that was merged, including files with conflicts resolved, and files with remaining conflicts.

Then I switched back to original branch, merged again, and looked at the git status

$ git checkout my-branch
$ git merge other-branch
$ git status

The status shows the full list of files with conflicts:

# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#   both modified:      myproject/src/main/java/com/acme/package1/Class1.java
#   both modified:      myproject/src/main/java/com/acme/package2/Class2.java
#   both modified:      myproject/src/main/java/com/acme/package3/Class3.java
#   both modified:      myproject/src/main/java/com/acme/package3/Class4.java
#

Now I needed to compare these two lists of files. Any files in the second list but not the first had already been resolved (in this example, Class1.java and Class2.java). So for each of those files, I pulled in the version with conflicts resolved from the temporary branch (like cherry-pick, but for individual files rather than an entire commit):

$ git checkout my-temp-branch myproject/src/main/java/com/acme/package1/Class1.java
$ git checkout my-temp-branch myproject/src/main/java/com/acme/package2/Class2.java

Having done this, I was back to the state before the stash, so I could resume resolving the remaining conflicts and commit the merge.

like image 28
mmindenhall Avatar answered Oct 18 '22 00:10

mmindenhall


When you are in a conflicted state ( index and working directory), you will not be able to do git stash - it will give an error sating unmerged entries.

Make sure that you have really done a stash. See output of git stauts and git stash show

like image 1
manojlds Avatar answered Oct 18 '22 02:10

manojlds