diff -r 890afefa7296 -r 84c6b9384d6a mercurial/commands.py --- a/mercurial/commands.py Fri Oct 06 14:45:17 2017 +0200 +++ b/mercurial/commands.py Tue Oct 17 21:15:31 2017 +0200 @@ -3234,6 +3234,9 @@ ('k', 'keyword', [], _('do case-insensitive search for a given text'), _('TEXT')), ('r', 'rev', [], _('show the specified revision or revset'), _('REV')), + ('L', 'line-range', [], + _('follow line range of specified file (EXPERIMENTAL)'), + _('FILE,RANGE')), ('', 'removed', None, _('include revisions where files were removed')), ('m', 'only-merges', None, _('show only merges (DEPRECATED)')), ('u', 'user', [], _('revisions committed by user'), _('USER')), @@ -3275,6 +3278,14 @@ Paths in the DAG are represented with '|', '/' and so forth. ':' in place of a '|' indicates one or more revisions in a path are omitted. + .. container:: verbose + + Use -L/--line-range FILE,M-N options to follow the history of lines + from M to N in FILE. With -p/--patch only diff hunks affecting + specified line range will be shown. This option requires --follow; + it can be specified multiple times. Currently, this option is not + compatible with --graph. This option is experimental. + .. note:: :hg:`log --patch` may generate unexpected diff output for merge @@ -3290,6 +3301,14 @@ .. container:: verbose + .. note:: + + The history resulting from -L/--line-range options depends on diff + options; for instance if white-spaces are ignored, respective changes + with only white-spaces in specified line range will not be listed. + + .. container:: verbose + Some examples: - changesets with full descriptions and file lists:: @@ -3336,6 +3355,15 @@ hg log -r "last(tagged())::" --template "{desc|firstline}\\n" + - changesets touching lines 13 to 23 for file.c:: + + hg log -L file.c,13-23 + + - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of + main.c with patch:: + + hg log -L file.c,13-23 -L main.c,2-6 -p + See :hg:`help dates` for a list of formats valid for -d/--date. See :hg:`help revisions` for more about specifying and ordering @@ -3350,14 +3378,38 @@ """ opts = pycompat.byteskwargs(opts) + linerange = opts.get('line_range') + + if linerange and not opts.get('follow'): + raise error.Abort(_('--line-range requires --follow')) + if opts.get('follow') and opts.get('rev'): opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))] del opts['follow'] if opts.get('graph'): + if linerange: + raise error.Abort(_('graph not supported with line range patterns')) return cmdutil.graphlog(ui, repo, pats, opts) revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts) + hunksfilter = None + + if linerange: + revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs( + repo, revs, opts) + + if filematcher is not None and lrfilematcher is not None: + basefilematcher = filematcher + + def filematcher(rev): + files = (basefilematcher(rev).files() + + lrfilematcher(rev).files()) + return scmutil.matchfiles(repo, files) + + elif filematcher is None: + filematcher = lrfilematcher + limit = cmdutil.loglimit(opts) count = 0 @@ -3385,7 +3437,12 @@ revmatchfn = filematcher(ctx.rev()) else: revmatchfn = None - displayer.show(ctx, copies=copies, matchfn=revmatchfn) + if hunksfilter: + revhunksfilter = hunksfilter(rev) + else: + revhunksfilter = None + displayer.show(ctx, copies=copies, matchfn=revmatchfn, + hunksfilterfn=revhunksfilter) if displayer.flush(ctx): count += 1