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?
Try again your cherry-pick after:
git config merge.conflictstyle diff3
You will get a more detailed diff:
<<<<<<< HEAD
||||||| parent of 5b2a14c... dev add line c
b
=======
b
c
>>>>>>> 5b2a14c... dev add line c
It shows that, when applying the patch represented by dev
's HEAD (b
and c
), 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 of b
.
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 which c
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:
> git cherry-pick -Xtheirs dev
[master 7849e0c] dev add line c
Date: Wed Aug 17 08:25:48 2016 +0200
1 file changed, 2 insertions(+)
Then, you would see b
and c
added to the original commit, without any conflict (since you indicated how to resolve it with the option '-Xtheirs
' passed to the default merge strategy recursive
)