diff -r 826e600605f6 -r 5e3b49defbff mercurial/revset.py --- a/mercurial/revset.py Mon Apr 10 15:11:36 2017 +0200 +++ b/mercurial/revset.py Mon Jan 16 09:24:47 2017 +0100 @@ -901,17 +901,22 @@ # of every revisions or files revisions. return _follow(repo, subset, x, '_followfirst', followfirst=True) -@predicate('followlines(file, fromline:toline[, startrev=.])', safe=True) +@predicate('followlines(file, fromline:toline[, startrev=., descend=False])', + safe=True) def followlines(repo, subset, x): """Changesets modifying `file` in line range ('fromline', 'toline'). Line range corresponds to 'file' content at 'startrev' and should hence be consistent with file size. If startrev is not specified, working directory's parent is used. + + By default, ancestors of 'startrev' are returned. If 'descend' is True, + descendants of 'startrev' are returned though renames are (currently) not + followed in this direction. """ from . import context # avoid circular import issues - args = getargsdict(x, 'followlines', 'file *lines startrev') + args = getargsdict(x, 'followlines', 'file *lines startrev descend') if len(args['lines']) != 1: raise error.ParseError(_("followlines requires a line range")) @@ -939,9 +944,17 @@ fromline, toline = util.processlinerange(fromline, toline) fctx = repo[rev].filectx(fname) - revs = (c.rev() for c, _linerange - in context.blockancestors(fctx, fromline, toline)) - return subset & generatorset(revs, iterasc=False) + if args.get('descend', False): + rs = generatorset( + (c.rev() for c, _linerange + in context.blockdescendants(fctx, fromline, toline)), + iterasc=True) + else: + rs = generatorset( + (c.rev() for c, _linerange + in context.blockancestors(fctx, fromline, toline)), + iterasc=False) + return subset & rs @predicate('all()', safe=True) def getall(repo, subset, x):