From 838466b8f7f9e8752a14114d5c4b1d685e0c6c25 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 9 May 2011 09:33:30 -0400 Subject: add tests for various blame formats We don't seem to have any tests for "blame --porcelain". Let's at least do a trivial test on a simple example. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh new file mode 100755 index 0000000..387d1a6 --- /dev/null +++ b/t/t8008-blame-formats.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='blame output in various formats on a simple case' +. ./test-lib.sh + +test_expect_success 'setup' ' + echo a >file && + git add file + test_tick && + git commit -m one && + echo b >>file && + echo c >>file && + echo d >>file && + test_tick && + git commit -a -m two +' + +cat >expect <<'EOF' +^baf5e0b (A U Thor 2005-04-07 15:13:13 -0700 1) a +8825379d (A U Thor 2005-04-07 15:14:13 -0700 2) b +8825379d (A U Thor 2005-04-07 15:14:13 -0700 3) c +8825379d (A U Thor 2005-04-07 15:14:13 -0700 4) d +EOF +test_expect_success 'normal blame output' ' + git blame file >actual && + test_cmp expect actual +' + +ID1=baf5e0b3869e0b2b2beb395a3720c7b51eac94fc +COMMIT1='author A U Thor +author-mail +author-time 1112911993 +author-tz -0700 +committer C O Mitter +committer-mail +committer-time 1112911993 +committer-tz -0700 +summary one +boundary +filename file' +ID2=8825379dfb8a1267b58e8e5bcf69eec838f685ec +COMMIT2='author A U Thor +author-mail +author-time 1112912053 +author-tz -0700 +committer C O Mitter +committer-mail +committer-time 1112912053 +committer-tz -0700 +summary two +previous baf5e0b3869e0b2b2beb395a3720c7b51eac94fc file +filename file' + +cat >expect <actual && + test_cmp expect actual +' + +test_done -- cgit v0.10.2-6-g49f6 From e86226e34097ce22ed78a9e759564110f141dda0 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 9 May 2011 09:34:02 -0400 Subject: blame: refactor porcelain output This is in preparation for adding more porcelain output options. The three changes are: 1. emit_porcelain now receives the format option flags 2. emit_one_suspect_detail takes an optional "repeat" parameter to suppress the "show only once" behavior 3. The code for emitting porcelain suspect is factored into its own function for repeatability. There should be no functional changes. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/blame.c b/builtin/blame.c index 4242e4b..1a45463 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1484,13 +1484,14 @@ static void write_filename_info(const char *path) /* * Porcelain/Incremental format wants to show a lot of details per * commit. Instead of repeating this every line, emit it only once, - * the first time each commit appears in the output. + * the first time each commit appears in the output (unless the + * user has specifically asked for us to repeat). */ -static int emit_one_suspect_detail(struct origin *suspect) +static int emit_one_suspect_detail(struct origin *suspect, int repeat) { struct commit_info ci; - if (suspect->commit->object.flags & METAINFO_SHOWN) + if (!repeat && (suspect->commit->object.flags & METAINFO_SHOWN)) return 0; suspect->commit->object.flags |= METAINFO_SHOWN; @@ -1529,7 +1530,7 @@ static void found_guilty_entry(struct blame_entry *ent) printf("%s %d %d %d\n", sha1_to_hex(suspect->commit->object.sha1), ent->s_lno + 1, ent->lno + 1, ent->num_lines); - emit_one_suspect_detail(suspect); + emit_one_suspect_detail(suspect, 0); write_filename_info(suspect->path); maybe_flush_or_die(stdout, "stdout"); } @@ -1619,7 +1620,15 @@ static const char *format_time(unsigned long time, const char *tz_str, #define OUTPUT_NO_AUTHOR 0200 #define OUTPUT_SHOW_EMAIL 0400 -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) +static void emit_porcelain_details(struct origin *suspect, int repeat) +{ + if (emit_one_suspect_detail(suspect, repeat) || + (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) + write_filename_info(suspect->path); +} + +static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, + int opt) { int cnt; const char *cp; @@ -1633,9 +1642,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) ent->s_lno + 1, ent->lno + 1, ent->num_lines); - if (emit_one_suspect_detail(suspect) || - (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) - write_filename_info(suspect->path); + emit_porcelain_details(suspect, 0); cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { @@ -1756,7 +1763,7 @@ static void output(struct scoreboard *sb, int option) for (ent = sb->ent; ent; ent = ent->next) { if (option & OUTPUT_PORCELAIN) - emit_porcelain(sb, ent); + emit_porcelain(sb, ent, option); else { emit_other(sb, ent, option); } -- cgit v0.10.2-6-g49f6 From ed747dd5216ba1fe6fa59da9585dcd6cced202bb Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 9 May 2011 09:34:42 -0400 Subject: 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 Signed-off-by: Junio C Hamano diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 16e3c68..e76195a 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -52,6 +52,11 @@ of lines before or after the line given by . --porcelain:: Show in a format designed for machine consumption. +--line-porcelain:: + Show the porcelain format, but output commit information for + each line, not just the first time a commit is referenced. + Implies --porcelain. + --incremental:: Show the result incrementally in a format designed for machine consumption. diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index bb8edb4..9516914 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -105,6 +105,19 @@ The contents of the actual line is output after the above header, prefixed by a TAB. This is to allow adding more 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: + + # count the number of lines attributed to each author + git blame --line-porcelain file | + sed -n 's/^author //p' | + sort | uniq -c | sort -rn + SPECIFYING RANGES ----------------- diff --git a/builtin/blame.c b/builtin/blame.c index 1a45463..26a5d42 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1619,6 +1619,7 @@ static const char *format_time(unsigned long time, const char *tz_str, #define OUTPUT_SHOW_SCORE 0100 #define OUTPUT_NO_AUTHOR 0200 #define OUTPUT_SHOW_EMAIL 0400 +#define OUTPUT_LINE_PORCELAIN 01000 static void emit_porcelain_details(struct origin *suspect, int repeat) { @@ -1630,6 +1631,7 @@ static void emit_porcelain_details(struct origin *suspect, int repeat) static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, int opt) { + int repeat = opt & OUTPUT_LINE_PORCELAIN; int cnt; const char *cp; struct origin *suspect = ent->suspect; @@ -1642,15 +1644,18 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, ent->s_lno + 1, ent->lno + 1, ent->num_lines); - emit_porcelain_details(suspect, 0); + emit_porcelain_details(suspect, repeat); cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; - if (cnt) + if (cnt) { printf("%s %d %d\n", hex, ent->s_lno + 1 + cnt, ent->lno + 1 + cnt); + if (repeat) + emit_porcelain_details(suspect, 1); + } putchar('\t'); do { ch = *cp++; @@ -2307,6 +2312,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME), OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER), OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN), + OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN), OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT), OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP), OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME), diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh index 387d1a6..d15f8b3 100755 --- a/t/t8008-blame-formats.sh +++ b/t/t8008-blame-formats.sh @@ -68,4 +68,23 @@ test_expect_success 'blame --porcelain output' ' test_cmp expect actual ' +cat >expect <actual && + test_cmp expect actual +' + test_done -- cgit v0.10.2-6-g49f6