6

Given that I have 3 commits in order

c1
+ print("A")

c2
+ print("B")

c3
+ print("C")

then I checkout a new branch at c1.

git checkout -b br c1

then I cherry-pick c3.

git cherry-pick c3.

what I want is the file has

print("A")
print("C") 

-- I just pick c3 and c3 just add the line print("C")

but the fact is I got conflicts and the result is

print("A")
++<<<<<<< HEAD
++=======
+ print("B")
+ print("C")
++>>>>>>> f1383aa... C

my question are: 1. why conflicts? 2. what shall i do if I want print("A") and print("C")?

I also tried even I

git diff C^1 .. C > 1.patch
git apply 1.patch

I got

zhifan@zhifandeMacBook-Pro ~/g/demo> git apply 1.patch
error: patch failed: 1.py:1
error: 1.py: patch does not apply
zhihuifan
  • 1,093
  • 2
  • 16
  • 30

1 Answers1

6

Cherry-picking is essentially copying (the effects of) a commit. You can think of it the way you obviously are—i.e., as diff the to-be-picked commit and its parent, then apply that diff to the current commit. However, it's more powerful than a mere diff-and-apply, because it has access to Git's full merge mechanism.

What this means is that git cherry-pick is really a full blown git merge internally, with the two commits being merged being your current commit—your HEAD—and the commit you are cherry-picking. The merge base for this operation is the parent of the commit you are cherry-picking.

The reason to do this is that, as you have seen, you can get a merge conflict if both your HEAD commit and the commit you are cherry-picking have changed "the same" lines. In this case, your HEAD commit added the line print("A"), probably at the end of the file, but in any case right before some other line. Meanwhile, the commit you are telling Git to cherry-pick—commit c3—adds the line print("C") at the same place (at the end of the file, or before the same existing line). Git does not know where to place the added print, so it declares a conflict and makes you choose the correct answer.

The solution is simple enough: open the conflicted file in your editor and adjust it to contain the correct resolution of the conflict, then write this out and use git add on the file so that you can run git cherry-pick --continue to finish up the cherry-picking process. Or, if you prefer, use a merge tool to obtain all three input files (base, "ours" or HEAD, and "theirs" or c3's version) and resolve the conflict that way.

For more about cherry-pick, see What does cherry-picking a commit with git mean?

torek
  • 448,244
  • 59
  • 642
  • 775
  • thanks @torek, I can understand the way you described here now, but given the c3, the only change is adding the line print("C"). after I cherry-pick c3, I get the conflicts the thing like ++<<<<<<< HEAD ++======= + print("b") + print("c") ++>>>>>>> f1383aa... C . with this I can't tell the difference between print("b") and print("c"), but in fact, they are different since print("c") is added in c3 and print("b") not. Is there any way to improve the experience here? – zhihuifan Oct 23 '18 at 01:55
  • If you set `merge.conflictStyle` to `diff3`, you'll get the base version as well as the two commit versions. I find this very helpful in resolving conflicts. Others swear by the mergetool method, since you get three windows (or whatever the mergetool shows) on the three versions. – torek Oct 23 '18 at 05:31