Please check out the revset feature

7 views
Skip to first unread message

Matt Mackall

unread,
Jun 7, 2010, 12:16:19 PM6/7/10
to mercurial-devel
Last week I pushed the revset feature to default. It's available
wherever revision ranges were previously supported. It's quite complex
and needs some testing. (And yes, there are currently no tests or docs!)

Some sample queries:

hg log -r 'branch(default)'
hg log -r 'branch(default) and 1.5:: and not merge()'
hg log -r '1.3::1.5 and keyword(bug) and file("hgext/*")'
hg log -r 'sort(date("May 2008"), user)'
hg log -r '(keyword(bug) or keyword(issue)) and not ancestors(tagged())'

grammar:

expr :=
( expr )
expr infix expr
prefix expr
expr postfix
identifier
"identifier"
function ( expr )

prefix operators:
not x / ! x
:x all revisions <= x
::x ancestors of x

postfix operators:
x:: descendants of x
x: revisions >= x

infix operators:
symbol(expression)
x::y / x..y dag range
x:y existing range operator
not x
x and y / x & y
x or y / x | y / x + y
x - y -> x & !y
x,y -> argument list

function-style filters:
adds(pattern)
all() -> 0:tip
ancestor(single, single)
ancestors(set)
author(string) alias for user
branch(set)
children(set)
closed() -> changeset is closed
contains(patterns) -> revision contains pattern
date(daterange)
descendants(set)
file(pattern)
follow() -> ::.
grep(regex) like keyword but with regex
head() -> changeset is a heads
heads(set) -> members of set with no children in set
keyword(string)
limit(set, n) -> first n members of set
max(set) -> highest revision in set
merge() -> cset is a merge
modifies(pattern)
outgoing([path])
p1(set)
p2(set)
parents(set)
removes(pattern)
reverse(set)
roots(set)
sort(set[, spec])
tagged() changeset is tagged
user(string)

Command line equivalents:

-f -> ::.
-d -> date(x)
-k -> keyword(x)
-m -> merge()
-u -> user(x)
-b -> branch(x)
-P -> !::x
-l -> limit(expr, x)


--
Mathematics is the supreme nostalgia of our time.


_______________________________________________
Mercurial-devel mailing list
Mercuri...@selenic.com
http://selenic.com/mailman/listinfo/mercurial-devel

Cedric Duval

unread,
Jun 7, 2010, 4:34:27 PM6/7/10
to mercuri...@selenic.com
Matt Mackall wrote:
> Last week I pushed the revset feature to default. It's available
> wherever revision ranges were previously supported. It's quite complex
> and needs some testing. (And yes, there are currently no tests or docs!)

> Some sample queries:

> hg log -r 'branch(default)'
> hg log -r 'branch(default) and 1.5:: and not merge()'
> hg log -r '1.3::1.5 and keyword(bug) and file("hgext/*")'
> hg log -r 'sort(date("May 2008"), user)'
> hg log -r '(keyword(bug) or keyword(issue)) and not ancestors(tagged())'

Very nice!

Giving it a try, I stumbled upon an issue while ending a specification
with '1.5::'. Something along the lines of the following patch might help.

# HG changeset patch
# User Cédric Duval <cedri...@free.fr>
# Date 1275942295 -7200
# Node ID 1dcf7d358d91d828ded364d7fc8b47f6a86c6de1
# Parent 3d0591a661189bcb0a5e8ef3393c59ecd7e42f79
cmdutil: fix range determination when using a DAG separator

revset must be used with open DAG range specifications, otherwise
requesting eg. 'tag::' causes a range lookup between "tag" and ":",
which triggers an abandon.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -13,6 +13,7 @@
import similar, revset

revrangesep = ':'
+dagrevrangesep = '::'

def parsealiases(cmd):
return cmd.lstrip("^").split("|")
@@ -149,8 +150,9 @@

seen, l = set(), []
for spec in revs:
- if spec and not (
- spec.startswith(revrangesep) or spec.endswith(revrangesep)):
+ if spec and (
+ spec.startswith(dagrevrangesep) or spec.endswith(dagrevrangesep) or
+ not (spec.startswith(revrangesep) or spec.endswith(revrangesep))):
m = revset.match(spec)
for r in m(repo, range(len(repo))):
if r not in seen:

