Skip to content

Commit a58a8e3

Browse files
committed
Merge branch 'jk/push-progress'
"git push" and "git clone" learned to give better progress meters to the end user who is waiting on the terminal. * jk/push-progress: receive-pack: send keepalives during quiet periods receive-pack: turn on connectivity progress receive-pack: relay connectivity errors to sideband receive-pack: turn on index-pack resolving progress index-pack: add flag for showing delta-resolution progress clone: use a real progress meter for connectivity check check_connected: add progress flag check_connected: relay errors to alternate descriptor check_everything_connected: use a struct with named options check_everything_connected: convert to argv_array rev-list: add optional progress reporting check_everything_connected: always pass --quiet to rev-list
2 parents 67b3a5d + 8355868 commit a58a8e3

File tree

9 files changed

+202
-64
lines changed

9 files changed

+202
-64
lines changed

Documentation/config.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,15 @@ receive.fsck.skipList::
24882488
can be safely ignored such as invalid committer email addresses.
24892489
Note: corrupt objects cannot be skipped with this setting.
24902490

2491+
receive.keepAlive::
2492+
After receiving the pack from the client, `receive-pack` may
2493+
produce no output (if `--quiet` was specified) while processing
2494+
the pack, causing some networks to drop the TCP connection.
2495+
With this option set, if `receive-pack` does not transmit
2496+
any data in this phase for `receive.keepAlive` seconds, it will
2497+
send a short keepalive packet. The default is 5 seconds; set
2498+
to 0 to disable keepalives entirely.
2499+
24912500
receive.unpackLimit::
24922501
If the number of objects received in a push is below this
24932502
limit then the objects will be unpacked into loose object

Documentation/rev-list-options.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ ifdef::git-rev-list[]
274274
Try to speed up the traversal using the pack bitmap index (if
275275
one is available). Note that when traversing with `--objects`,
276276
trees and blobs will not have their associated path printed.
277+
278+
--progress=<header>::
279+
Show progress reports on stderr as objects are considered. The
280+
`<header>` text will be printed with each progress update.
277281
endif::git-rev-list[]
278282

279283
--

