# HG changeset patch # User Durham Goode # Date 2013-11-16 16:57:08 # Node ID 10433163bf5768cddac7f36ad39244282710e786 # Parent 60c308b932ebd8a77f497ae285774fdced382eee revset: add 'only' revset Adds a only() revset that has two forms: only() is equivalent to ":: - ::(heads() - heads(::))" only(,) is equivalent to ":: - ::" On a large repo, this implementation can process/traverse 50,000 revs in 0.7 seconds, versus 4.2 seconds using ":: - ::". 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 re 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 @@ def author(repo, subset, x): 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. :: - ::). + """ + 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 @@ symbols = { "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 @@ ancestor can accept 0 or more arguments 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