Peter Arrenbrecht

unread,
Jun 8, 2010, 9:06:44 AM6/8/10
to Matt Mackall, mercurial-devel
On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
> Last week I pushed the revset feature to default. It's available
> wherever revision ranges were previously supported. It's quite complex
> and needs some testing. (And yes, there are currently no tests or docs!)
> ...

>  x - y  -> x & !y

This seems to break branch names with dashes in them, as in:

hg glog --rev p-root:tip

-parren

Peter Arrenbrecht

unread,
Jun 8, 2010, 9:23:46 AM6/8/10
to Matt Mackall, mercurial-devel
On Tue, Jun 8, 2010 at 3:06 PM, Peter Arrenbrecht
<peter.ar...@gmail.com> wrote:
> On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
>> Last week I pushed the revset feature to default. It's available
>> wherever revision ranges were previously supported. It's quite complex
>> and needs some testing. (And yes, there are currently no tests or docs!)
>> ...
>>  x - y  -> x & !y
>
> This seems to break branch names with dashes in them, as in:
>
>  hg glog --rev p-root:tip

I wonder if the following diff suggests that this will not be treated
as a regression.

$ hg diff -c e581f3ac tests
diff --git a/tests/test-bookmarks b/tests/test-bookmarks
--- a/tests/test-bookmarks
+++ b/tests/test-bookmarks
@@ -82,7 +82,7 @@
hg bookmarks

echo % look up stripped bookmark name
-hg log -r 'x y'
+hg log -r '"x y"'

echo % reject bookmark name with newline
hg bookmark '

Peter Arrenbrecht

unread,
Jun 8, 2010, 9:45:07 AM6/8/10
to Matt Mackall, mercurial-devel
On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
> Last week I pushed the revset feature to default. It's available
> wherever revision ranges were previously supported. It's quite complex
> and needs some testing. (And yes, there are currently no tests or docs!)

$ hg debugrevspec 'contains())'
** unknown exception encountered, details follow
** report bug details to http://mercurial.selenic.com/bts/
** or merc...@selenic.com
** Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) [GCC 4.4.3]
** Mercurial Distributed SCM (version 1.5.1+50-3f30190781a3+20100409)
** Extensions loaded:
Traceback (most recent call last):
File "./hg", line 27, in <module>
mercurial.dispatch.run()
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 16, in run
sys.exit(dispatch(sys.argv[1:]))
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 34, in dispatch
return _runcatch(u, args)
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 54, in _runcatch
return _dispatch(ui, args)
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 480, in _dispatch
return runcommand(lui, repo, cmd, fullargs, ui, options, d)
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 350, in
runcommand
ret = _runcommand(ui, options, cmd, d)
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 531, in
_runcommand
return checkargs()
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 485, in checkargs
return cmdfunc()
File "/home/peo/dev/hg/dev-crew/mercurial/dispatch.py", line 479, in <lambda>
d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
File "/home/peo/dev/hg/dev-crew/mercurial/util.py", line 408, in check
return func(*args, **kwargs)
File "/home/peo/dev/hg/dev-crew/mercurial/commands.py", line 945, in
debugrevspec
for c in func(repo, range(len(repo))):
File "/home/peo/dev/hg/dev-crew/mercurial/revset.py", line 553, in mfunc
return getset(repo, subset, tree)
File "/home/peo/dev/hg/dev-crew/mercurial/revset.py", line 109, in getset
return methods[x[0]](repo, subset, *x[1:])
File "/home/peo/dev/hg/dev-crew/mercurial/revset.py", line 154, in func
return symbols[a[1]](repo, subset, b)
File "/home/peo/dev/hg/dev-crew/mercurial/revset.py", line 281, in contains
pat = getstring(x, "file wants a pattern")
File "/home/peo/dev/hg/dev-crew/mercurial/revset.py", line 89, in getstring
if x[0] == 'string' or x[0] == 'symbol':
TypeError: 'NoneType' object is unsubscriptable

Peter Arrenbrecht

