Git cherry-pick causes merge conflict while merging does not

Curious picture Curious · May 15, 2016 · Viewed 14.2k times · Source

I am trying to learn how to use git cherry pick, I read the manual pages that git returns by doing git cherry-pick --help but that did not seem to help. I will try and explain the problem below. I have two branches master and other.

On branch master The commit history is

0x2 Second commit from master branch
0x1 Initial commit

And the only file in the repository that I am tracking readme has the following contents

Some text

On branch other The commit history is

0x5 CHECKPOINT, going to cherry-pick onto master
0x4 second commit from branch other
0x3 first commit from other branch:
0x2 Second commit from master branch
0x1 Initial commit

And the contents of the readme file are

Some text.

Adding some text from other branch.  Adding some more text.

Going to cherry-pick this commit.

The working directory is clean on both branches with no untracked changes. From this point on when I switch to the master branch and merge with git merge other the merge happens gracefully with no merge conflicts. But when I try git cherry-pick 0x5 there is a merge conflict, I get the following output from git

error: could not apply 0x5... CHECKPOINT, going to cherry-pick onto master
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

And the readme file has the following contents

<<<<<<< HEAD
Some text
=======
Some text.

Adding some text from other branch.  Adding some more text.

Going to cherry-pick this commit.
>>>>>>> 0x5... CHECKPOINT, going to cherry-pick onto master

Why is there this merge conflict? I am trying to understand why it occurs. Shouldn't cherry-picking be the same as trying to make all the edits made on the commit that is to be cherry-picked yourself and then commiting that change onto the branch (master in this case)?

Also when exactly is there a merge conflict in git? I seem to get them at weird times. Is this implementation dependent (for example dependent on the algorithm used to merge)?

Thank you!

Answer

VonC picture VonC · May 15, 2016

I just tested that scenario, after reading:

If the modification to the first line (Some text. instead of Some text) was done immediately after 0x2, as in 0x3, then git cherry-pick 0x3 works without conflict.

But if that same change is done a few commits later, the git cherry-pick won't generate a patch compatible with the content of 0x2.

There is no notion of "common ancestor" here (as incorrectly stated here): only of "patch".

A git cherry-pick, even if it uses merging strategies, is not a git merge.

  • A git merge will look for a common ancestor (going back in the history of commits of 0x5, to find a common commit with 0x2: here 0x2 itself)
  • A git cherry-pick only creates a patch by doing a unified diff between two commits (by default, the commit you mention and its immediate parent 0x4)

The point is: that patch won't be able to be applied on top of 0x2.

Try if for yourself: a git cherry-pick 0x5 is like doing a git diff -p 0x4..0x5.
You will see in that patch lines which are not part of 0x2, and reflect changes coming from 0x3 or 0x4.

Such a patch cannot be applied on 0x2, as it is based on a content which does not exist for 0x2.

I have created a test repo in which I made from master two modifications.

  • Adding some text from other branch (no modification to the first line)
  • Then a second commit modifying the first line.

Here what my patch looks like:

C:\Users\vonc\prog\git\tests\cp>git diff -p dev~..dev
diff --git a/f b/f
index 2b6dd7b..1c4bb79 100644
--- a/f
+++ b/f
@@ -1,4 +1,4 @@
-"Some text"
+"Some text."^M

 Adding some text from other branch.  Adding some more text.

I cannot apply (cherry-pick) that commit onto 0x2, as 0x2 has no line "Adding some text from other branch" yet. It only has one line "Some text".

That is why git reports a conflict: the content has diverged, and that patch is supposed to change line 1 on top of a file including "Adding some text from other branch", which 0x2 does not have.

This differs from a git merge of course, as a git merge will look for a common ancestor (here 0x2) and reports all modifications since 0x2 onto 0x2 without any issue.