]> git.ipfire.org Git - thirdparty/git.git/commitdiff
blame: print unblamable and ignored commits in porcelain mode
authorKarthik Nayak <karthik.188@gmail.com>
Thu, 3 Apr 2025 16:03:26 +0000 (18:03 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 7 Apr 2025 21:50:18 +0000 (14:50 -0700)
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>
Documentation/blame-options.adoc
Documentation/git-blame.adoc
builtin/blame.c
t/t8013-blame-ignore-revs.sh

index aa77406d4ef335c3fd39b6605c7ddea961a4bbec..19ea1872388ffe7e4bd5b9037f7299592f842b3b 100644 (file)
@@ -125,7 +125,8 @@ take effect.
        another commit will be marked with a `?` in the blame output.  If the
        `blame.markUnblamableLines` config option is set, then those lines touched
        by an ignored commit that we could not attribute to another revision are
-       marked with a '*'.
+       marked with a '*'. In the porcelain modes, we print 'ignored' and
+       'unblamable' on a newline respectively.
 
 --ignore-revs-file <file>::
        Ignore revisions listed in `file`, which must be in the same format as an
index f75ed4479021cbf418e8a41326896508335acd48..e438d28625882669b7cb615fac7e6580479c0dbe 100644 (file)
@@ -135,10 +135,11 @@ header elements later.
 The porcelain format generally suppresses commit information that has
 already been seen. For example, two lines that are blamed to the same
 commit will both be shown, but the details for that commit will be shown
-only once. This is more efficient, but may require more state be kept by
-the reader. The `--line-porcelain` option can be used to output full
-commit information for each line, allowing simpler (but less efficient)
-usage like:
+only once. Information which is specific to individual lines will not be
+grouped together, like revs to be marked 'ignored' or 'unblamable'. This
+is more efficient, but may require more state be kept by the reader. The
+`--line-porcelain` option can be used to output full commit information
+for each line, allowing simpler (but less efficient) usage like:
 
        # count the number of lines attributed to each author
        git blame --line-porcelain file |
index c470654c7ec2c364c30b28ae2da09e15a0571491..9436f70aecd6cefa4e67fc1b329f14291b72d064 100644 (file)
@@ -351,6 +351,19 @@ static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
                write_filename_info(suspect);
 }
 
+/*
+ * Information which needs to be printed per-line goes here. Any
+ * information which can be clubbed on a commit/file level, should
+ * be printed via 'emit_one_suspect_detail()'.
+ */
+static void emit_porcelain_per_line_details(struct blame_entry *ent)
+{
+       if (mark_unblamable_lines && ent->unblamable)
+               puts("unblamable");
+       if (mark_ignored_lines && ent->ignored)
+               puts("ignored");
+}
+
 static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
                           int opt)
 {
@@ -367,6 +380,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
               ent->lno + 1,
               ent->num_lines);
        emit_porcelain_details(suspect, repeat);
+       emit_porcelain_per_line_details(ent);
 
        cp = blame_nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
@@ -377,6 +391,7 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
                               ent->lno + 1 + cnt);
                        if (repeat)
                                emit_porcelain_details(suspect, 1);
+                       emit_porcelain_per_line_details(ent);
                }
                putchar('\t');
                do {
index 370b76814927f3ec460272f983daacb4d303979e..cace00ae8d6ae7b3cb194e1e8466c7e0e77293b0 100755 (executable)
@@ -158,6 +158,25 @@ test_expect_success mark_unblamable_lines '
        test_cmp expect actual
 '
 
+for opt in --porcelain --line-porcelain
+do
+       test_expect_success "mark_unblamable_lines with $opt" "
+               sha=$(git rev-parse Y) &&
+
+               git -c blame.markUnblamableLines=false blame $opt --ignore-rev Y file >raw &&
+               cat > sedscript <<- 'EOF' &&
+               /^      y3/i\\
+               unblamable
+               /^      y4/i\\
+               unblamable
+               EOF
+               sed -f sedscript raw >expect &&
+
+               git -c blame.markUnblamableLines=true blame $opt --ignore-rev Y file >actual &&
+               test_cmp expect actual
+       "
+done
+
 # Commit Z will touch the first two lines.  Y touched all four.
 #      A--B--X--Y--Z
 # The blame output when ignoring Z should be:
@@ -191,6 +210,25 @@ test_expect_success mark_ignored_lines '
        ! test_cmp expect actual
 '
 
+for opt in --porcelain --line-porcelain
+do
+       test_expect_success "mark_ignored_lines with $opt" "
+               sha=$(git rev-parse Y) &&
+
+               git -c blame.markIgnoredLines=false blame $opt --ignore-rev Z file >raw &&
+               cat > sedscript <<- 'EOF' &&
+               /^      line-one-Z/i\\
+               ignored
+               /^      line-two-Z/i\\
+               ignored
+               EOF
+               sed -f sedscript raw >expect &&
+
+               git -c blame.markIgnoredLines=true blame $opt --ignore-rev Z file >actual &&
+               test_cmp expect actual
+       "
+done
+
 # For ignored revs that added 'unblamable' lines and more recent commits changed
 # the blamable lines, mark the unblamable lines with a
 # '*'