On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <[email protected]> wrote:
> Johan Herland <[email protected]> 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---o---o---o---o---o
\ / \ \
\ / \ \
\ / \ \
o---o---o P2 \
\ \ / \
\ \ / M
\ \ / /
o---o---+---o /
\ \ \ /
\ P1 \ /
\ / \ /
o---o---o---o---o
(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
--
Johan Herland, <[email protected]>
www.herland.net
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html