blame: add support for --[no-]progress option

Teach the command to show progress output when it takes long time to produce the first line of output; this option cannot be used with "--incremental" or "--porcelain" options. git-annotate inherits the option as well. Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Edmundo Carmona Antoranz <eantoranz@gmail.com> Reviewed-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Edmundo Carmona Antoranz committed Dec 12, 2015 at 18:51 UTC aba37f495ee39aa9506a375bb4c667731df39899
3 files changed +39 -5
Documentation/blame-options.txt
+7
@@ -70,6 +70,13 @@ include::line-range-format.txt[]
70 iso format is used. For more information, See the discussion
71 of the --date option at linkgit:git-log[1].
72
73 +--[no-]progress::
74 + Progress status is reported on the standard error stream
75 + by default when it is attached to a terminal. This flag
76 + enables progress reporting even if not attached to a
77 + terminal. Can't use `--progress` together with `--porcelain`
78 + or `--incremental`.
79 +
80 -M|<num>|::
81 Detect moved or copied lines within a file. When a commit
82 moves or copies a block of lines (e.g. the original file
Documentation/git-blame.txt
+2 -1
@@ -10,7 +10,8 @@ SYNOPSIS
10 [verse]
11 'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
12 [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
13 - [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>] [--] <file>
13 + [--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>]
14 + [--] <file>
15
16 DESCRIPTION
17 -----------
builtin/blame.c
+30 -4
@@ -28,6 +28,7 @@
28 #include "line-range.h"
29 #include "line-log.h"
30 #include "dir.h"
31 +#include "progress.h"
32
33 static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
34
@@ -50,6 +51,7 @@ static int incremental;
51 static int xdl_opts;
52 static int abbrev = -1;
53 static int no_whole_file_rename;
54 +static int show_progress;
55
56 static struct date_mode blame_date_mode = { DATE_ISO8601 };
57 static size_t blame_date_width;
@@ -127,6 +129,11 @@ struct origin {
129 char path[FLEX_ARRAY];
130 };
131
132 +struct progress_info {
133 + struct progress *progress;
134 + int blamed_lines;
135 +};
136 +
137 static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
138 xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
139 {
@@ -1745,7 +1752,8 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
1752 * The blame_entry is found to be guilty for the range.
1753 * Show it in incremental output.
1754 */
1748 -static void found_guilty_entry(struct blame_entry *ent)
1755 +static void found_guilty_entry(struct blame_entry *ent,
1756 + struct progress_info *pi)
1757 {
1758 if (incremental) {
1759 struct origin *suspect = ent->suspect;
@@ -1757,6 +1765,8 @@ static void found_guilty_entry(struct blame_entry *ent)
1765 write_filename_info(suspect->path);
1766 maybe_flush_or_die(stdout, "stdout");
1767 }
1768 + pi->blamed_lines += ent->num_lines;
1769 + display_progress(pi->progress, pi->blamed_lines);
1770 }
1771
1772 /*
@@ -1767,6 +1777,11 @@ static void assign_blame(struct scoreboard *sb, int opt)
1777 {
1778 struct rev_info *revs = sb->revs;
1779 struct commit *commit = prio_queue_get(&sb->commits);
1780 + struct progress_info pi = { NULL, 0 };
1781 +
1782 + if (show_progress)
1783 + pi.progress = start_progress_delay(_("Blaming lines"),
1784 + sb->num_lines, 50, 1);
1785
1786 while (commit) {
1787 struct blame_entry *ent;
@@ -1808,7 +1823,7 @@ static void assign_blame(struct scoreboard *sb, int opt)
1823 suspect->guilty = 1;
1824 for (;;) {
1825 struct blame_entry *next = ent->next;
1811 - found_guilty_entry(ent);
1826 + found_guilty_entry(ent, &pi);
1827 if (next) {
1828 ent = next;
1829 continue;
@@ -1824,6 +1839,8 @@ static void assign_blame(struct scoreboard *sb, int opt)
1839 if (DEBUG) /* sanity */
1840 sanity_check_refcnt(sb);
1841 }
1842 +
1843 + stop_progress(&pi.progress);
1844 }
1845
1846 static const char *format_time(unsigned long time, const char *tz_str,
@@ -2513,6 +2530,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2530 OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
2531 OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
2532 OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
2533 + OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
2534 OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
2535 OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
2536 OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
@@ -2548,6 +2566,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
2566
2567 save_commit_buffer = 0;
2568 dashdash_pos = 0;
2569 + show_progress = -1;
2570
2571 parse_options_start(&ctx, argc, argv, prefix, options,
2572 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
@@ -2572,6 +2591,13 @@ parse_done:
2591 DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
2592 argc = parse_options_end(&ctx);
2593
2594 + if (incremental || (output_option & OUTPUT_PORCELAIN)) {
2595 + if (show_progress > 0)
2596 + die("--progress can't be used with --incremental or porcelain formats");
2597 + show_progress = 0;
2598 + } else if (show_progress < 0)
2599 + show_progress = isatty(2);
2600 +
2601 if (0 < abbrev)
2602 /* one more abbrev length is needed for the boundary commit */
2603 abbrev++;
@@ -2797,11 +2823,11 @@ parse_done:
2823
2824 read_mailmap(&mailmap, NULL);
2825
2826 + assign_blame(&sb, opt);
2827 +
2828 if (!incremental)
2829 setup_pager();
2830
2803 - assign_blame(&sb, opt);
2804 -
2831 free(final_commit_name);
2832
2833 if (incremental)