When there is a conflict in the material to be cherry-picked, Git does the same thing it always does:
- Look at the merge base version;
- look at the
HEAD
version; and
- look at the to-be-merged version.
If you set merge.conflictStyle
to diff3
(I do), you will see all three versions, rather than just two of these three, in the conflict area. I find that this helps to see what Git was seeing.
So why am I seeing anything from A show up in C when it wasn't directly added in B and I'm cherry picking the commits? I'm guessing this is related to the conflict because nothing else from A is coming over, just the stuff around the conflict line.
That's correct: the issue is that Git must find a merge base commit in order to decide "what you changed"—this is the result of comparing the merge base to your current or HEAD
commit—and "what they changed", which is the result of comparing the merge base to "their" commit.
You mentioned "branches" at the beginning of all of this:
I have branch B which was created off of branch A. I make a few commits in branch B that I want to cherry-pick into branch C (which is similar to A).
But in fact, Git mostly doesn't care about branches at all. Git only cares about commits—branches mainly matter to Git in that branch names allow Git to find individual commits. It helps to draw out the actual commits (and, if you like, include the branch labels that let us—and Git—find these commits):
H--I--J <-- branch-B
/
...--E--F--G <-- branch-A
\
K--L <-- branch-C
I've made this graph up from whole cloth, and it may look very little like your graph, but it now allows us to illustrate the odd way git cherry-pick
identifies merge base commits inside Git.
If we're "on branch-C" as git status
might say, our HEAD
commit is commit L
, the tip of branch-C. If we then run git cherry-pick <hash-of-commit-I>
, Git makes these assignments:
- merge-base = commit H
- HEAD or
--ours
= commit L
--theirs
= commit I
Git will then diff (as in git diff
) commit H
against commit I
to see what they did—that's the cherry we would like to pick—but also diff commit H
against commit L
, to see what we changed and look for conflicts.
If there are conflicts, Git shows us what both sides did to the merge base version H
, without actually showing us merge base version H
itself. This may include stuff we didn't want: stuff we "deleted" by going "backwards" from H
to L
. Had Git showed up the merge-base version H
as well, we could see that we "deleted" the stuff we don't want, so we should "keep it deleted" when resolving the merge conflict.