comparison mercurial/revset.py @ 33377:5d63e5f40bea

revset: define successors revset This revset returns all successors, including transit nodes and the source nodes (to be consistent with existing revsets like "ancestors"). To filter out transit nodes, use `successors(X)-obsolete()`. To filter out divergent case, use `successors(X)-divergent()-obsolete()`. The revset could be useful to define rebase destination, like: `max(successors(BASE)-divergent()-obsolete())`. The `max` is to deal with splits. There are other implementations where `successors` returns just one level of successors, and `allsuccessors` returns everything. I think `successors` returning all successors by default is more user friendly. We have seen cases in production where people use 1-level `successors` while they really want `allsuccessors`. So it seems better to just have one single revset returning all successors by default to avoid user errors. In the future we might want to add `depth` keyword argument to it and for other revsets like `ancestors` etc. Or even build some flexible indexing syntax [1] to satisfy people having the depth limit requirement. [1]: https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-July/101140.html
author Jun Wu <quark@fb.com>
date Mon, 10 Jul 2017 10:56:40 -0700
parents 4672db164c98
children 9467d5337292
comparison
equal deleted inserted replaced
33376:d5a38eae67e5 33377:5d63e5f40bea
17 error, 17 error,
18 hbisect, 18 hbisect,
19 match as matchmod, 19 match as matchmod,
20 node, 20 node,
21 obsolete as obsmod, 21 obsolete as obsmod,
22 obsutil,
22 pathutil, 23 pathutil,
23 phases, 24 phases,
24 registrar, 25 registrar,
25 repoview, 26 repoview,
26 revsetlang, 27 revsetlang,
1824 1825
1825 return False 1826 return False
1826 1827
1827 return subset.filter(matches, condrepr=('<subrepo %r>', pat)) 1828 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
1828 1829
1830 def _mapbynodefunc(repo, s, f):
1831 """(repo, smartset, [node] -> [node]) -> smartset
1832
1833 Helper method to map a smartset to another smartset given a function only
1834 talking about nodes. Handles converting between rev numbers and nodes, and
1835 filtering.
1836 """
1837 cl = repo.unfiltered().changelog
1838 torev = cl.rev
1839 tonode = cl.node
1840 nodemap = cl.nodemap
1841 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
1842 return smartset.baseset(result - repo.changelog.filteredrevs)
1843
1844 @predicate('successors(set)', safe=True)
1845 def successors(repo, subset, x):
1846 """All successors for set, including the given set themselves"""
1847 s = getset(repo, fullreposet(repo), x)
1848 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
1849 d = _mapbynodefunc(repo, s, f)
1850 return subset & d
1851
1829 def _substringmatcher(pattern, casesensitive=True): 1852 def _substringmatcher(pattern, casesensitive=True):
1830 kind, pattern, matcher = util.stringmatcher(pattern, 1853 kind, pattern, matcher = util.stringmatcher(pattern,
1831 casesensitive=casesensitive) 1854 casesensitive=casesensitive)
1832 if kind == 'literal': 1855 if kind == 'literal':
1833 if not casesensitive: 1856 if not casesensitive: