diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -149,6 +149,22 @@ def rawsmartset(repo, subset, x, order): return x & subset +def raw_node_set(repo, subset, x, order): + """argument is a list of nodeid, resolve and use them""" + nodes = _ordered_node_set(repo, x) + if order == followorder: + return subset & nodes + else: + return nodes & subset + + +def _ordered_node_set(repo, nodes): + if not nodes: + return baseset() + to_rev = repo.changelog.index.rev + return baseset([to_rev(r) for r in nodes]) + + def rangeset(repo, subset, x, y, order): m = getset(repo, fullreposet(repo), x) n = getset(repo, fullreposet(repo), y) @@ -2772,6 +2788,7 @@ methods = { b"parent": parentspec, b"parentpost": parentpost, b"smartset": rawsmartset, + b"nodeset": raw_node_set, } relations = { diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py --- a/mercurial/revsetlang.py +++ b/mercurial/revsetlang.py @@ -392,7 +392,7 @@ def _analyze(x): elif op == b'negate': s = getstring(x[1], _(b"can't negate that")) return _analyze((b'string', b'-' + s)) - elif op in (b'string', b'symbol', b'smartset'): + elif op in (b'string', b'symbol', b'smartset', b'nodeset'): return x elif op == b'rangeall': return (op, None) @@ -441,8 +441,9 @@ def _optimize(x): return 0, x op = x[0] - if op in (b'string', b'symbol', b'smartset'): - return 0.5, x # single revisions are small + if op in (b'string', b'symbol', b'smartset', b'nodeset'): + # single revisions are small, and set of already computed revision are assumed to be cheap. + return 0.5, x elif op == b'and': wa, ta = _optimize(x[1]) wb, tb = _optimize(x[2]) @@ -784,6 +785,8 @@ def formatspec(expr, *args): if isinstance(arg, set): arg = sorted(arg) ret.append(_formatintlist(list(arg))) + elif t == b'nodeset': + ret.append(_formatlistexp(list(arg), b"n")) else: raise error.ProgrammingError(b"unknown revspec item type: %r" % t) return b''.join(ret) @@ -801,6 +804,10 @@ def spectree(expr, *args): newtree = (b'smartset', smartset.baseset(arg)) inputs.append(newtree) ret.append(b"$") + elif t == b'nodeset': + newtree = (b'nodeset', arg) + inputs.append(newtree) + ret.append(b"$") else: raise error.ProgrammingError(b"unknown revspec item type: %r" % t) expr = b''.join(ret) @@ -863,6 +870,12 @@ def _parseargs(expr, args): ret.append((b'baseset', arg)) pos += 1 continue + elif islist and d == b'n' and arg: + # we cannot turn the node into revision yet, but not + # serializing them will same a lot of time for large set. + ret.append((b'nodeset', arg)) + pos += 1 + continue try: ret.append((None, f(list(arg), d))) except (TypeError, ValueError):