On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gits...@pobox.com> wrote:
> Johan Herland <jo...@herland.net> writes:
>>> But P is a commit(/merge with two parents), not a blob. Can we have trees
>>> pointing to commits instead of blobs ?
>> Sort of. We do so when recording submodules in regular git trees.
> You are using notes to maintain reachability, aren't you?  Because
> commit objects that appears in trees are not treated as reachable
> from the trees, that won't fly.
> I think you guys are making it unnecessarily complex by using notes.
> To record a prepared evil merge for merging branch that contains A
> with another branch that contains B (assuming that the interation
> between A and B is what makes the evil merge necessary, e.g. A
> renames a function foo() to bar(), while B adds new callsite that
> calls foo()), we can store a single commit that records the prepared
> evil merge under "refs/merge-fix/$A-$B" where A and B are their
> object names.
> Then when merging a branch Y that contains B into our history X that
> already contains A (or vice versa),
>   ---o---o---A---o---X... ???
>       \                  .
>        \                .
>         \              .
>          o---B----o---Y
> we can enumerate the commits that appear in "log --left-right X...Y"
> on the left/right side and notice there is refs/merge-fix/$A-$B.
> So the simplest implementation of "an efficient data store to record
> a commit for <A,B> pair" turns out to be just a ref namespace ;-)
> There may be other <C,D> pairs in X...Y history, and it probably is
> the sane thing to do to replay prepackaged evil merges from older to
> newer in the topological sense, but that loop would be trivial, once
> we understand how to replay a single such evil merge.

This raises the same question I recently asked Antoine: For a given
prepackaged merge <X,Y>, do we assume that it only resolves conflicts
between the changes introduced in commit X vs. changes introduced in
commit Y, or do we assume that it resolves conflicts between the
histories leading up to X and Y, respectively? In other words, does
<X,Y> _supercede_ earlier pre-merges between the histories leading up
to X and Y?

I think the latter makes more sense, since we can then reduce the
number of pre-merges to consider in the final merge. There might still
be more than one pre-merge to consider, though, e.g. in criss-cross
cases like this:

      \             /     \       \
       \           /       \       \
        \         /         \       \
         o---o---o           P2      \
          \       \         /         \
           \       \       /           M
            \       \     /           /
             o---o---+---o           /
              \       \   \         /
               \       P1  \       /
                \     /     \     /

(there is no commit at the "+")

> The actual merge-fix data should be just a commit with a single
> parent. The easiest way to prepare it would be like this:
>   ---o---o---A
>       \       \
>        \       M---F
>         \     /
>          o---B
> where M is the result of mechanical merge between A and B (there
> could be textual conflicts and you could choose to leave them in, or
> you could choose to have rerere resolve it.  As long as you do the
> same when replaying this prepackaged evil merge, this choice does
> not matter, but using rerere will make your life easier), and F is
> the final result you would want, with semantics conflicts resolved.
> In other words, in the ideal world, you would have resolved a merge
> between A and B to record the tree of F.
> Point "F" with refs/merge-fix/$A-$B and you are done.
> When you replay this prepackaged evil merge, first you mechanically
> merge X and Y without worrying about M or F to produce N.  If you
> allowed rerere to resolve textual conflicts between A and B when you
> recorded M, allow rerere to resolve this merge.  Otherwise leave the
> textual conflict in.
>   ---o---o---A---o---X
>       \               \
>        \               N
>         \             /
>          o---B---o---Y
> Then on top of N, you cherry-pick F, which will bring the semantic
> conflict resolution between M and F on top of N.
>   ---o---o---A---o---X
>       \               \
>        \               N---F'
>         \             /
>          o---B---o---Y
> Once you know the tree shape of F', then you no longer need N.  Just
> amend it away and make the tree recorded in F' the result of the
> merge between X and Y.
>   ---o---o---A---o---X---.
>       \                   \
>        \                  F''
>         \                /
>          o---B---o---Y--.

This is obviously a much better way to solve it. It might already be
obvious, but I would suggest when making "refs/merge-fix/$A-$B" that you
canonicalize the name by always choosing A and B such that A precedes B
alphabetically. That way you won't have problems with both recording
"refs/merge-fix/$A-$B" and "refs/merge-fix/$B-$A".


Johan Herland, <jo...@herland.net>
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to