2222#include "utf8.h"
2323#include "userdiff.h"
2424#include "line-range.h"
25+ #include "line-log.h"
2526
2627static char blame_usage [] = N_ ("git blame [options] [rev-opts] [rev] [--] file" );
2728
@@ -2233,29 +2234,18 @@ static int blame_move_callback(const struct option *option, const char *arg, int
22332234 return 0 ;
22342235}
22352236
2236- static int blame_bottomtop_callback (const struct option * option , const char * arg , int unset )
2237- {
2238- const char * * bottomtop = option -> value ;
2239- if (!arg )
2240- return -1 ;
2241- if (* bottomtop )
2242- die ("More than one '-L n,m' option given" );
2243- * bottomtop = arg ;
2244- return 0 ;
2245- }
2246-
22472237int cmd_blame (int argc , const char * * argv , const char * prefix )
22482238{
22492239 struct rev_info revs ;
22502240 const char * path ;
22512241 struct scoreboard sb ;
22522242 struct origin * o ;
2253- struct blame_entry * ent ;
2254- long dashdash_pos , bottom , top , lno ;
2243+ struct blame_entry * ent = NULL ;
2244+ long dashdash_pos , lno ;
22552245 const char * final_commit_name = NULL ;
22562246 enum object_type type ;
22572247
2258- static const char * bottomtop = NULL ;
2248+ static struct string_list range_list ;
22592249 static int output_option = 0 , opt = 0 ;
22602250 static int show_stats = 0 ;
22612251 static const char * revs_file = NULL ;
@@ -2281,13 +2271,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
22812271 OPT_STRING (0 , "contents" , & contents_from , N_ ("file" ), N_ ("Use <file>'s contents as the final image" )),
22822272 { OPTION_CALLBACK , 'C' , NULL , & opt , N_ ("score" ), N_ ("Find line copies within and across files" ), PARSE_OPT_OPTARG , blame_copy_callback },
22832273 { OPTION_CALLBACK , 'M' , NULL , & opt , N_ ("score" ), N_ ("Find line movements within and across files" ), PARSE_OPT_OPTARG , blame_move_callback },
2284- OPT_CALLBACK ('L' , NULL , & bottomtop , N_ ("n,m" ), N_ ("Process only line range n,m, counting from 1" ), blame_bottomtop_callback ),
2274+ OPT_STRING_LIST ('L' , NULL , & range_list , N_ ("n,m" ), N_ ("Process only line range n,m, counting from 1" )),
22852275 OPT__ABBREV (& abbrev ),
22862276 OPT_END ()
22872277 };
22882278
22892279 struct parse_opt_ctx_t ctx ;
22902280 int cmd_is_annotate = !strcmp (argv [0 ], "annotate" );
2281+ struct range_set ranges ;
2282+ unsigned int range_i ;
22912283
22922284 git_config (git_blame_config , NULL );
22932285 init_revisions (& revs , NULL );
@@ -2480,23 +2472,46 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24802472 num_read_blob ++ ;
24812473 lno = prepare_lines (& sb );
24822474
2483- bottom = top = 0 ;
2484- if (bottomtop && parse_range_arg (bottomtop , nth_line_cb , & sb , lno ,
2485- & bottom , & top , sb .path ))
2486- usage (blame_usage );
2487- if (lno < top || ((lno || bottom ) && lno < bottom ))
2488- die ("file %s has only %lu lines" , path , lno );
2489- if (bottom < 1 )
2490- bottom = 1 ;
2491- if (top < 1 )
2492- top = lno ;
2493- bottom -- ;
2494-
2495- ent = xcalloc (1 , sizeof (* ent ));
2496- ent -> lno = bottom ;
2497- ent -> num_lines = top - bottom ;
2498- ent -> suspect = o ;
2499- ent -> s_lno = bottom ;
2475+ if (lno && !range_list .nr )
2476+ string_list_append (& range_list , xstrdup ("1" ));
2477+
2478+ range_set_init (& ranges , range_list .nr );
2479+ for (range_i = 0 ; range_i < range_list .nr ; ++ range_i ) {
2480+ long bottom , top ;
2481+ if (parse_range_arg (range_list .items [range_i ].string ,
2482+ nth_line_cb , & sb , lno ,
2483+ & bottom , & top , sb .path ))
2484+ usage (blame_usage );
2485+ if (lno < top || ((lno || bottom ) && lno < bottom ))
2486+ die ("file %s has only %lu lines" , path , lno );
2487+ if (bottom < 1 )
2488+ bottom = 1 ;
2489+ if (top < 1 )
2490+ top = lno ;
2491+ bottom -- ;
2492+ range_set_append_unsafe (& ranges , bottom , top );
2493+ }
2494+ sort_and_merge_range_set (& ranges );
2495+
2496+ for (range_i = ranges .nr ; range_i > 0 ; -- range_i ) {
2497+ const struct range * r = & ranges .ranges [range_i - 1 ];
2498+ long bottom = r -> start ;
2499+ long top = r -> end ;
2500+ struct blame_entry * next = ent ;
2501+ ent = xcalloc (1 , sizeof (* ent ));
2502+ ent -> lno = bottom ;
2503+ ent -> num_lines = top - bottom ;
2504+ ent -> suspect = o ;
2505+ ent -> s_lno = bottom ;
2506+ ent -> next = next ;
2507+ if (next )
2508+ next -> prev = ent ;
2509+ origin_incref (o );
2510+ }
2511+ origin_decref (o );
2512+
2513+ range_set_release (& ranges );
2514+ string_list_clear (& range_list , 0 );
25002515
25012516 sb .ent = ent ;
25022517 sb .path = path ;
0 commit comments