# HG changeset patch # User Gábor Stefanik <gabor.stefa...@nng.com> # Date 1475588213 -7200 # Tue Oct 04 15:36:53 2016 +0200 # Node ID fc6190cdbebfab4a3cff72f213018fcc30b8f25c # Parent bc8729a69d10d61498712d5dab773918f1edcde0 ?copies: update _checkcopies to work in a rotated DAG (issue4028)
This introduces a distinction between "merge common ancestor" and "topological common ancestor". During a regular merge, these two are identical. Graft, however, performs a merge in a rotated DAG, where the merge common ancestor will not be a common ancestor at all in the original DAG. To correctly find copies in case of a graft, we need to take both the merge CA and the topological CA into account, and track any renames between them in reverse. Special care must be taken about the case where the merge CA lies not between the topological CA and the source, but outside it (typically between the topological CA and the destination). This is handled using the remoteca parameter; it would be possible to have _checkcopies itself detect this, but it's quite expensive and also guaranteed not to change between multiple _checkcopies invocations in the same mergecopies call, so it's better to check it there, and pass to _checkcopies as a parameter. diff -r bc8729a69d10 -r fc6190cdbebf mercurial/copies.py --- a/mercurial/copies.py Mon Oct 03 13:29:59 2016 +0200 +++ b/mercurial/copies.py Tue Oct 04 15:36:53 2016 +0200 @@ -345,10 +345,12 @@ bothnew = sorted(addedinm1 & addedinm2) for f in u1u: - _checkcopies(c1, f, m1, m2, ca, limit, diverge, copy1, fullcopy1) + _checkcopies(c1, f, m1, m2, ca, ca, False, limit, diverge, copy1, + fullcopy1) for f in u2u: - _checkcopies(c2, f, m2, m1, ca, limit, diverge, copy2, fullcopy2) + _checkcopies(c2, f, m2, m1, ca, ca, False, limit, diverge, copy2, + fullcopy2) copy = dict(copy1.items() + copy2.items()) movewithdir = dict(movewithdir1.items() + movewithdir2.items()) @@ -373,8 +375,10 @@ % "\n ".join(bothnew)) bothdiverge, _copy, _fullcopy = {}, {}, {} for f in bothnew: - _checkcopies(c1, f, m1, m2, ca, limit, bothdiverge, _copy, _fullcopy) - _checkcopies(c2, f, m2, m1, ca, limit, bothdiverge, _copy, _fullcopy) + _checkcopies(c1, f, m1, m2, ca, ca, False, limit, bothdiverge, _copy, + _fullcopy) + _checkcopies(c2, f, m2, m1, ca, ca, False, limit, bothdiverge, _copy, + _fullcopy) for of, fl in bothdiverge.items(): if len(fl) == 2 and fl[0] == fl[1]: copy[fl[0]] = of # not actually divergent, just matching renames @@ -454,7 +458,8 @@ return copy, movewithdir, diverge, renamedelete -def _checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy): +def _checkcopies(ctx, f, m1, m2, ca, tca, remoteca, limit, diverge, copy, + fullcopy): """ check possible copies of f from m1 to m2 @@ -462,7 +467,9 @@ f = the filename to check m1 = the source manifest m2 = the destination manifest - ca = the changectx of the common ancestor + ca = the changectx of the common ancestor, overridden on graft + tca = topological common ancestor for graft-like scenarios + remoteca = True if ca is outside tca::ctx, False otherwise limit = the rev number to not search beyond diverge = record all diverges in this dict copy = record all non-divergent copies in this dict @@ -475,6 +482,8 @@ """ ma = ca.manifest() + mta = tca.manifest() + backwards = ca != tca and not remoteca and f in ma getfctx = _makegetfctx(ctx) def _related(f1, f2, limit): @@ -520,15 +529,26 @@ continue seen.add(of) - fullcopy[f] = of # remember for dir rename detection + # remember for dir rename detection + if backwards: + fullcopy[of] = f # grafting backwards through renames + else: + fullcopy[f] = of if of not in m2: continue # no match, keep looking if m2[of] == ma.get(of): return # no merge needed, quit early c2 = getfctx(of, m2[of]) - cr = _related(oc, c2, ca.rev()) + cr = _related(oc, c2, tca.rev()) if cr and (of == f or of == c2.path()): # non-divergent - copy[f] = of + if backwards: + copy[of] = f + elif of in ma: + copy[f] = of + elif remoteca: # special case: a <- b <- a -> b "ping-pong" rename + copy[of] = f + del fullcopy[f] + fullcopy[of] = f return if of in ma: diff -r bc8729a69d10 -r fc6190cdbebf tests/test-graft.t --- a/tests/test-graft.t Mon Oct 03 13:29:59 2016 +0200 +++ b/tests/test-graft.t Tue Oct 04 15:36:53 2016 +0200 @@ -427,8 +427,8 @@ $ hg graft 3 --log -u foo grafting 3:4c60f11aa304 "3" warning: can't find ancestor for 'c' copied from 'b'! - $ hg log --template '{rev} {parents} {desc}\n' -r tip - 14 1:5d205f8b35b6 3 + $ hg log --template '{rev}:{node|short} {parents} {desc}\n' -r tip + 14:0c921c65ef1e 1:5d205f8b35b6 3 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8) Resolve conflicted graft @@ -620,7 +620,7 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: 2 - changeset: 14:f64defefacee + changeset: 14:0c921c65ef1e parent: 1:5d205f8b35b6 user: foo date: Thu Jan 01 00:00:00 1970 +0000
_______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel