Reputation: 13953
1 <- 2 <- 5 (merge commit) <- master <- HEAD
\ /
3 <-- 4 <- dev
2
and 4
during the a merge? If I am right, then in which situations a two way merge is used?Upvotes: 4
Views: 5071
Reputation: 489808
I don't think anyone really talks about "two way diffs"; they are just "diffs". In practice I don't see the phrase "three way diffs" used either, but in version control, it is the obvious label for a pair of diffs starting from a common merge base, looking at two subsequent but divergent snapshots. (You might also look up "interdiff". See How do I get the interdiff between these two git commits? and https://linux.die.net/man/1/interdiff.)
The term merge has multiple meanings, and is (for instance, unrelated to Git) well-defined when talking about K-way merge sort. However, when it comes to version control (more general than just Git), the phrase three way merge is quite specific, and refers to a merge that starts with a merge base version, from which there are two divergences.
Using the fact that version control systems have defined "three way merge", some people have made a kind of back-formation to call the process of applying a single diff a "two-way merge". This is not a good term, in my opinion, as there is no real merging going on. Just call it "applying a diff" or "applying a patch".
See also Why is a 3-way merge advantageous over a 2-way merge? Note that the comment that talks about a 4 or even 5 way merge is not really applicable to Git.
You can use git diff --full-index <commit1> <commit2> | git apply -3
to make Git do three-way merges on individual files, where each merge base version of each file is selected individually from the index
line. However, this is essentially the same as choosing all the files associated with <commit1>
as the merge base. The way this works is that git diff
prints the hash ID of each blob in its output, and if git apply
is unable to apply the patch as-is, Git will use the printed blob ID to locate the original file, then compute a second diff from that merge base version to the current version of the file.1 It then feeds the two diffs into the merge machinery. (See also the git merge-file
command.) But note that the blob hash of each file in <commit1>
is determined strictly by the tree object attached to <commit1>
. This is therefore no different from saying the files associated with <commit1>
. That is, it's no different with one exception: if Git has the commit hash ID, or the corresponding tree ID, Git can do a tree-wide file comparison to look for rename operations, after which Git can associate the merge base's file path PB with a different path PL, the "local" or --ours
file.
In other words, the primary differences between git diff --full-index <parent> <child> | git apply -3
and git cherry-pick <child>
is that the former will not detect renames during the fall-back "three-way patch" operation, and will even not try a three-way merge on any one file if it's able to do the patch application without that. It is, I think, difficult (but not impossible) to construct artificial examples in which these produce very different outcomes, but I don't have time to do that right now.
1Things get a little complex here since "the current version" is not necessarily the HEAD version. Specifically, git apply
uses the work-tree version as the --ours
variant, while git apply --index
uses the index version as the --ours
variant. The git cherry-pick
command, however, requires that the index and work-tree be "clean" by default, i.e., match the HEAD
commit. In this case, there's normally no difference between "the HEAD version", "the index version", and "the work-tree version".
Upvotes: 5