Skip to content

Commit ed747dd

Browse files
peffgitster
authored andcommitted
blame: add --line-porcelain output format
This is just like --porcelain, except that we always output the commit information for each line, not just the first time it is referenced. This can make quick and dirty scripts much easier to write; see the example added to the blame documentation. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent e86226e commit ed747dd

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

Documentation/blame-options.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ of lines before or after the line given by <start>.
5252
--porcelain::
5353
Show in a format designed for machine consumption.
5454

55+
--line-porcelain::
56+
Show the porcelain format, but output commit information for
57+
each line, not just the first time a commit is referenced.
58+
Implies --porcelain.
59+
5560
--incremental::
5661
Show the result incrementally in a format designed for
5762
machine consumption.

Documentation/git-blame.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ The contents of the actual line is output after the above
105105
header, prefixed by a TAB. This is to allow adding more
106106
header elements later.
107107

108+
The porcelain format generally suppresses commit information that has
109+
already been seen. For example, two lines that are blamed to the same
110+
commit will both be shown, but the details for that commit will be shown
111+
only once. This is more efficient, but may require more state be kept by
112+
the reader. The `--line-porcelain` option can be used to output full
113+
commit information for each line, allowing simpler (but less efficient)
114+
usage like:
115+
116+
# count the number of lines attributed to each author
117+
git blame --line-porcelain file |
118+
sed -n 's/^author //p' |
119+
sort | uniq -c | sort -rn
120+
108121

109122
SPECIFYING RANGES
110123
-----------------

builtin/blame.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
16191619
#define OUTPUT_SHOW_SCORE 0100
16201620
#define OUTPUT_NO_AUTHOR 0200
16211621
#define OUTPUT_SHOW_EMAIL 0400
1622+
#define OUTPUT_LINE_PORCELAIN 01000
16221623

16231624
static void emit_porcelain_details(struct origin *suspect, int repeat)
16241625
{
@@ -1630,6 +1631,7 @@ static void emit_porcelain_details(struct origin *suspect, int repeat)
16301631
static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
16311632
int opt)
16321633
{
1634+
int repeat = opt & OUTPUT_LINE_PORCELAIN;
16331635
int cnt;
16341636
const char *cp;
16351637
struct origin *suspect = ent->suspect;
@@ -1642,15 +1644,18 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
16421644
ent->s_lno + 1,
16431645
ent->lno + 1,
16441646
ent->num_lines);
1645-
emit_porcelain_details(suspect, 0);
1647+
emit_porcelain_details(suspect, repeat);
16461648

16471649
cp = nth_line(sb, ent->lno);
16481650
for (cnt = 0; cnt < ent->num_lines; cnt++) {
16491651
char ch;
1650-
if (cnt)
1652+
if (cnt) {
16511653
printf("%s %d %d\n", hex,
16521654
ent->s_lno + 1 + cnt,
16531655
ent->lno + 1 + cnt);
1656+
if (repeat)
1657+
emit_porcelain_details(suspect, 1);
1658+
}
16541659
putchar('\t');
16551660
do {
16561661
ch = *cp++;
@@ -2307,6 +2312,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
23072312
OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
23082313
OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
23092314
OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
2315+
OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
23102316
OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
23112317
OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
23122318
OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),

t/t8008-blame-formats.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,23 @@ test_expect_success 'blame --porcelain output' '
6868
test_cmp expect actual
6969
'
7070

71+
cat >expect <<EOF
72+
$ID1 1 1 1
73+
$COMMIT1
74+
a
75+
$ID2 2 2 3
76+
$COMMIT2
77+
b
78+
$ID2 3 3
79+
$COMMIT2
80+
c
81+
$ID2 4 4
82+
$COMMIT2
83+
d
84+
EOF
85+
test_expect_success 'blame --line-porcelain output' '
86+
git blame --line-porcelain file >actual &&
87+
test_cmp expect actual
88+
'
89+
7190
test_done

0 commit comments

Comments
 (0)