progress: pay attention to (customized) delay time

Using one of the start_delayed_*() functions, clients of the progress API can request that a progress meter is only shown after some time. To do that, the implementation intends to count down the number of seconds stored in struct progress by observing flag progress_update, which the timer interrupt handler sets when a second has elapsed. This works during the first second of the delay. But the code forgets to reset the flag to zero, so that subsequent calls of display_progress() think that another second has elapsed and decrease the count again until zero is reached. Due to the frequency of the calls, this happens without an observable delay in practice, so that the effective delay is always just one second. This bug has been with us since the inception of the feature. Despite having been touched on various occasions, such as 8aade107dd84 (progress: simplify "delayed" progress API), 9c5951cacf5c (progress: drop delay-threshold code), and 44a4693bfcec (progress: create GIT_PROGRESS_DELAY), the short delay went unnoticed. Copy the flag state into a local variable and reset the global flag right away so that we can detect the next clock tick correctly. Since we have not had any complaints that the delay of one second is too short nor that GIT_PROGRESS_DELAY is ignored, people seem to be comfortable with the status quo. Therefore, set the default to 1 to keep the current behavior. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Sixt committed Aug 25, 2025 at 21:16 UTC 457534d0417d047b943f76a849f256b739894ce9
2 files changed +8 -6
Documentation/git.adoc
+1 -1
@@ -684,7 +684,7 @@ other
684
685 `GIT_PROGRESS_DELAY`::
686 A number controlling how many seconds to delay before showing
687 - optional progress indicators. Defaults to 2.
687 + optional progress indicators. Defaults to 1.
688
689 `GIT_EDITOR`::
690 This environment variable overrides `$EDITOR` and `$VISUAL`.
progress.c
+7 -5
@@ -114,16 +114,19 @@ static void display(struct progress *progress, uint64_t n, const char *done)
114 const char *tp;
115 struct strbuf *counters_sb = &progress->counters_sb;
116 int show_update = 0;
117 + int update = !!progress_update;
118 int last_count_len = counters_sb->len;
119
119 - if (progress->delay && (!progress_update || --progress->delay))
120 + progress_update = 0;
121 +
122 + if (progress->delay && (!update || --progress->delay))
123 return;
124
125 progress->last_value = n;
126 tp = (progress->throughput) ? progress->throughput->display.buf : "";
127 if (progress->total) {
128 unsigned percent = n * 100 / progress->total;
126 - if (percent != progress->last_percent || progress_update) {
129 + if (percent != progress->last_percent || update) {
130 progress->last_percent = percent;
131
132 strbuf_reset(counters_sb);
@@ -133,7 +136,7 @@ static void display(struct progress *progress, uint64_t n, const char *done)
136 tp);
137 show_update = 1;
138 }
136 - } else if (progress_update) {
139 + } else if (update) {
140 strbuf_reset(counters_sb);
141 strbuf_addf(counters_sb, "%"PRIuMAX"%s", (uintmax_t)n, tp);
142 show_update = 1;
@@ -166,7 +169,6 @@ static void display(struct progress *progress, uint64_t n, const char *done)
169 }
170 fflush(stderr);
171 }
169 - progress_update = 0;
172 }
173 }
174
@@ -281,7 +283,7 @@ static int get_default_delay(void)
283 static int delay_in_secs = -1;
284
285 if (delay_in_secs < 0)
284 - delay_in_secs = git_env_ulong("GIT_PROGRESS_DELAY", 2);
286 + delay_in_secs = git_env_ulong("GIT_PROGRESS_DELAY", 1);
287
288 return delay_in_secs;
289 }