I know git cherry-pick
is a command that use to apply the changes of specified commit, but I think I just don't really understand the way it works.
Let's say a repo act like that:
git init
echo a>a
git add .; git commit -am 'master add line a'
git checkout -b dev
echo b>>a
git commit -am 'dev add line b'
echo c>>a
git commit -am 'dev add line c'
git checkout master
git cherry-pick dev
I thought cherry-pick
command would work well and change file a
into:
a
c
but in fact I got the following message:
error: could not apply 08e8d3e... dev add line c
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 then I run:
git diff
output:
diff --cc a
index 7898192,de98044..0000000
--- a/a
+++ b/a
@@@ -1,1 -1,3 +1,6 @@@
a
++<<<<<<< HEAD
++=======
+ b
+ c
++>>>>>>> 11fff29... abc
So my question is: Why is there a conflict like git-diff shows? What are the details of cherry-pick working in this case?
Technically, since you are editing the same line of the same file on different branches, Git sees this as a conflict. Cherrypicking, while not technically a 'merge' operation, still looks for the same types of conflict and asks you to resolve them.
From git-scm documentation
Try again your cherry-pick after:
You will get a more detailed diff:
It shows that, when applying the patch represented by
dev
's HEAD (b
andc
), Git does not know of a common ancestor; it defers to:c
'after a line 'b
')b
at all on top of which it could apply the added change 'c
')Hence conflict.
Cherry-picking is not like a merge (which looks for a merge-base).
Cherry-picking takes a commit and applies the change that it introduces.
Here the change introduced is: add
c
on top ofb
.And the destination commit has no
b
at all, so for Git:b
" (or never had it in the first place, which is the case here, but Git does not know that),b
on top of whichc
is added.As far as Git knows when trying to apply that patch (and that is all
git cherry-pick
does: apply patch. It does not look for the history of the cherry-picked commit at all), that is a conflict: concurrent modification.If you are sure of the way that resolution should go, you can do:
Then, you would see
b
andc
added to the original commit, without any conflict (since you indicated how to resolve it with the option '-Xtheirs
' passed to the default merge strategyrecursive
)