[PATCH] revset: add 'only' revset

Augie Fackler raf at durin42.com
Fri Feb 28 11:29:03 CST 2014


On Wed, Feb 26, 2014 at 11:35:14AM -0800, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham at fb.com>
> # Date 1384621028 28800
> #      Sat Nov 16 08:57:08 2013 -0800
> # Node ID 9bcbd10a93137b4dbc83bebd41fb4f00143a7615
> # Parent  0ad353831461516132f57ccda8e8e0515213ec60
> revset: add 'only' revset

Not crazy about the name, but seems reasonable.

I had to think about this for a /long/ time to figure out that it's
not ancestors(<set>). Can you figure out some clearer descriptions of
this operator?

>
> Adds a only() revset that has two forms:
>
> only(<set>) is equivalent to "::<set> - ::(heads() - heads(<set>::))"
>
> only(<include>,<exclude>) is equivalent to "::<include> - ::<exclude>"
>
> On a large repo, this implementation can process/traverse 50,000 revs in 0.7
> seconds, versus 4.2 seconds using "::<include> - ::<exclude>".

Hm. I wonder if we could do something to make - smarter so that it
could auto-optimize that case? Probably too ambitious.


>
> This is useful for performing histedits on your branch:
> hg histedit -r 'first(only(.))'
>
> Or lifting branch foo off of branch bar:
> hg rebase -d @ -s 'only(foo, bar)'
>
> Or a variety of other uses.
>
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -9,6 +9,7 @@
>  import parser, util, error, discovery, hbisect, phases
>  import node
>  import match as matchmod
> +import ancestor as ancestormod
>  from i18n import _
>  import encoding
>  import obsolete as obsmod
> @@ -351,6 +352,25 @@
>      kind, pattern, matcher = _substringmatcher(n)
>      return lazyset(subset, lambda x: matcher(encoding.lower(repo[x].user())))
>
> +def only(repo, subset, x):
> +    """``only(set, [set])
> +    Changesets that are only ancestors of the first set, but not the second.
> +    If no second set is specified, it is assumed to be the heads that are
> +    not in or descendants of the first set.
> +    """
> +    cl = repo.changelog
> +    args = getargs(x, 1, 2, _('only takes one or two arguments'))
> +    include = set(getset(repo, baseset(cl), args[0]))
> +    if len(args) == 1:
> +        descendants = set(_revdescendants(repo, include, False))
> +        exclude = [rev for rev in cl.headrevs()
> +            if not rev in descendants and not rev in include]
> +    else:
> +        exclude = getset(repo, baseset(cl), args[1])
> +
> +    results = set(ancestormod.missingancestors(include, exclude, cl.parentrevs))
> +    return lazyset(subset, lambda x: x in results)
> +
>  def bisect(repo, subset, x):
>      """``bisect(string)``
>      Changesets marked in the specified bisect status:
> @@ -1587,6 +1607,7 @@
>      "ancestors": ancestors,
>      "_firstancestors": _firstancestors,
>      "author": author,
> +    "only": only,
>      "bisect": bisect,
>      "bisected": bisected,
>      "bookmark": bookmark,
> diff --git a/tests/test-revset.t b/tests/test-revset.t
> --- a/tests/test-revset.t
> +++ b/tests/test-revset.t
> @@ -367,6 +367,22 @@
>    4
>    $ log 'id(5)'
>    2
> +  $ log 'only(9)'
> +  8
> +  9
> +  $ log 'only(8)'
> +  8
> +  $ log 'only(9, 5)'
> +  2
> +  4
> +  8
> +  9
> +  $ log 'only(7 + 9, 5 + 2)'
> +  4
> +  6
> +  7
> +  8
> +  9
>    $ log 'outgoing()'
>    8
>    9
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list