Reputation: 215
The git merge documentation states for the example:
A---B---C topic
/
D---E---F---G master
Then "git merge topic" will replay the changes made on the topic branch since it diverged from master (i.e., E) until its current commit (C) on top of master, and record the result in a new commit along with the names of the two parent commits and a log message from the user describing the changes.
I'm wondering about the phrase "replay the changes." I could hardly find mention of the word "replay" in other articles about git merging.
I imagine git finding what changed between A and the merge base, applying that change, applying the diff between B and A, applying the diff between C and B, then consolidating that series of changes into a merge commit. Essentially looking at each commit after the merge base and evaluating them individually.
If that's true, what happens in the case of...
A---B---C---I topic
/ \
D---E---F---G---H(merge)---O master
and I want to merge master into topic. Assuming the current branch is topic, "git merge master." My merge base per "git merge-base master topic" is commit C.
If we stick to the story of "replaying" changes, how does the topic branch get the changes to commits F and G? Is it finding the diff between H and C (the merge base)? If so, why replay a series of changes in the first example and instead just find the diff between the branch heads and the merge base?
Upvotes: 2
Views: 1327
Reputation: 15088
git-merge
man page acknowledges this potential confusion and offers clarity(emphasis added by me)
With the strategies that use 3-way merge (including the default, ort), if a change is made on both branches, but later reverted on one of the branches, that change will be present in the merged result; some people find this behavior confusing. It occurs because only the heads and the merge base are considered when performing a merge, not the individual commits. The merge algorithm therefore considers the reverted change as no change at all, and substitutes the changed version instead.
Upvotes: 0
Reputation: 489858
I think the word "replay" is poor terminology:
I imagine git finding what changed between A and the merge base, applying that change, applying the diff between B and A, applying the diff between C and B, then consolidating that series of changes into a merge commit.
That would be a reasonable way to interpret the wording.
That's not what Git does.
Conclusion: the wording is poor.
What Git does do is to find the merge base1 and then compute diffs from that commit to the two2 commits that are to be merged, one diff against each such commit. These diffs effectively "skip over" all the intermediate work.
1Assuming there is a single lowest common ancestor in the graph, that is. If there are multiple LCA candidates, the next step depends on the merge strategy.
The -s recursive
(default) strategy handles multiple merge bases (two or more LCAs) by merging them and making a new temporary commit. It makes that merge by calling itself recursively, hence the name "recursive". The -s resolve
strategy handles multiple merge bases by picking one merge base arbitrarily and proceeding as if there were only the one merge base.
2Two or more, really, except that only certain merge strategies handle more than two heads. Specifically, the -s ours
strategy can use any number of heads—but it ignores all but the current head anyway, which means it makes a merge commit (merge as a noun/adjective) without doing any merge work (merge as a verb). The -s octopus
strategy can also handle more than two heads, but is otherwise more limited than the two-head strategies.
Upvotes: 7
Reputation: 45819
The description they are using here is just that: descriptive. But there is nothing wrong with it, really.
Technically git looks at exactly three commits: "ours", "theirs", and the "merge base". The changes between the merge base and "theirs" are applied to "ours", so long as they don't conflict with any changes between the merge base and "ours". The documentation describes this as "replaying" the changes. It doesn't imply that each commit is examined along the way (a la rebase).
From that standpoint, your 2nd example is quite simple: base is C
, "theirs" is H
, the differences between C
and H
are calculated and those changes are applied ("replayed") to I
.
Upvotes: 3