[PATCH STABLE] graft: support grafting across renames (issue4028)

Matt Mackall mpm at selenic.com
Tue Jul 26 13:39:50 EDT 2016

On Wed, 2016-07-27 at 00:07 +0900, Yuya Nishihara wrote:
> On Mon, 25 Jul 2016 13:16:32 -0500, Gábor Stefanik wrote:
> > 
> > # HG changeset patch
> > # User Gábor Stefanik <gabor.stefanik at nng.com>
> > # Date 1469470573 -7200
> > #      Mon Jul 25 20:16:13 2016 +0200
> > # Branch stable
> > # Node ID 395d3fa2ac89fad199c99cc137bf801502292325
> > # Parent  9c2cc107547fd701a7604349632f2f590366f17c
> > graft: support grafting across renames (issue4028)
> > 
> > Graft performs a merge with a false common ancestor, which must be taken
> > into
> > account when tracking renames. Compute the real common ancestor in this
> > case,
> > and track renames between the real and false common ancestors in reverse.
> I don't know the detail of the copy tracing, I can't tell if this strategy
> is correct.
> Many tests fails with this patch.

Yes, I'm afraid it's much trickier than this.

Basically, the main copy tracing function for merges assumes all merges go
forward in history because it was written before we had any form of rebasing or

  ancestor --> a - merge
    \            /
     --------> b 

But when we graft or rebase, we're doing a merge that looks like this:

   ancestor--<--a_parent-> a - b'
        \                     /
         ------------------> b

..and twisting the graph to look like this:

a_parent -------------> a - b'
    \                      /
     --->-ancestor -----> b

The stretch between a_parent and ancestor is backwards in the real history but
gets flipped for our effective merge DAG. That means a rename of x to y in that
span effectively becomes a rename from y to x for the purposes of our operation.
But the spans from a_parent to a and from ancestor to b remain unflipped.
Teaching mergecopies() how to do this amounts to a complete rewrite.

The situation with copies is even more confusing (search the list archives for a
discussion of "ypoc"s).

And it's actually even trickier than this, since the merge ancestor is actually
not a sufficiently large scope for finding relevant copies! See the comment


Working out how to properly combine -that- with the DAG twist above is non-

(You may be wondering: but how does Git do it? Git doesn't store rename/copy
data, it uses heuristics to guess which files have been renamed without even
inspecting the DAG. We'll probably add this capability at some point.)
Mathematics is the supreme nostalgia of our time.

More information about the Mercurial-devel mailing list