diff --git a/mercurial/copies.py b/mercurial/copies.py --- a/mercurial/copies.py +++ b/mercurial/copies.py @@ -150,7 +150,7 @@ t[k] = v return t -def _tracefile(fctx, am, limit): +def _tracefile(fctx, am, basemf, limit): """return file context that is the ancestor of fctx present in ancestor manifest am, stopping after the first ancestor lower than limit""" @@ -158,6 +158,8 @@ path = f.path() if am.get(path, None) == f.filenode(): return path + if basemf and basemf.get(path, None) == f.filenode(): + return path if not f.isintroducedafter(limit): return None @@ -183,7 +185,7 @@ return (repo.ui.config('experimental', 'copies.read-from') in ('changeset-only', 'compatibility')) -def _committedforwardcopies(a, b, match): +def _committedforwardcopies(a, b, base, match): """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" # files might have to be traced back to the fctx parent of the last # one-side-only changeset, but not further back than that @@ -201,6 +203,7 @@ if debug: dbg('debug.copies: search limit: %d\n' % limit) am = a.manifest() + basemf = None if base is None else base.manifest() # find where new files came from # we currently don't try to find where old files went, too expensive @@ -232,7 +235,7 @@ if debug: start = util.timer() - opath = _tracefile(fctx, am, limit) + opath = _tracefile(fctx, am, basemf, limit) if opath: if debug: dbg('debug.copies: rename of: %s\n' % opath) @@ -311,17 +314,19 @@ heapq.heappush(work, (c, parent, newcopies)) assert False -def _forwardcopies(a, b, match=None): +def _forwardcopies(a, b, base=None, match=None): """find {dst@b: src@a} copy mapping where a is an ancestor of b""" + if base is None: + base = a match = a.repo().narrowmatch(match) # check for working copy if b.rev() is None: - cm = _committedforwardcopies(a, b.p1(), match) + cm = _committedforwardcopies(a, b.p1(), base, match) # combine copies from dirstate if necessary copies = _chain(cm, _dirstatecopies(b._repo, match)) else: - copies = _committedforwardcopies(a, b, match) + copies = _committedforwardcopies(a, b, base, match) return copies def _backwardrenames(a, b, match): @@ -369,8 +374,11 @@ else: if debug: repo.ui.debug('debug.copies: search mode: combined\n') + base = None + if a.rev() != node.nullrev: + base = x copies = _chain(_backwardrenames(x, a, match=match), - _forwardcopies(a, y, match=match)) + _forwardcopies(a, y, base, match=match)) _filter(x, y, copies) return copies diff --git a/tests/test-copies-unrelated.t b/tests/test-copies-unrelated.t --- a/tests/test-copies-unrelated.t +++ b/tests/test-copies-unrelated.t @@ -299,22 +299,10 @@ o 0 base a $ hg debugpathcopies 1 4 - x -> y (no-filelog !) -#if filelog -BROKEN: This should succeed and merge the changes from x into y - $ hg graft -r 2 - grafting 2:* "modify x" (glob) - file 'x' was deleted in local [local] but was modified in other [graft]. - What do you want to do? - use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u - abort: unresolved conflicts, can't continue - (use 'hg resolve' and 'hg graft --continue') - [255] -#else + x -> y $ hg graft -r 2 grafting 2:* "modify x" (glob) merging y and x to y -#endif $ hg co -qC 2 $ hg graft -r 4 grafting 4:* "rename x to y"* (glob)