diff --git a/hgext/graphlog.py b/hgext/graphlog.py --- a/hgext/graphlog.py +++ b/hgext/graphlog.py @@ -303,8 +303,10 @@ def revset(repo, pats, opts): # pats/include/exclude cannot be represented as separate # revset expressions as their filtering logic applies at file # level. For instance "-I a -X a" matches a revision touching - # "a" and "b" while "file(a) and not file(b)" does not. - matchargs = [] + # "a" and "b" while "file(a) and not file(b)" does + # not. Besides, filesets are evaluated against the working + # directory. + matchargs = ['r:'] for p in pats: matchargs.append('p:' + p) for p in opts.get('include', []): diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -534,12 +534,16 @@ def _matchfiles(repo, subset, x): # # builds a match object from them and filters subset. Allowed # prefixes are 'p:' for regular patterns, 'i:' for include - # patterns and 'x:' for exclude patterns. + # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass + # a revision identifier, or the empty string to reference the + # working directory, from which the match object is + # initialized. At most one 'r:' argument can be passed. # i18n: "_matchfiles" is a keyword l = getargs(x, 1, -1, _("_matchfiles requires at least one argument")) pats, inc, exc = [], [], [] hasset = False + rev = None for arg in l: s = getstring(arg, _("_matchfiles requires string arguments")) prefix, value = s[:2], s[2:] @@ -549,6 +553,11 @@ def _matchfiles(repo, subset, x): inc.append(value) elif prefix == 'x:': exc.append(value) + elif prefix == 'r:': + if rev is not None: + raise error.ParseError(_('_matchfiles expected at most one ' + 'revision')) + rev = value else: raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix) if not hasset and matchmod.patkind(value) == 'set': @@ -557,9 +566,12 @@ def _matchfiles(repo, subset, x): s = [] for r in subset: c = repo[r] - if not m or hasset: + if not m or (hasset and rev is None): + ctx = c + if rev is not None: + ctx = repo[rev or None] m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc, - exclude=exc, ctx=c) + exclude=exc, ctx=ctx) for f in c.files(): if m(f): s.append(r) diff --git a/tests/test-glog.t b/tests/test-glog.t --- a/tests/test-glog.t +++ b/tests/test-glog.t @@ -1539,12 +1539,12 @@ have 2 filelog topological heads in a li Test falling back to slow path for non-existing files $ testlog a c - ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('string', 'p:a'), ('string', 'p:c'))))) + ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('string', 'r:'), ('string', 'p:a')), ('string', 'p:c'))))) Test multiple --include/--exclude/paths $ testlog --include a --include e --exclude b --exclude e a e - ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('list', ('list', ('list', ('string', 'p:a'), ('string', 'p:e')), ('string', 'i:a')), ('string', 'i:e')), ('string', 'x:b')), ('string', 'x:e'))))) + ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('list', ('list', ('list', ('list', ('string', 'r:'), ('string', 'p:a')), ('string', 'p:e')), ('string', 'i:a')), ('string', 'i:e')), ('string', 'x:b')), ('string', 'x:e'))))) Test glob expansion of pats @@ -1660,3 +1660,10 @@ Test --copies | o 0 add a copies: +Test "set:..." and parent revision + + $ hg up -q 4 + $ testlog --include "set:copied()" + ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('string', 'r:'), ('string', 'i:set:copied()'))))) + $ testlog -r "sort(file('set:copied()'), -rev)" + ('group', ('group', ('func', ('symbol', 'sort'), ('list', ('func', ('symbol', 'file'), ('string', 'set:copied()')), ('negate', ('symbol', 'rev'))))))