Mercurial > public > mercurial-scm > hg
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: |