diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -295,7 +295,7 @@ def diff(self, ctx2=None, match=None, changes=None, opts=None, losedatafn=None, prefix='', relroot='', copy=None, - hunksfilterfn=None): + copysourcematch=None, hunksfilterfn=None): """Returns a diff generator for the given contexts and matcher""" if ctx2 is None: ctx2 = self.p1() @@ -304,6 +304,7 @@ return patch.diff(self._repo, ctx2, self, match=match, changes=changes, opts=opts, losedatafn=losedatafn, prefix=prefix, relroot=relroot, copy=copy, + copysourcematch=copysourcematch, hunksfilterfn=hunksfilterfn) def dirs(self): diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py --- a/mercurial/logcmdutil.py +++ b/mercurial/logcmdutil.py @@ -64,6 +64,7 @@ relroot = pathutil.canonpath(repo.root, repo.getcwd(), root) else: relroot = '' + copysourcematch = None if relroot != '': # XXX relative roots currently don't work if the root is within a # subrepo @@ -76,6 +77,7 @@ relrootmatch = scmutil.match(ctx2, pats=[relroot], default='path') match = matchmod.intersectmatchers(match, relrootmatch) + copysourcematch = relrootmatch if stat: diffopts = diffopts.copy(context=0, noprefix=False) @@ -84,7 +86,8 @@ width = ui.termwidth() - graphwidth chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, prefix=prefix, - relroot=relroot, hunksfilterfn=hunksfilterfn) + relroot=relroot, copysourcematch=copysourcematch, + hunksfilterfn=hunksfilterfn) if fp is not None or ui.canwritewithoutlabels(): out = fp or ui diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -2240,7 +2240,7 @@ def diff(repo, node1=None, node2=None, match=None, changes=None, opts=None, losedatafn=None, prefix='', relroot='', copy=None, - hunksfilterfn=None): + copysourcematch=None, hunksfilterfn=None): '''yields diff of changes to files between two nodes, or node and working directory. @@ -2264,6 +2264,9 @@ copy, if not empty, should contain mappings {dst@y: src@x} of copy information. + if copysourcematch is not None, then copy sources will be filtered by this + matcher + hunksfilterfn, if not None, should be a function taking a filectx and hunks generator that may yield filtered hunks. ''' @@ -2277,7 +2280,7 @@ repo, ctx1=ctx1, ctx2=ctx2, match=match, changes=changes, opts=opts, losedatafn=losedatafn, prefix=prefix, relroot=relroot, copy=copy, - ): + copysourcematch=copysourcematch): if hunksfilterfn is not None: # If the file has been removed, fctx2 is None; but this should # not occur here since we catch removed files early in @@ -2292,7 +2295,8 @@ yield text def diffhunks(repo, ctx1, ctx2, match=None, changes=None, - opts=None, losedatafn=None, prefix='', relroot='', copy=None): + opts=None, losedatafn=None, prefix='', relroot='', copy=None, + copysourcematch=None): """Yield diff of changes to files in the form of (`header`, `hunks`) tuples where `header` is a list of diff headers and `hunks` is an iterable of (`hunkrange`, `hunklines`) tuples. @@ -2337,11 +2341,11 @@ if opts.git or opts.upgrade: copy = copies.pathcopies(ctx1, ctx2, match=match) - if relroot: - # filter out copies where source side isn't inside the relative root + if copysourcematch: + # filter out copies where source side isn't inside the matcher # (copies.pathcopies() already filtered out the destination) copy = {dst: src for dst, src in copy.iteritems() - if src.startswith(relroot)} + if copysourcematch(src)} modifiedset = set(modified) addedset = set(added)