[PATCH 5 of 5] graphlog: paths/-I/-X handling requires a new revset

Matt Mackall mpm at selenic.com
Fri Feb 24 13:12:27 CST 2012


On Fri, 2012-02-24 at 16:34 +0100, Patrick Mézard wrote:
> Le 24/02/12 00:12, Matt Mackall a écrit :
> > On Thu, 2012-02-23 at 18:10 +0100, Patrick Mezard wrote:
> >> # HG changeset patch
> >> # User Patrick Mezard <patrick at mezard.eu>
> >> # Date 1330016720 -3600
> >> # Node ID 5a627b49b4d94a627b6e990f07f7a5544e9376bf
> >> # Parent  1bfc7ba8b404b650bb360d36bd41c11a80d6f5ab
> >> graphlog: paths/-I/-X handling requires a new revset
> >>
> >> The filtering logic of match objects cannot be reproduced with the existing
> >> revsets as it operates at changeset files level. A changeset touching "a" and
> >> "b" is matched by "-I a -X b" but not by "file(a) and not file(b)".
> > 
> > Interesting.
> > 
> > The basic logic of include/exclude works like this (match.py:74):
> > 
> >             if include:
> >                 if exclude:
> >                     m = lambda f: im(f) and not em(f) and pm(f)
> > 
> > In English, a file matches if it's included AND not excluded AND matches
> > the base pattern (which might be "all files").
> > 
> > The next question is: how is this pattern matching applied to the set of
> > files in a changeset? The log code has this (cmdutil.py:1083):
> > 
> >         # The slow path checks files modified in every changeset.                                                                                                                                 
> >         for i in sorted(revs):
> >             ctx = change(i)
> >             matches = filter(match, ctx.files())
> >             if matches:
> >                 fncache[i] = matches
> >                 wanted.add(i)
> > 
> > ..which considers a changeset matching if ANY individual file matches. Which gives us three cases:
> > 
> >  -I files and -X files have no overlap -> equivalent to just -I (your original example)
> >  -I files and -X files overlap completely -> empty set
> >  -I files and -X files overlap partially -> complex!
> > 
> > But I think there's a relatively simple way to add a revset to deal with this:
> > 
> >  everyfile(pattern) -> match changesets where ALL files match pattern
> > 
> > So for a case like:
> > 
> >  hg log -I tests -X **.py
> > 
> > ..we get:
> > 
> >  hg log -r 'file(tests) and not everyfile("**.py")'
> > 
> > Cases:
> > 
> >   cset has tests/foo.t -> matches
> >   cset has tests/foo.t and tests/foo.py -> matches
> >   cset has test/foo.py -> doesn't match
> >   cset has tests/foo.t and other/foo.py -> matches
> > 
> > There's probably some way to show this is correct formally with
> > DeMorgan's rule, but I don't see an obvious notation.
> > 
> > Also note: multiple -I and -X patterns get ORed together, as do base
> > patterns, so a complex command like this:
> > 
> >  hg log p1 p2 -I i1 -I i2 -X x1 -X x2
> > 
> > becomes
> > 
> > (file(p1) or file(p2)) and (file(i1) or file(i2)) and not (everyfile(x1)
> > or everyfile(x2))
> 
> So "everyfile(rev, pattern)" is true if all elements of rev.files() are matched by pattern?
> 
> If "a" and "b" are changed in "rev":
> 
>   hg log -I b -X b
> 
> becomes:
> 
>   (file(b) and not everyfile(b))
> 
> and here everyfile(b) does not include "rev" since it does not match "a", so "rev" is returned.

Yep, you're right, that won't work.

-- 
Mathematics is the supreme nostalgia of our time.




More information about the Mercurial-devel mailing list