Patchwork [V2] revset: add 'only' revset

login
register
mail settings
Submitter Durham Goode
Date Feb. 28, 2014, 10:40 p.m.
Message ID <4cafddd6e1e13f4215a0.1393627254@dev010.prn1.facebook.com>
Download mbox | patch
Permalink /patch/3808/
State Accepted
Commit 10433163bf5768cddac7f36ad39244282710e786
Headers show

Comments

Durham Goode - Feb. 28, 2014, 10:40 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1384621028 28800
#      Sat Nov 16 08:57:08 2013 -0800
# Node ID 4cafddd6e1e13f4215a0e6711e9568f5933f62b3
# Parent  60c308b932ebd8a77f497ae285774fdced382eee
revset: add 'only' revset

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>".

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.
Matt Mackall - Feb. 28, 2014, 10:50 p.m.
On Fri, 2014-02-28 at 14:40 -0800, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham@fb.com>
> # Date 1384621028 28800
> #      Sat Nov 16 08:57:08 2013 -0800
> # Node ID 4cafddd6e1e13f4215a0e6711e9568f5933f62b3
> # Parent  60c308b932ebd8a77f497ae285774fdced382eee
> revset: add 'only' revset

Queued for default, thanks.

Perhaps you can add some examples to the rebase and histedit help?

> hg histedit -r 'first(only(.))'

Why does histedit need first? Can we fix that?
Sean Farley - Feb. 28, 2014, 10:58 p.m.
Matt Mackall <mpm@selenic.com> writes:

> On Fri, 2014-02-28 at 14:40 -0800, Durham Goode wrote:
>> # HG changeset patch
>> # User Durham Goode <durham@fb.com>
>> # Date 1384621028 28800
>> #      Sat Nov 16 08:57:08 2013 -0800
>> # Node ID 4cafddd6e1e13f4215a0e6711e9568f5933f62b3
>> # Parent  60c308b932ebd8a77f497ae285774fdced382eee
>> revset: add 'only' revset
>
> Queued for default, thanks.
>
> Perhaps you can add some examples to the rebase and histedit help?
>
>> hg histedit -r 'first(only(.))'
>
> Why does histedit need first? Can we fix that?

hisedit needs the first ancestor that you want to edit ... unless you're
suggesting always edit the entire branch?

What about a name of 'branchlet'? Too confusing?
Matt Mackall - Feb. 28, 2014, 11:10 p.m.
On Fri, 2014-02-28 at 16:58 -0600, Sean Farley wrote:
> Matt Mackall <mpm@selenic.com> writes:
> 
> > On Fri, 2014-02-28 at 14:40 -0800, Durham Goode wrote:
> >> # HG changeset patch
> >> # User Durham Goode <durham@fb.com>
> >> # Date 1384621028 28800
> >> #      Sat Nov 16 08:57:08 2013 -0800
> >> # Node ID 4cafddd6e1e13f4215a0e6711e9568f5933f62b3
> >> # Parent  60c308b932ebd8a77f497ae285774fdced382eee
> >> revset: add 'only' revset
> >
> > Queued for default, thanks.
> >
> > Perhaps you can add some examples to the rebase and histedit help?
> >
> >> hg histedit -r 'first(only(.))'
> >
> > Why does histedit need first? Can we fix that?
> 
> hisedit needs the first ancestor that you want to edit ... unless you're
> suggesting always edit the entire branch?

Ok. But if I give the first part of the branch and its (linear)
descendants, can we teach histedit not to complain? Then first() won't
be needed.
Sean Farley - Feb. 28, 2014, 11:17 p.m.
Matt Mackall <mpm@selenic.com> writes:

> On Fri, 2014-02-28 at 16:58 -0600, Sean Farley wrote:
>> Matt Mackall <mpm@selenic.com> writes:
>> 
>> > On Fri, 2014-02-28 at 14:40 -0800, Durham Goode wrote:
>> >> # HG changeset patch
>> >> # User Durham Goode <durham@fb.com>
>> >> # Date 1384621028 28800
>> >> #      Sat Nov 16 08:57:08 2013 -0800
>> >> # Node ID 4cafddd6e1e13f4215a0e6711e9568f5933f62b3
>> >> # Parent  60c308b932ebd8a77f497ae285774fdced382eee
>> >> revset: add 'only' revset
>> >
>> > Queued for default, thanks.
>> >
>> > Perhaps you can add some examples to the rebase and histedit help?
>> >
>> >> hg histedit -r 'first(only(.))'
>> >
>> > Why does histedit need first? Can we fix that?
>> 
>> hisedit needs the first ancestor that you want to edit ... unless you're
>> suggesting always edit the entire branch?
>
> Ok. But if I give the first part of the branch and its (linear)
> descendants, can we teach histedit not to complain? Then first() won't
> be needed.

Ugh. I misread 'only(.)' to mean 'only this commit' ... yes, I agree
with teaching histedit about linear descendants.

Patch

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,26 @@ 
     kind, pattern, matcher = _substringmatcher(n)
     return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
 
+def only(repo, subset, x):
+    """``only(set, [set])``
+    Changesets that are ancestors of the first set that are not ancestors
+    of any other head in the repo. If a second set is specified, the result
+    is ancestors of the first set that are not ancestors of the second set
+    (i.e. ::<set1> - ::<set2>).
+    """
+    cl = repo.changelog
+    args = getargs(x, 1, 2, _('only takes one or two arguments'))
+    include = getset(repo, spanset(repo), args[0]).set()
+    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, spanset(repo), 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:
@@ -1606,6 +1627,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