简体   繁体   中英

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

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?

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.

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 (eg 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM