Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GIT: Why do I need to solve my merge conflicts twice when using rebase?

Tags:

git

git-branch

I really like the git pull --rebase option, but when using it combined with a merge conflict I end up solving my conflicts twice. I have tried to use git pull --rebase=preserve which should make it considering merges as well.

Try have a look at the following example:

# do a new clone "a"
$ mkdir origin && cd origin && git init --bare --shared && cd ..
$ git clone ./origin a && cd a

# Add, commit, push
a (master) $ echo "foo" > foo && git add foo && git commit -m "foo"
a (master) $ git push origin master

# Create branch "b"
a (master) $ git branch b

# change foo and push
a (master) $ echo "// eof " >> foo && git ci -am "eof - master"
a (master) $ git push origin master

# checkout branch "b", change and push
a (master) $ git checkout b
a (b) $ echo "// EOF " >> foo && git ci -am "EOF b" && git push origin b

# back to master
a (b) $ git checkout master

# merge
a (master) $ git merge b # conflict as expected
a (master) $ git diff
diff --cc foo
index e10b853,1d3cc50..0000000
--- a/foo
+++ b/foo
@@@ -1,2 -1,2 +1,6 @@@
  foo
++<<<<<<< HEAD
 +// eof
++=======
+ // EOF
++>>>>>>> b

# Now, resolve the conflict
a (master|MERGING) $ echo "foo" > foo && echo "// eof" >> foo && git add foo
a (master|MERGING) $ git commit

# In the mean while somewhere else. ############################################
a (master) $ cd ..  && git clone ./origin other && cd other/
other (master) $ echo "bar" > bar && git add bar && git ci -am "bar" && git push # OK

# Back to us ###################################################################
other (master) $ cd ../a
a (master) $ git push # will fail...

# I now do a rebase preserve as I want to rebase my merge commit to the top of master
a (master) $ git pull --rebase=preserve # This command does not do a very good job...
a (master|REBASE-i 1/1) $ git diff
diff --cc foo
index e10b853,1d3cc50..0000000
--- a/foo
+++ b/foo
@@@ -1,2 -1,2 +1,6 @@@
  foo
++<<<<<<< HEAD
 +// eof
++=======
+ // EOF
++>>>>>>> 3cd5d3ac5b870c613233f0a9f1a81df5691ccc7c

If I replace git pull --rebase=preserve with git pull --no-rebase then it works as expected (I only need to solve the conflicts once), but then I have to look at all these merge commits in my log.

How can I make git "rebase" the merge-and-the-conflict-solving such that it fit on top on the new remote HEAD?

like image 617
Allan Avatar asked Feb 09 '15 17:02

Allan


2 Answers

I found that the Git "rerere" feature solved my issue.

Documented in: git rerere --help or http://git-scm.com/docs/git-rerere

Adding this to my .gitconfig

[rerere]
    enabled = true

Solved my problem.

like image 172
Allan Avatar answered Sep 22 '22 09:09

Allan


Rebase basically just takes commits between HEAD and base and applies them sequentially on base. This means that if you had some merges between them they are lost and you have to resolve conflicts again. Illustration:

Let's say you have following tree:

A--B---M
 \    / 
  `-C'

M is the merge of conflicting changes B and C and it's your HEAD. Now if you run git rebase A then git will try to create following tree:

A-B-C

But when trying to apply C onto B it encounters a conflict. Having disregarded merge M it has to ask you, the user to resolve it.

At this point you can just check out files in question from revision M which has them already merged: git checkout M -- file/with/conflict, but I don't know of any means to do this automatically (e.g. rebase option).

To be honest I really don't understand people's dislike of merges, I personally see them as useful, but if you want you can omit them in log with --no-merges

like image 22
joozek Avatar answered Sep 23 '22 09:09

joozek