On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gitster@xxxxxxxxx> wrote: > Johan Herland <johan@xxxxxxxxxxx> 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, <johan@xxxxxxxxxxx> www.herland.net -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html