]> git.ipfire.org Git - thirdparty/git.git/commit - git-merge-octopus.sh
git-merge-octopus: use (merge-base A (merge B C D E...)) for stepwise merge
authorJunio C Hamano <gitster@pobox.com>
Sun, 27 Jul 2008 20:47:22 +0000 (13:47 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 Jul 2008 07:20:51 +0000 (00:20 -0700)
commitc5dc9a28298afb75d2be6b212d420fc89c258aa0
tree305485d603d840b7c92bebf0f133101f333f3d66
parenta7a66921772ca5e609d283b0b73b8dd446a2a506
git-merge-octopus: use (merge-base A (merge B C D E...)) for stepwise merge

Suppose you have this topology, and you are trying to make an octopus
across A, B and C (you are at C and merging A and B into your branch).
The protoccol between "git merge" and merge strategies is for the former
to pass common ancestor(s), '--' and then commits being merged.

git-merge-octopus does not produce the final merge in one-go.  It
iteratively produces pairwise merges.  So the first step might be to come
up with a merge between B and C:

               o---o---o---o---C
              /                 :
             /   o---o---o---B..(M)
            /   /
        ---1---2---o---o---o---A

and for that, "1" is used as the merge base, not because it is the base
across A, B and C but because it is the base between B and C.  For this
merge, A does not matter.

I drew M in parentheses and lines between B and C to it in dotted line
because we actually do _not_ create a real commit --- the only thing we
need is a tree object, in order to proceed to the next step.

Then the final merge result is obtained by merging tree of (M) and A using
their common ancestor.  For that, we _could_ still use "1" as the merge
base.

But if you imagine a case where you started from A and M, you would _not_
pick "1" as the merge base; you would rather use "2" which is a better
base for this merge.

That is why git-merge-octopus ignores the merge base given by "merge" but
computes its own.

The comment at the end of git-merge-octopus talks about "merge reference
commit", that we used to update it to common found in this round, and that
that updating was pointless.  After the first round of merge to produce
the tree for M (but without actually creating the commit object M itself),
in order to figure out the merge base used to merge that with A in the
second round, we used to use A and "1" (which was merge base between B and
C).  That was pointless --- "merge-base A 1" is guaranteed to give a base
that is no better than either "merge-base A B" or "merge-base A C".  So
the current code keeps using the original head (iow, MRC=C, because in
this case we are starting from C and merging B and then A into it).

This trickerly was necessary only because we avoided creating the extra
merge commit object M.

Side note.  An alternative implementation could have been to
actually record it as a real merge commit M, and then let the
two-commit merge-base compute the base between A and M when
merging A to the result of the previous round, but we avoided
creating M, at the expense of potentially using suboptimal base in
the later rounds.

But we do not have to be that pessimistic.  We can instead accumulate the
commits we have merged so far in MRC, and have merge_bases_many() compute
the merge base for the new head being merged and the heads we have
processed so far, which can give a better base than what we currently do.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-merge-octopus.sh