Git fork

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 <ps@pks.im>
Helped-by: Toon Claes <toon@iotcl.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Karthik Nayak and committed by
Junio C Hamano
4d253071 683c54c9

+60 -5
+2 -1
Documentation/blame-options.adoc
··· 125 another commit will be marked with a `?` in the blame output. If the 126 `blame.markUnblamableLines` config option is set, then those lines touched 127 by an ignored commit that we could not attribute to another revision are 128 - marked with a '*'. 129 130 --ignore-revs-file <file>:: 131 Ignore revisions listed in `file`, which must be in the same format as an
··· 125 another commit will be marked with a `?` in the blame output. If the 126 `blame.markUnblamableLines` config option is set, then those lines touched 127 by an ignored commit that we could not attribute to another revision are 128 + marked with a '*'. In the porcelain modes, we print 'ignored' and 129 + 'unblamable' on a newline respectively. 130 131 --ignore-revs-file <file>:: 132 Ignore revisions listed in `file`, which must be in the same format as an
+5 -4
Documentation/git-blame.adoc
··· 135 The porcelain format generally suppresses commit information that has 136 already been seen. For example, two lines that are blamed to the same 137 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: 142 143 # count the number of lines attributed to each author 144 git blame --line-porcelain file |
··· 135 The porcelain format generally suppresses commit information that has 136 already been seen. For example, two lines that are blamed to the same 137 commit will both be shown, but the details for that commit will be shown 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: 143 144 # count the number of lines attributed to each author 145 git blame --line-porcelain file |
+15
builtin/blame.c
··· 351 write_filename_info(suspect); 352 } 353 354 static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, 355 int opt) 356 { ··· 367 ent->lno + 1, 368 ent->num_lines); 369 emit_porcelain_details(suspect, repeat); 370 371 cp = blame_nth_line(sb, ent->lno); 372 for (cnt = 0; cnt < ent->num_lines; cnt++) { ··· 377 ent->lno + 1 + cnt); 378 if (repeat) 379 emit_porcelain_details(suspect, 1); 380 } 381 putchar('\t'); 382 do {
··· 351 write_filename_info(suspect); 352 } 353 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 + 367 static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, 368 int opt) 369 { ··· 380 ent->lno + 1, 381 ent->num_lines); 382 emit_porcelain_details(suspect, repeat); 383 + emit_porcelain_per_line_details(ent); 384 385 cp = blame_nth_line(sb, ent->lno); 386 for (cnt = 0; cnt < ent->num_lines; cnt++) { ··· 391 ent->lno + 1 + cnt); 392 if (repeat) 393 emit_porcelain_details(suspect, 1); 394 + emit_porcelain_per_line_details(ent); 395 } 396 putchar('\t'); 397 do {
+38
t/t8013-blame-ignore-revs.sh
··· 158 test_cmp expect actual 159 ' 160 161 # Commit Z will touch the first two lines. Y touched all four. 162 # A--B--X--Y--Z 163 # The blame output when ignoring Z should be: ··· 190 sed -n "4p" blame_raw | cut -c1 >actual && 191 ! test_cmp expect actual 192 ' 193 194 # For ignored revs that added 'unblamable' lines and more recent commits changed 195 # the blamable lines, mark the unblamable lines with a
··· 158 test_cmp expect actual 159 ' 160 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 + 180 # Commit Z will touch the first two lines. Y touched all four. 181 # A--B--X--Y--Z 182 # The blame output when ignoring Z should be: ··· 209 sed -n "4p" blame_raw | cut -c1 >actual && 210 ! test_cmp expect actual 211 ' 212 + 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 232 # For ignored revs that added 'unblamable' lines and more recent commits changed 233 # the blamable lines, mark the unblamable lines with a