unread,
Jun 8, 2010, 10:00:27 AM6/8/10
to Matt Mackall, mercurial-devel
On Tue, Jun 8, 2010 at 3:23 PM, Peter Arrenbrecht

<peter.ar...@gmail.com> wrote:
> On Tue, Jun 8, 2010 at 3:06 PM, Peter Arrenbrecht
> <peter.ar...@gmail.com> wrote:
>> On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
>>> Last week I pushed the revset feature to default. It's available
>>> wherever revision ranges were previously supported. It's quite complex
>>> and needs some testing. (And yes, there are currently no tests or docs!)
>>> ...
>>>  x - y  -> x & !y
>>
>> This seems to break branch names with dashes in them, as in:
>>
>>  hg glog --rev p-root:tip
>
> I wonder if the following diff suggests that this will not be treated
> as a regression.
>
> $ hg diff -c e581f3ac tests
> diff --git a/tests/test-bookmarks b/tests/test-bookmarks
> --- a/tests/test-bookmarks
> +++ b/tests/test-bookmarks
> @@ -82,7 +82,7 @@
>  hg bookmarks
>
>  echo % look up stripped bookmark name
> -hg log -r 'x  y'
> +hg log -r '"x  y"'
>
>  echo % reject bookmark name with newline
>  hg bookmark '

Just chatted with hstuart a bit. Ideas:

* Require spaces around operators.

* Make 'with-dash' first look up the name "with-dash". If there is no
such name, fall back on the expression 'with - dash'. To be on the
safe side, one could use spaces to force ' - ' to be an operator.

* Accept this as changed behaviour, but at least explicitly specify _
to never become an operator.

Peter Arrenbrecht

unread,
Jun 8, 2010, 10:35:25 AM6/8/10
to Matt Mackall, Henrik Stuart, Benoit Boissinot, mercurial-devel
On Tue, Jun 8, 2010 at 4:00 PM, Peter Arrenbrecht

More ideas:

* Require a prefix to introduce revspecs. This could either be a
prefix that forces people to quote in bash so they get into the habit
to avoid surprises later. Suggestion is # so if people forget to
bash-quote no harm's done:

hg log -r '#tagged()'

or else something not requiring bash-quoting like surrounding /.../:

hg log -r /a..b/
hg log -r /a-b/
hg log -r my-branch

This would still trip up people with leading slashes in their branch names.

* Supporting quoting names using /.../, so we avoid the double
quoting needed in bash for "...". Optionally we could support omitting
the trailing /:

hg log -r /my-branch/
hg log -r /my-branch
hg log -r a..b
hg log -r a-b

Matt Mackall

unread,
Jun 8, 2010, 11:09:09 AM6/8/10
to Peter Arrenbrecht, mercurial-devel
On Tue, Jun 08, 2010 at 04:00:27PM +0200, Peter Arrenbrecht wrote:
> On Tue, Jun 8, 2010 at 3:23 PM, Peter Arrenbrecht
> <peter.ar...@gmail.com> wrote:
> > On Tue, Jun 8, 2010 at 3:06 PM, Peter Arrenbrecht
> > <peter.ar...@gmail.com> wrote:
> >> On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
> >>> Last week I pushed the revset feature to default. It's available
> >>> wherever revision ranges were previously supported. It's quite complex
> >>> and needs some testing. (And yes, there are currently no tests or docs!)
> >>> ...
> >>> ?x - y ?-> x & !y

> >>
> >> This seems to break branch names with dashes in them, as in:
> >>
> >> ?hg glog --rev p-root:tip

> >
> > I wonder if the following diff suggests that this will not be treated
> > as a regression.
> >
> > $ hg diff -c e581f3ac tests
> > diff --git a/tests/test-bookmarks b/tests/test-bookmarks
> > --- a/tests/test-bookmarks
> > +++ b/tests/test-bookmarks
> > @@ -82,7 +82,7 @@
> > ?hg bookmarks
> >
> > ?echo % look up stripped bookmark name
> > -hg log -r 'x ?y'
> > +hg log -r '"x ?y"'
> >
> > ?echo % reject bookmark name with newline
> > ?hg bookmark '

