comparison mercurial/revset.py @ 31938:5e3b49defbff

revset: add a 'descend' argument to followlines to return descendants This is useful to follow changes in a block of lines forward in the history (for instance, when one wants to find out how a function evolved from a point in history). We added a 'descend' parameter to followlines(), which defaults to False. If True, followlines() returns descendants of startrev. Because context.blockdescendants() does not follow renames, these are not followed by the revset either, so history will end when a rename occurs (as can be seen in tests).
author Denis Laxalde <denis.laxalde@logilab.fr>
date Mon, 16 Jan 2017 09:24:47 +0100
parents 81abd0d12c86
children 83527d9f1f13
comparison
equal deleted inserted replaced
31937:826e600605f6 31938:5e3b49defbff
899 # ``followfirst([pattern[, startrev]])`` 899 # ``followfirst([pattern[, startrev]])``
900 # Like ``follow([pattern[, startrev]])`` but follows only the first parent 900 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
901 # of every revisions or files revisions. 901 # of every revisions or files revisions.
902 return _follow(repo, subset, x, '_followfirst', followfirst=True) 902 return _follow(repo, subset, x, '_followfirst', followfirst=True)
903 903
904 @predicate('followlines(file, fromline:toline[, startrev=.])', safe=True) 904 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
905 safe=True)
905 def followlines(repo, subset, x): 906 def followlines(repo, subset, x):
906 """Changesets modifying `file` in line range ('fromline', 'toline'). 907 """Changesets modifying `file` in line range ('fromline', 'toline').
907 908
908 Line range corresponds to 'file' content at 'startrev' and should hence be 909 Line range corresponds to 'file' content at 'startrev' and should hence be
909 consistent with file size. If startrev is not specified, working directory's 910 consistent with file size. If startrev is not specified, working directory's
910 parent is used. 911 parent is used.
912
913 By default, ancestors of 'startrev' are returned. If 'descend' is True,
914 descendants of 'startrev' are returned though renames are (currently) not
915 followed in this direction.
911 """ 916 """
912 from . import context # avoid circular import issues 917 from . import context # avoid circular import issues
913 918
914 args = getargsdict(x, 'followlines', 'file *lines startrev') 919 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
915 if len(args['lines']) != 1: 920 if len(args['lines']) != 1:
916 raise error.ParseError(_("followlines requires a line range")) 921 raise error.ParseError(_("followlines requires a line range"))
917 922
918 rev = '.' 923 rev = '.'
919 if 'startrev' in args: 924 if 'startrev' in args:
937 fromline, toline = [getinteger(a, _("line range bounds must be integers")) 942 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
938 for a in lr] 943 for a in lr]
939 fromline, toline = util.processlinerange(fromline, toline) 944 fromline, toline = util.processlinerange(fromline, toline)
940 945
941 fctx = repo[rev].filectx(fname) 946 fctx = repo[rev].filectx(fname)
942 revs = (c.rev() for c, _linerange 947 if args.get('descend', False):
943 in context.blockancestors(fctx, fromline, toline)) 948 rs = generatorset(
944 return subset & generatorset(revs, iterasc=False) 949 (c.rev() for c, _linerange
950 in context.blockdescendants(fctx, fromline, toline)),
951 iterasc=True)
952 else:
953 rs = generatorset(
954 (c.rev() for c, _linerange
955 in context.blockancestors(fctx, fromline, toline)),
956 iterasc=False)
957 return subset & rs
945 958
946 @predicate('all()', safe=True) 959 @predicate('all()', safe=True)
947 def getall(repo, subset, x): 960 def getall(repo, subset, x):
948 """All changesets, the same as ``0:tip``. 961 """All changesets, the same as ``0:tip``.
949 """ 962 """