status: warn when a/b calculation takes too long

The ahead/behind calculation in 'git status' can be slow in some cases. Users may not realize that there are ways to avoid this computation, especially if they are not using the information. Add a warning that appears if this calculation takes more than two seconds. The warning can be disabled through the new config setting advice.statusAheadBehind. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Jun 18, 2019 at 13:21 UTC 0a53561a6221f989b210797e62e83fb7260fa42c
4 files changed +26
Documentation/config/advice.txt
+6
@@ -37,6 +37,12 @@ advice.*::
37 we can still suggest that the user push to either
38 refs/heads/* or refs/tags/* based on the type of the
39 source object.
40 + statusAheadBehind::
41 + Shown when linkgit:git-status[1] computes the ahead/behind
42 + counts for a local ref compared to its remote tracking ref,
43 + and that calculation takes longer than expected. Will not
44 + appear if `status.aheadBehind` is false or the option
45 + `--no-ahead-behind` is given.
46 statusHints::
47 Show directions on how to proceed from the current
48 state in the output of linkgit:git-status[1], in
advice.c
+2
@@ -12,6 +12,7 @@ int advice_push_needs_force = 1;
12 int advice_push_unqualified_ref_name = 1;
13 int advice_status_hints = 1;
14 int advice_status_u_option = 1;
15 +int advice_status_ahead_behind_warning = 1;
16 int advice_commit_before_merge = 1;
17 int advice_reset_quiet_warning = 1;
18 int advice_resolve_conflict = 1;
@@ -68,6 +69,7 @@ static struct {
69 { "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
70 { "statusHints", &advice_status_hints },
71 { "statusUoption", &advice_status_u_option },
72 + { "statusAheadBehindWarning", &advice_status_ahead_behind_warning },
73 { "commitBeforeMerge", &advice_commit_before_merge },
74 { "resetQuiet", &advice_reset_quiet_warning },
75 { "resolveConflict", &advice_resolve_conflict },
advice.h
+1
@@ -12,6 +12,7 @@ extern int advice_push_needs_force;
12 extern int advice_push_unqualified_ref_name;
13 extern int advice_status_hints;
14 extern int advice_status_u_option;
15 +extern int advice_status_ahead_behind_warning;
16 extern int advice_commit_before_merge;
17 extern int advice_reset_quiet_warning;
18 extern int advice_resolve_conflict;
wt-status.c
+17
@@ -19,6 +19,8 @@
19 #include "lockfile.h"
20 #include "sequencer.h"
21
22 +#define AB_DELAY_WARNING_IN_MS (2 * 1000)
23 +
24 static const char cut_line[] =
25 "------------------------ >8 ------------------------\n";
26
@@ -1085,14 +1087,29 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
1087 struct branch *branch;
1088 char comment_line_string[3];
1089 int i;
1090 + uint64_t t_begin = 0;
1091
1092 assert(s->branch && !s->is_initial);
1093 if (!skip_prefix(s->branch, "refs/heads/", &branch_name))
1094 return;
1095 branch = branch_get(branch_name);
1096 +
1097 + t_begin = getnanotime();
1098 +
1099 if (!format_tracking_info(branch, &sb, s->ahead_behind_flags))
1100 return;
1101
1102 + if (advice_status_ahead_behind_warning &&
1103 + s->ahead_behind_flags == AHEAD_BEHIND_FULL) {
1104 + uint64_t t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
1105 + if (t_delta_in_ms > AB_DELAY_WARNING_IN_MS) {
1106 + strbuf_addf(&sb, _("\n"
1107 + "It took %.2f seconds to compute the branch ahead/behind values.\n"
1108 + "You can use '--no-ahead-behind' to avoid this.\n"),
1109 + t_delta_in_ms / 1000.0);
1110 + }
1111 + }
1112 +
1113 i = 0;
1114 if (s->display_comment_prefix) {
1115 comment_line_string[i++] = comment_line_char;