Skip to content

Commit d0738d9

Browse files
Barret Rhodengitster
authored andcommitted
blame: add config options to handle output for ignored lines
When ignoring commits, the commit that is blamed might not be responsible for the change. Users might want to know when a particular line has a potentially inaccurate blame. Furthermore, they might never want to see the object hash of an ignored commit. This patch adds two config options to control the output behavior. The first option can identify ignored lines by specifying blame.markIgnoredFiles. When this option is set, each blame line is marked with an '*'. For example: 278b6158d6fdb (Barret Rhoden 2016-04-11 13:57:54 -0400 26) appears as: *278b6158d6fd (Barret Rhoden 2016-04-11 13:57:54 -0400 26) where the '*' is placed before the commit, and the hash has one fewer characters. Sometimes we are unable to even guess at what commit touched a line. These lines are 'unblamable.' The second option, blame.maskIgnoredUnblamables, will zero the hash of any unblamable line. For example, say we ignore e5e8d36d04cbe: e5e8d36d04cbe (Barret Rhoden 2016-04-11 13:57:54 -0400 26) appears as: 0000000000000 (Barret Rhoden 2016-04-11 13:57:54 -0400 26) Signed-off-by: Barret Rhoden <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a5c9167 commit d0738d9

File tree

6 files changed

+69
-3
lines changed

6 files changed

+69
-3
lines changed

Documentation/blame-options.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ take effect.
115115
change never happened. Lines that were changed or added by an ignored
116116
commit will be blamed on the previous commit that changed that line or
117117
nearby lines. This option may be specified multiple times to ignore
118-
more than one revision.
118+
more than one revision. If the `blame.markIgnoredLines` config option
119+
is set, then lines that were changed by an ignored commit will be
120+
marked with a `*` in the blame output. If the
121+
`blame.maskIgnoredUnblamables` config option is set, then those lines that
122+
we could not attribute to another revision are outputted as all zeros.
119123

120124
--ignore-revs-file <file>::
121125
Ignore revisions listed in `file`, one unabbreviated object name per line.

Documentation/config/blame.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,12 @@ blame.ignoreRevsFile::
2626
`#` are ignored. This option may be repeated multiple times. Empty
2727
file names will reset the list of ignored revisions. This option will
2828
be handled before the command line option `--ignore-revs-file`.
29+
30+
blame.maskIgnoredUnblamables::
31+
Output an object hash of all zeros for lines that were changed by an ignored
32+
revision and that we could not attribute to another revision in the output
33+
of linkgit:git-blame[1].
34+
35+
blame.markIgnoredLines::
36+
Mark lines that were changed by an ignored revision with a '*' in the
37+
output of linkgit:git-blame[1].

