As I understand, cherry picking a certain commit introduces a new commit to the target branch, with the changes done in the cherry picked commit.
That is correct. However, these changes may not apply cleanly, in which case:
... I encountered a merge conflict.
At this point, git cherry-pick
is doing a three-way merge, which requires choosing a merge base.
Which files or commits are used as the merge base depends in part on your Git version, as I recall. Modern Git, if you run git cherry-pick
, uses the cherry-picked commit's parent as the merge base, but at least one form (using git am
or git apply
with the --3way
option, which git rebase
can still do) can pick out a much earlier version of a file using the index
lines of git diff
output. In the end, this probably should not matter too much.
In any case, the merge will, in effect, run git diff
from the base commit to each of the two "tips" (the cherry-picked commit, and the HEAD commit to which you are attempting to apply the cherry-pick). To see, visually, what's going on, you should—as usual—start by drawing the commit graph. (I don't have your repository, so I will draw a different graph and hope it's close enough. But you should draw your own—or have Git do it, or use gitk
or some such.)
o--@ <-- branch (HEAD)
/
...--o--o
\
I--P--C--o <-- otherbranch
I have given single-letter names to various commits here: C
is the commit we are about to cherry pick, and P
is its parent. I marked our current (HEAD) commit as @
here, though all the real work will happen in the index and work-tree. (Fortunately git cherry-pick
requires that the index and work-tree be "clean", unless you are using -n
to assemble multiple cherries into one big pick, so the index and work-tree will match commit @
anyway.) And, I marked commit I
as "important".
Now, consider what happens if we do a three way merge with P
as the base, C
as one of the commits, and @
as the other commit. When we compute instructions for changing P
into C
, we get the diff we want to apply: that's quite straightforward. But when we compute instructions for changing P
into @
, well, ugh.
We made some important changes in I
. Those changes are part of P
, i.e., they're in our merge base. But they are not in @
. The implication for merging is that Git will think of those important changes as things we are trying to un-do. And in fact, they are! We did not cherry-pick I
itself, so we must undo these I
changes in order to apply the changes from C
.
Wherever those I
changes we are "undoing" aren't in @
to start with and don't affect any of the changes from C
, we're fine: they're already undone. If, by some chance or purpose, one of those I
changes is in @
(perhaps through @
's parent), those aren't even in the set we're trying to undo in the first place, so again we're fine. It's when those changes conflict with, or even just abut into (the context of), the P
-to-C
changes, that we have problems.
In this case, Git will show, in one of the two merge conflict areas, some I
changes. Those are in the part we're trying to cherry-pick. They are not necessarily being applied, they are just part of the conflict we must resolve. And if you set merge.conflictStyle
to diff3
—something I generally recommend—the I
changes will be shown as part of the merge base, because the merge base is commit P
, which is itself based on I
(i.e., P
's snapshot includes the code from I
except where we changed it while making P
).
So, it's not entirely clear to me what you are asking about, but it is normal to see, in the merge conflict area, changes unrelated to the bits you are cherry-picking.
git cherry-pick
does not give me a merge conflict, but the modified file has changes it should not have and I get the same using a patch andgit apply
. – Reprise