blame: fix coloring for repeated suspects

The option --ignore-rev passes the blame to an older commit. This can cause adjacent scoreboard entries to blame the same commit. Currently we only look at the present entry when determining whether a line needs to be colored for --color-lines. Check the previous entry as well. Reported-by: Seth McDonald <sethmcmail@pm.me> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Feb 1, 2026 at 12:47 UTC d519082d4ebf998cd9d10a5ef33544a479e7699c
2 files changed +23 -4
builtin/blame.c
+9 -4
@@ -461,7 +461,8 @@ static void determine_line_heat(struct commit_info *ci, const char **dest_color)
461 *dest_color = colorfield[i].col;
462 }
463
464 -static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
464 +static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent,
465 + int opt, struct blame_entry *prev_ent)
466 {
467 int cnt;
468 const char *cp;
@@ -492,7 +493,10 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
493 the_hash_algo->hexsz : (size_t) abbrev;
494
495 if (opt & OUTPUT_COLOR_LINE) {
495 - if (cnt > 0) {
496 + if (cnt > 0 ||
497 + (prev_ent &&
498 + oideq(&suspect->commit->object.oid,
499 + &prev_ent->suspect->commit->object.oid))) {
500 color = repeated_meta_color;
501 reset = GIT_COLOR_RESET;
502 } else {
@@ -578,7 +582,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
582
583 static void output(struct blame_scoreboard *sb, int option)
584 {
581 - struct blame_entry *ent;
585 + struct blame_entry *ent, *prev_ent = NULL;
586
587 if (option & OUTPUT_PORCELAIN) {
588 for (ent = sb->ent; ent; ent = ent->next) {
@@ -600,7 +604,8 @@ static void output(struct blame_scoreboard *sb, int option)
604 if (option & OUTPUT_PORCELAIN)
605 emit_porcelain(sb, ent, option);
606 else {
603 - emit_other(sb, ent, option);
607 + emit_other(sb, ent, option, prev_ent);
608 + prev_ent = ent;
609 }
610 }
611 }
t/t8012-blame-colors.sh
+14
@@ -28,6 +28,20 @@ test_expect_success 'colored blame colors contiguous lines' '
28 test_line_count = 3 H.expect
29 '
30
31 +test_expect_success 'color lines becoming contiguous due to --ignore-rev' '
32 + mv hello.c hello.orig &&
33 + sed "s/ / /g" <hello.orig >hello.c &&
34 + git add hello.c &&
35 + git commit -m"tabs to spaces" &&
36 + git -c color.blame.repeatedLines=yellow blame --color-lines --ignore-rev=HEAD hello.c >actual.raw &&
37 + test_decode_color <actual.raw >actual &&
38 + grep "<YELLOW>" <actual >darkened &&
39 + grep "(F" darkened > F.expect &&
40 + grep "(H" darkened > H.expect &&
41 + test_line_count = 2 F.expect &&
42 + test_line_count = 3 H.expect
43 +'
44 +
45 test_expect_success 'color by age consistently colors old code' '
46 git blame --color-by-age hello.c >actual.raw &&
47 git -c blame.coloring=highlightRecent blame hello.c >actual.raw.2 &&