blame.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ void blame_coalesce(struct blame_scoreboard *sb)
480480
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
481481
if (ent->suspect == next->suspect &&
482482
ent->s_lno + ent->num_lines == next->s_lno &&
483+
ent->ignored == next->ignored &&
483484
ent->unblamable == next->unblamable) {
484485
ent->num_lines += next->num_lines;
485486
ent->next = next->next;
@@ -732,6 +733,7 @@ static void split_overlap(struct blame_entry *split,
732733
int chunk_end_lno;
733734
memset(split, 0, sizeof(struct blame_entry [3]));
734735

736+
split[0].ignored = split[1].ignored = split[2].ignored = e->ignored;
735737
split[0].unblamable = e->unblamable;
736738
split[1].unblamable = e->unblamable;
737739
split[2].unblamable = e->unblamable;
@@ -856,6 +858,7 @@ static struct blame_entry *split_blame_at(struct blame_entry *e, int len,
856858
struct blame_entry *n = xcalloc(1, sizeof(struct blame_entry));
857859

858860
n->suspect = new_suspect;
861+
n->ignored = e->ignored;
859862
n->unblamable = e->unblamable;
860863
n->lno = e->lno + len;
861864
n->s_lno = e->s_lno + len;
@@ -921,6 +924,7 @@ static void ignore_blame_entry(struct blame_entry *e,
921924
struct blame_line_tracker *line_blames;
922925
int entry_len, nr_lines, i;
923926

927+
e->ignored = 1;
924928
line_blames = xcalloc(sizeof(struct blame_line_tracker),
925929
e->num_lines);
926930
guess_line_blames(e, parent, target, offset, parent_slno, parent_len,

blame.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct blame_entry {
9292
* scanning the lines over and over.
9393
*/
9494
unsigned score;
95+
int ignored;
9596
int unblamable;
9697
};
9798

builtin/blame.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ static int show_progress;
5353
static char repeated_meta_color[COLOR_MAXLEN];
5454
static int coloring_mode;
5555
static struct string_list ignore_revs_file_list = STRING_LIST_INIT_NODUP;
56+
static int mask_ignored_unblamables;
57+
static int mark_ignored_lines;
5658

5759
static struct date_mode blame_date_mode = { DATE_ISO8601 };
5860
static size_t blame_date_width;
@@ -347,7 +349,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
347349
char hex[GIT_MAX_HEXSZ + 1];
348350

349351
oid_to_hex_r(hex, &suspect->commit->object.oid);
350-
if (ent->unblamable)
352+
if (mask_ignored_unblamables && ent->unblamable)
351353
memset(hex, '0', strlen(hex));
352354
printf("%s %d %d %d\n",
353355
hex,
@@ -482,7 +484,11 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
482484
}
483485
}
484486

485-
if (ent->unblamable)
487+
if (mark_ignored_lines && ent->ignored) {
488+
length--;
489+
putchar('*');
490+
}
491+
if (mask_ignored_unblamables && ent->unblamable)
486492
memset(hex, '0', length);
487493
printf("%.*s", length, hex);
488494
if (opt & OUTPUT_ANNOTATE_COMPAT) {
@@ -710,6 +716,14 @@ static int git_blame_config(const char *var, const char *value, void *cb)
710716
string_list_insert(&ignore_revs_file_list, str);
711717
return 0;
712718
}
719+
if (!strcmp(var, "blame.maskignoredunblamables")) {
720+
mask_ignored_unblamables = git_config_bool(var, value);
721+
return 0;
722+
}
723+
if (!strcmp(var, "blame.markignoredlines")) {
724+
mark_ignored_lines = git_config_bool(var, value);
725+
return 0;
726+
}
713727
if (!strcmp(var, "color.blame.repeatedlines")) {
714728
if (color_parse_mem(value, strlen(value), repeated_meta_color))
715729
warning(_("invalid color '%s' in color.blame.repeatedLines"),

t/t8013-blame-ignore-revs.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ test_expect_success ignore_rev_changing_lines '
5353
# to have nothing in common with "line-one" or "line-two", to keep any
5454
# heuristics from matching them with any lines in the parent.
5555
test_expect_success ignore_rev_adding_unblamable_lines '
56+
git config --add blame.maskIgnoredUnblamables true &&
5657
test_write_lines line-one-change line-two-changed y3 y4 >file &&
5758
git add file &&
5859
test_tick &&
@@ -123,6 +124,39 @@ test_expect_success bad_files_and_revs '
123124
test_i18ngrep "Invalid object name: NOREV" err
124125
'
125126

127+
# Commit Z will touch the first two lines. Y touched all four.
128+
# A--B--X--Y--Z
129+
# The blame output when ignoring Z should be:
130+
# ^Y ... 1)
131+
# ^Y ... 2)
132+
# Y ... 3)
133+
# Y ... 4)
134+
# We're checking only the first character
135+
test_expect_success mark_ignored_lines '
136+
git config --add blame.markIgnoredLines true &&
137+
138+
test_write_lines line-one-Z line-two-Z y3 y4 >file &&
139+
git add file &&
140+
test_tick &&
141+
git commit -m Z &&
142+
git tag Z &&
143+
144+
git blame --ignore-rev Z file >blame_raw &&
145+
echo "*" >expect &&
146+
147+
sed -n "1p" blame_raw | cut -c1 >actual &&
148+
test_cmp expect actual &&
149+
150+
sed -n "2p" blame_raw | cut -c1 >actual &&
151+
test_cmp expect actual &&
152+
153+
sed -n "3p" blame_raw | cut -c1 >actual &&
154+
! test_cmp expect actual &&
155+
156+
sed -n "4p" blame_raw | cut -c1 >actual &&
157+
! test_cmp expect actual
158+
'
159+
126160
# Resetting the repo and creating:
127161
#
128162
# A--B--M

0 commit comments

Comments
 (0)