@@ -2402,16 +2402,11 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
2402
2402
return commit ;
2403
2403
}
2404
2404
2405
- static char * prepare_final (struct scoreboard * sb )
2405
+ static struct object_array_entry * find_single_final (struct rev_info * revs )
2406
2406
{
2407
2407
int i ;
2408
- const char * final_commit_name = NULL ;
2409
- struct rev_info * revs = sb -> revs ;
2408
+ struct object_array_entry * found = NULL ;
2410
2409
2411
- /*
2412
- * There must be one and only one positive commit in the
2413
- * revs->pending array.
2414
- */
2415
2410
for (i = 0 ; i < revs -> pending .nr ; i ++ ) {
2416
2411
struct object * obj = revs -> pending .objects [i ].item ;
2417
2412
if (obj -> flags & UNINTERESTING )
@@ -2420,14 +2415,24 @@ static char *prepare_final(struct scoreboard *sb)
2420
2415
obj = deref_tag (obj , NULL , 0 );
2421
2416
if (obj -> type != OBJ_COMMIT )
2422
2417
die ("Non commit %s?" , revs -> pending .objects [i ].name );
2423
- if (sb -> final )
2418
+ if (found )
2424
2419
die ("More than one commit to dig from %s and %s?" ,
2425
2420
revs -> pending .objects [i ].name ,
2426
- final_commit_name );
2427
- sb -> final = (struct commit * ) obj ;
2428
- final_commit_name = revs -> pending .objects [i ].name ;
2421
+ found -> name );
2422
+ found = & (revs -> pending .objects [i ]);
2423
+ }
2424
+ return found ;
2425
+ }
2426
+
2427
+ static char * prepare_final (struct scoreboard * sb )
2428
+ {
2429
+ struct object_array_entry * found = find_single_final (sb -> revs );
2430
+ if (found ) {
2431
+ sb -> final = (struct commit * ) found -> item ;
2432
+ return xstrdup (found -> name );
2433
+ } else {
2434
+ return NULL ;
2429
2435
}
2430
- return xstrdup_or_null (final_commit_name );
2431
2436
}
2432
2437
2433
2438
static char * prepare_initial (struct scoreboard * sb )
@@ -2503,6 +2508,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2503
2508
long dashdash_pos , lno ;
2504
2509
char * final_commit_name = NULL ;
2505
2510
enum object_type type ;
2511
+ struct commit * final_commit = NULL ;
2506
2512
2507
2513
static struct string_list range_list ;
2508
2514
static int output_option = 0 , opt = 0 ;
@@ -2692,11 +2698,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2692
2698
}
2693
2699
else if (contents_from )
2694
2700
die ("--contents and --reverse do not blend well." );
2695
- else if (revs .first_parent_only )
2696
- die ("combining --first-parent and --reverse is not supported" );
2697
2701
else {
2698
2702
final_commit_name = prepare_initial (& sb );
2699
2703
sb .commits .compare = compare_commits_by_reverse_commit_date ;
2704
+ if (revs .first_parent_only )
2705
+ revs .children .name = NULL ;
2700
2706
}
2701
2707
2702
2708
if (!sb .final ) {
@@ -2713,6 +2719,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2713
2719
else if (contents_from )
2714
2720
die ("Cannot use --contents with final commit object name" );
2715
2721
2722
+ if (reverse && revs .first_parent_only ) {
2723
+ struct object_array_entry * entry = find_single_final (sb .revs );
2724
+ if (!entry )
2725
+ die ("--reverse and --first-parent together require specified latest commit" );
2726
+ else
2727
+ final_commit = (struct commit * ) entry -> item ;
2728
+ }
2729
+
2716
2730
/*
2717
2731
* If we have bottom, this will mark the ancestors of the
2718
2732
* bottom commits we would reach while traversing as
@@ -2721,6 +2735,25 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2721
2735
if (prepare_revision_walk (& revs ))
2722
2736
die (_ ("revision walk setup failed" ));
2723
2737
2738
+ if (reverse && revs .first_parent_only ) {
2739
+ struct commit * c = final_commit ;
2740
+
2741
+ sb .revs -> children .name = "children" ;
2742
+ while (c -> parents &&
2743
+ hashcmp (c -> object .sha1 , sb .final -> object .sha1 )) {
2744
+ struct commit_list * l = xcalloc (1 , sizeof (* l ));
2745
+
2746
+ l -> item = c ;
2747
+ if (add_decoration (& sb .revs -> children ,
2748
+ & c -> parents -> item -> object , l ))
2749
+ die ("BUG: not unique item in first-parent chain" );
2750
+ c = c -> parents -> item ;
2751
+ }
2752
+
2753
+ if (hashcmp (c -> object .sha1 , sb .final -> object .sha1 ))
2754
+ die ("--reverse --first-parent together require range along first-parent chain" );
2755
+ }
2756
+
2724
2757
if (is_null_sha1 (sb .final -> object .sha1 )) {
2725
2758
o = sb .final -> util ;
2726
2759
sb .final_buf = xmemdupz (o -> file .ptr , o -> file .size );
0 commit comments