Skip to content

Commit 4d25307

Browse files
KarthikNayakgitster
authored andcommitted
blame: print unblamable and ignored commits in porcelain mode
The 'git-blame(1)' command allows users to ignore specific revisions via the '--ignore-rev <rev>' and '--ignore-revs-file <file>' flags. These flags are often combined with the 'blame.markIgnoredLines' and 'blame.markUnblamableLines' config options. These config options prefix ignored and unblamable lines with a '?' and '*', respectively. However, this option was never extended to the porcelain mode of 'git-blame(1)'. Since the documentation does not indicate this exclusion, it is a bug. Fix this by printing 'ignored' and 'unblamable' respectively for the options when using the porcelain modes. Helped-by: Patrick Steinhardt <[email protected]> Helped-by: Toon Claes <[email protected]> Helped-by: Phillip Wood <[email protected]> Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 683c54c commit 4d25307

File tree

4 files changed

+60
-5
lines changed

4 files changed

+60
-5
lines changed

Documentation/blame-options.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ take effect.
125125
another commit will be marked with a `?` in the blame output. If the
126126
`blame.markUnblamableLines` config option is set, then those lines touched
127127
by an ignored commit that we could not attribute to another revision are
128-
marked with a '*'.
128+
marked with a '*'. In the porcelain modes, we print 'ignored' and
129+
'unblamable' on a newline respectively.
129130

130131
--ignore-revs-file <file>::
131132
Ignore revisions listed in `file`, which must be in the same format as an

Documentation/git-blame.adoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,11 @@ header elements later.
135135
The porcelain format generally suppresses commit information that has
136136
already been seen. For example, two lines that are blamed to the same
137137
commit will both be shown, but the details for that commit will be shown
138-
only once. This is more efficient, but may require more state be kept by
139-
the reader. The `--line-porcelain` option can be used to output full
140-
commit information for each line, allowing simpler (but less efficient)
141-
usage like:
138+
only once. Information which is specific to individual lines will not be
139+
grouped together, like revs to be marked 'ignored' or 'unblamable'. This
140+
is more efficient, but may require more state be kept by the reader. The
141+
`--line-porcelain` option can be used to output full commit information
142+
for each line, allowing simpler (but less efficient) usage like:
142143

143144
# count the number of lines attributed to each author
144145
git blame --line-porcelain file |

builtin/blame.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,19 @@ static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
351351
write_filename_info(suspect);
352352
}
353353

354+
/*
355+
* Information which needs to be printed per-line goes here. Any
356+
* information which can be clubbed on a commit/file level, should
357+
* be printed via 'emit_one_suspect_detail()'.
358+
*/
359+
static void emit_porcelain_per_line_details(struct blame_entry *ent)
360+
{
361+
if (mark_unblamable_lines && ent->unblamable)
362+
puts("unblamable");
363+
if (mark_ignored_lines && ent->ignored)
364+
puts("ignored");
365+
}
366+
354367
static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
355368
int opt)
356369
{
@@ -367,6 +380,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
367380
ent->lno + 1,
368381
ent->num_lines);
369382
emit_porcelain_details(suspect, repeat);
383+
emit_porcelain_per_line_details(ent);
370384

371385
cp = blame_nth_line(sb, ent->lno);
372386
for (cnt = 0; cnt < ent->num_lines; cnt++) {
@@ -377,6 +391,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
377391
ent->lno + 1 + cnt);
378392
if (repeat)
379393
emit_porcelain_details(suspect, 1);
394+
emit_porcelain_per_line_details(ent);
380395
}
381396
putchar('\t');
382397
do {

t/t8013-blame-ignore-revs.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,25 @@ test_expect_success mark_unblamable_lines '
158158
test_cmp expect actual
159159
'
160160

161+
for opt in --porcelain --line-porcelain
162+
do
163+
test_expect_success "mark_unblamable_lines with $opt" "
164+
sha=$(git rev-parse Y) &&
165+
166+
git -c blame.markUnblamableLines=false blame $opt --ignore-rev Y file >raw &&
167+
cat > sedscript <<- 'EOF' &&
168+
/^ y3/i\\
169+
unblamable
170+
/^ y4/i\\
171+
unblamable
172+
EOF
173+
sed -f sedscript raw >expect &&
174+
175+
git -c blame.markUnblamableLines=true blame $opt --ignore-rev Y file >actual &&
176+
test_cmp expect actual
177+
"
178+
done
179+
161180
# Commit Z will touch the first two lines. Y touched all four.
162181
# A--B--X--Y--Z
163182
# The blame output when ignoring Z should be:
@@ -191,6 +210,25 @@ test_expect_success mark_ignored_lines '
191210
! test_cmp expect actual
192211
'
193212

213+
for opt in --porcelain --line-porcelain
214+
do
215+
test_expect_success "mark_ignored_lines with $opt" "
216+
sha=$(git rev-parse Y) &&
217+
218+
git -c blame.markIgnoredLines=false blame $opt --ignore-rev Z file >raw &&
219+
cat > sedscript <<- 'EOF' &&
220+
/^ line-one-Z/i\\
221+
ignored
222+
/^ line-two-Z/i\\
223+
ignored
224+
EOF
225+
sed -f sedscript raw >expect &&
226+
227+
git -c blame.markIgnoredLines=true blame $opt --ignore-rev Z file >actual &&
228+
test_cmp expect actual
229+
"
230+
done
231+
194232
# For ignored revs that added 'unblamable' lines and more recent commits changed
195233
# the blamable lines, mark the unblamable lines with a
196234
# '*'

0 commit comments

Comments
 (0)