>
> Just chatted with hstuart a bit. Ideas:
>
> * Require spaces around operators.

We could, but for operators like ':,(!', that's not really what you want.

> * Make 'with-dash' first look up the name "with-dash". If there is no
> such name, fall back on the expression 'with - dash'. To be on the
> safe side, one could use spaces to force ' - ' to be an operator.

Horrors. x - y is just shorthand for "x and not y", so the simplest answer is
to just drop it.

Here are the characters that when included in a specifier will
effectively make it a query:

essential: space ( ) " ' , :
convenience: ! & | - + ..

Of these, I think - and + are both pretty problematic but I'm not too
worried about the others. So we either need to drop some of the
convenience operators or mark queries specially.

In the past, ranges have been detected by the presence of a :, which
is why : is banned in tag names. We could for instance mark queries
like this:

hg log -r '?1.5::'

but it's a little unfortunate that this cuts us off from simply typing

hg log -r 1.5::

On the other hand, these simple :: expressions are about all you can
type without needing shell quoting.

Alternately, we could make the query test something hairy like:

if ':' in x or ' ' in x or '(' in x:

but that just seems to present weird corner cases like:

hg log -r 'tip&default'

The subspace of useful expressions without '( :' is pretty small but
it isn't quite empty.

Also, right now the parser insists that any identifier not matching
[a-z09._]+ be in quotes. Quoting allows any identifier to be
specified. This ought to be made a bit more liberal.

> * Accept this as changed behaviour, but at least explicitly specify _
> to never become an operator.

On reflection, I think the current approach is too aggressive.

--
Mathematics is the supreme nostalgia of our time.

Greg Ward

unread,
Jun 8, 2010, 3:45:53 PM6/8/10
to Matt Mackall, mercurial-devel
On Mon, Jun 7, 2010 at 12:16 PM, Matt Mackall <m...@selenic.com> wrote:
> Last week I pushed the revset feature to default. It's available
> wherever revision ranges were previously supported. It's quite complex
> and needs some testing. (And yes, there are currently no tests or docs!)

Cool! This is a killer feature.

I just naively tried to do this:

hg update 'p1(109360)'

which was rejected: presumably update doesn't accept revsets at all,
since it's nonsensical in general. But there are certainly useful
revsets with only one member. Would it be possible to make update
accept a query that evaluates to exactly one changeset, and barf
otherwise?

Greg

Matt Mackall

unread,
Jun 8, 2010, 3:49:11 PM6/8/10
to Greg Ward, mercurial-devel
On Tue, 2010-06-08 at 15:45 -0400, Greg Ward wrote:
> On Mon, Jun 7, 2010 at 12:16 PM, Matt Mackall <m...@selenic.com> wrote:
> > Last week I pushed the revset feature to default. It's available
> > wherever revision ranges were previously supported. It's quite complex
> > and needs some testing. (And yes, there are currently no tests or docs!)
>
> Cool! This is a killer feature.
>
> I just naively tried to do this:
>
> hg update 'p1(109360)'
>
> which was rejected: presumably update doesn't accept revsets at all,
> since it's nonsensical in general. But there are certainly useful
> revsets with only one member. Would it be possible to make update
> accept a query that evaluates to exactly one changeset, and barf
> otherwise?

Yes. Haven't gotten there yet though.

--
Mathematics is the supreme nostalgia of our time.

Matt Mackall

unread,
Jun 8, 2010, 6:20:22 PM6/8/10
to peter.ar...@gmail.com, mercurial-devel
On Tue, 2010-06-08 at 15:45 +0200, Peter Arrenbrecht wrote:
> On Mon, Jun 7, 2010 at 6:16 PM, Matt Mackall <m...@selenic.com> wrote:
> > Last week I pushed the revset feature to default. It's available
> > wherever revision ranges were previously supported. It's quite complex
> > and needs some testing. (And yes, there are currently no tests or docs!)
>
> $ hg debugrevspec 'contains())'

This is actually tripping over the lack of arguments to contains and not
the extra paren.

--
Mathematics is the supreme nostalgia of our time.

Reply all
Reply to author
Forward
0 new messages