builtin/clone.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -624,13 +624,13 @@ static void update_remote_refs(const struct ref *refs,
624624
const struct ref *rm = mapped_refs;
625625

626626
if (check_connectivity) {
627-
if (transport->progress)
628-
fprintf(stderr, _("Checking connectivity... "));
629-
if (check_everything_connected_with_transport(iterate_ref_map,
630-
0, &rm, transport))
627+
struct check_connected_options opt = CHECK_CONNECTED_INIT;
628+
629+
opt.transport = transport;
630+
opt.progress = transport->progress;
631+
632+
if (check_connected(iterate_ref_map, &rm, &opt))
631633
die(_("remote did not send all necessary objects"));
632-
if (transport->progress)
633-
fprintf(stderr, _("done.\n"));
634634
}
635635

636636
if (refs) {

builtin/fetch.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
729729
url = xstrdup("foreign");
730730

731731
rm = ref_map;
732-
if (check_everything_connected(iterate_ref_map, 0, &rm)) {
732+
if (check_connected(iterate_ref_map, &rm, NULL)) {
733733
rc = error(_("%s did not send all necessary objects\n"), url);
734734
goto abort;
735735
}
@@ -866,6 +866,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
866866
static int quickfetch(struct ref *ref_map)
867867
{
868868
struct ref *rm = ref_map;
869+
struct check_connected_options opt = CHECK_CONNECTED_INIT;
869870

870871
/*
871872
* If we are deepening a shallow clone we already have these
@@ -876,7 +877,8 @@ static int quickfetch(struct ref *ref_map)
876877
*/
877878
if (depth)
878879
return -1;
879-
return check_everything_connected(iterate_ref_map, 1, &rm);
880+
opt.quiet = 1;
881+
return check_connected(iterate_ref_map, &rm, &opt);
880882
}
881883

882884
static int fetch_refs(struct transport *transport, struct ref *ref_map)

builtin/index-pack.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ static int strict;
7777
static int do_fsck_object;
7878
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
7979
static int verbose;
80+
static int show_resolving_progress;
8081
static int show_stat;
8182
static int check_self_contained_and_connected;
8283

@@ -1191,7 +1192,7 @@ static void resolve_deltas(void)
11911192
qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry),
11921193
compare_ref_delta_entry);
11931194

1194-
if (verbose)
1195+
if (verbose || show_resolving_progress)
11951196
progress = start_progress(_("Resolving deltas"),
11961197
nr_ref_deltas + nr_ofs_deltas);
11971198

@@ -1626,6 +1627,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
16261627
struct pack_idx_option opts;
16271628
unsigned char pack_sha1[20];
16281629
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
1630+
int report_end_of_input = 0;
16291631

16301632
if (argc == 2 && !strcmp(argv[1], "-h"))
16311633
usage(index_pack_usage);
@@ -1695,6 +1697,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
16951697
input_len = sizeof(*hdr);
16961698
} else if (!strcmp(arg, "-v")) {
16971699
verbose = 1;
1700+
} else if (!strcmp(arg, "--show-resolving-progress")) {
1701+
show_resolving_progress = 1;
1702+
} else if (!strcmp(arg, "--report-end-of-input")) {
1703+
report_end_of_input = 1;
16981704
} else if (!strcmp(arg, "-o")) {
16991705
if (index_name || (i+1) >= argc)
17001706
usage(index_pack_usage);
@@ -1752,6 +1758,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
17521758
obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
17531759
ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
17541760
parse_pack_objects(pack_sha1);
1761+
if (report_end_of_input)
1762+
write_in_full(2, "\0", 1);
17551763
resolve_deltas();
17561764
conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
17571765
free(ofs_deltas);

builtin/receive-pack.c

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ static long nonce_stamp_slop;
7878
static unsigned long nonce_stamp_slop_limit;
7979
static struct ref_transaction *transaction;
8080

81+
static enum {
82+
KEEPALIVE_NEVER = 0,
83+
KEEPALIVE_AFTER_NUL,
84+
KEEPALIVE_ALWAYS
85+
} use_keepalive;
86+
static int keepalive_in_sec = 5;
87+
8188
static enum deny_action parse_deny_action(const char *var, const char *value)
8289
{
8390
if (value) {
@@ -200,6 +207,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
200207
return 0;
201208
}
202209

210+
if (strcmp(var, "receive.keepalive") == 0) {
211+
keepalive_in_sec = git_config_int(var, value);
212+
return 0;
213+
}
214+
203215
return git_default_config(var, value, cb);
204216
}
205217

@@ -328,10 +340,60 @@ static void rp_error(const char *err, ...)
328340
static int copy_to_sideband(int in, int out, void *arg)
329341
{
330342
char data[128];
343+
int keepalive_active = 0;
344+
345+
if (keepalive_in_sec <= 0)
346+
use_keepalive = KEEPALIVE_NEVER;
347+
if (use_keepalive == KEEPALIVE_ALWAYS)
348+
keepalive_active = 1;
349+
331350
while (1) {
332-
ssize_t sz = xread(in, data, sizeof(data));
351+
ssize_t sz;
352+
353+
if (keepalive_active) {
354+
struct pollfd pfd;
355+
int ret;
356+
357+
pfd.fd = in;
358+
pfd.events = POLLIN;
359+
ret = poll(&pfd, 1, 1000 * keepalive_in_sec);
360+
361+
if (ret < 0) {
362+
if (errno == EINTR)
363+
continue;
364+
else
365+
break;
366+
} else if (ret == 0) {
367+
/* no data; send a keepalive packet */
368+
static const char buf[] = "0005\1";
369+
write_or_die(1, buf, sizeof(buf) - 1);
370+
continue;
371+
} /* else there is actual data to read */
372+
}
373+
374+
sz = xread(in, data, sizeof(data));
333375
if (sz <= 0)
334376
break;
377+
378+
if (use_keepalive == KEEPALIVE_AFTER_NUL && !keepalive_active) {
379+
const char *p = memchr(data, '\0', sz);
380+
if (p) {
381+
/*
382+
* The NUL tells us to start sending keepalives. Make
383+
* sure we send any other data we read along
384+
* with it.
385+
*/
386+
keepalive_active = 1;
387+
send_sideband(1, 2, data, p - data, use_sideband);
388+
send_sideband(1, 2, p + 1, sz - (p - data + 1), use_sideband);
389+
continue;
390+
}
391+
}
392+
393+
/*
394+
* Either we're not looking for a NUL signal, or we didn't see
395+
* it yet; just pass along the data.
396+
*/
335397
send_sideband(1, 2, data, sz, use_sideband);
336398
}
337399
close(in);
@@ -761,7 +823,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
761823
{
762824
static struct lock_file shallow_lock;
763825
struct sha1_array extra = SHA1_ARRAY_INIT;
764-
const char *alt_file;
826+
struct check_connected_options opt = CHECK_CONNECTED_INIT;
765827
uint32_t mask = 1 << (cmd->index % 32);
766828
int i;
767829

@@ -773,9 +835,8 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
773835
!delayed_reachability_test(si, i))
774836
sha1_array_append(&extra, si->shallow->sha1[i]);
775837

776-
setup_alternate_shallow(&shallow_lock, &alt_file, &extra);
777-
if (check_shallow_connected(command_singleton_iterator,
778-
0, cmd, alt_file)) {
838+
setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
839+
if (check_connected(command_singleton_iterator, cmd, &opt)) {
779840
rollback_lock_file(&shallow_lock);
780841
sha1_array_clear(&extra);
781842
return -1;
@@ -1184,8 +1245,8 @@ static void set_connectivity_errors(struct command *commands,
11841245
if (shallow_update && si->shallow_ref[cmd->index])
11851246
/* to be checked in update_shallow_ref() */
11861247
continue;
1187-
if (!check_everything_connected(command_singleton_iterator,
1188-
0, &singleton))
1248+
if (!check_connected(command_singleton_iterator, &singleton,
1249+
NULL))
11891250
continue;
11901251
cmd->error_string = "missing necessary objects";
11911252
}
@@ -1343,21 +1404,38 @@ static void execute_commands(struct command *commands,
13431404
struct shallow_info *si,
13441405
const struct string_list *push_options)
13451406
{
1407+
struct check_connected_options opt = CHECK_CONNECTED_INIT;
13461408
struct command *cmd;
13471409
unsigned char sha1[20];
13481410
struct iterate_data data;
1411+
struct async muxer;
1412+
int err_fd = 0;
13491413

13501414
if (unpacker_error) {
13511415
for (cmd = commands; cmd; cmd = cmd->next)
13521416
cmd->error_string = "unpacker error";
13531417
return;
13541418
}
13551419

1420+
if (use_sideband) {
1421+
memset(&muxer, 0, sizeof(muxer));
1422+
muxer.proc = copy_to_sideband;
1423+
muxer.in = -1;
1424+
if (!start_async(&muxer))
1425+
err_fd = muxer.in;
1426+
/* ...else, continue without relaying sideband */
1427+
}
1428+
13561429
data.cmds = commands;
13571430
data.si = si;
1358-
if (check_everything_connected(iterate_receive_command_list, 0, &data))
1431+
opt.err_fd = err_fd;
1432+
opt.progress = err_fd && !quiet;
1433+
if (check_connected(iterate_receive_command_list, &data, &opt))
13591434
set_connectivity_errors(commands, si);
13601435

1436+
if (use_sideband)
1437+
finish_async(&muxer);
1438+
13611439
reject_updates_to_hidden(commands);
13621440

13631441
if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
@@ -1591,6 +1669,10 @@ static const char *unpack(int err_fd, struct shallow_info *si)
15911669
(uintmax_t)getpid(),
15921670
hostname);
15931671

1672+
if (!quiet && err_fd)
1673+
argv_array_push(&child.args, "--show-resolving-progress");
1674+
if (use_sideband)
1675+
argv_array_push(&child.args, "--report-end-of-input");
15941676
if (fsck_objects)
15951677
argv_array_pushf(&child.args, "--strict%s",
15961678
fsck_msg_types.buf);
@@ -1620,6 +1702,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
16201702
if (!use_sideband)
16211703
return unpack(0, si);
16221704

1705+
use_keepalive = KEEPALIVE_AFTER_NUL;
16231706
memset(&muxer, 0, sizeof(muxer));
16241707
muxer.proc = copy_to_sideband;
16251708
muxer.in = -1;
@@ -1811,6 +1894,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
18111894
unpack_status = unpack_with_sideband(&si);
18121895
update_shallow_info(commands, &si, &ref);
18131896
}
1897+
use_keepalive = KEEPALIVE_ALWAYS;
18141898
execute_commands(commands, unpack_status, &si,
18151899
&push_options);
18161900
if (pack_lockfile)

builtin/rev-list.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "log-tree.h"
1010
#include "graph.h"
1111
#include "bisect.h"
12+
#include "progress.h"
1213

1314
static const char rev_list_usage[] =
1415
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -49,12 +50,17 @@ static const char rev_list_usage[] =
4950
" --bisect-all"
5051
;
5152

53+
static struct progress *progress;
54+
static unsigned progress_counter;
55+
5256
static void finish_commit(struct commit *commit, void *data);
5357
static void show_commit(struct commit *commit, void *data)
5458
{
5559
struct rev_list_info *info = data;
5660
struct rev_info *revs = info->revs;
5761

62+
display_progress(progress, ++progress_counter);
63+
5864
if (info->flags & REV_LIST_QUIET) {
5965
finish_commit(commit, data);
6066
return;
@@ -190,6 +196,7 @@ static void show_object(struct object *obj, const char *name, void *cb_data)
190196
{
191197
struct rev_list_info *info = cb_data;
192198
finish_object(obj, name, cb_data);
199+
display_progress(progress, ++progress_counter);
193200
if (info->flags & REV_LIST_QUIET)
194201
return;
195202
show_object_with_name(stdout, obj, name);
@@ -276,6 +283,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
276283
int bisect_show_vars = 0;
277284
int bisect_find_all = 0;
278285
int use_bitmap_index = 0;
286+
const char *show_progress = NULL;
279287

280288
git_config(git_default_config, NULL);
281289
init_revisions(&revs, prefix);
@@ -325,6 +333,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
325333
test_bitmap_walk(&revs);
326334
return 0;
327335
}
336+
if (skip_prefix(arg, "--progress=", &arg)) {
337+
show_progress = arg;
338+
continue;
339+
}
328340
usage(rev_list_usage);
329341

330342
}
@@ -355,6 +367,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
355367
if (bisect_list)
356368
revs.limited = 1;
357369

370+
if (show_progress)
371+
progress = start_progress_delay(show_progress, 0, 0, 2);
372+
358373
if (use_bitmap_index && !revs.prune) {
359374
if (revs.count && !revs.left_right && !revs.cherry_mark) {
360375
uint32_t commit_count;
@@ -392,6 +407,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
392407

393408
traverse_commit_list(&revs, show_commit, show_object, &info);
394409

410+
stop_progress(&progress);
411+
395412
if (revs.count) {
396413
if (revs.left_right && revs.cherry_mark)
397414
printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);

0 commit comments

Comments
 (0)