Skip to content

Commit da9a9fa

Browse files
committed
Merge branch 'js/fetch-jobs' into pu
* js/fetch-jobs: fetch: let --jobs=<n> parallelize --multiple, too
2 parents 023731f + 7f53b72 commit da9a9fa

File tree

4 files changed

+137
-21
lines changed

4 files changed

+137
-21
lines changed

Documentation/config/fetch.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ fetch.showForcedUpdates::
7070
linkgit:git-fetch[1] and linkgit:git-pull[1] commands.
7171
Defaults to true.
7272

73+
fetch.parallel::
74+
Specifies the maximal number of fetch operations to be run in parallel
75+
at a time (submodules, or remotes when the `--multiple` option of
76+
linkgit:git-fetch[1] is in effect).
77+
+
78+
A value of 0 will give some reasonable default. If unset, it defaults to 1.
79+
+
80+
For submodules, this setting can be overridden using the `submodule.fetchJobs`
81+
config setting.
82+
7383
fetch.writeCommitGraph::
7484
Set to true to write a commit-graph after every `git fetch` command
7585
that downloads a pack-file from a remote. Using the `--split` option,

Documentation/fetch-options.txt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,15 @@ ifndef::git-pull[]
160160

161161
-j::
162162
--jobs=<n>::
163-
Number of parallel children to be used for fetching submodules.
164-
Each will fetch from different submodules, such that fetching many
165-
submodules will be faster. By default submodules will be fetched
166-
one at a time.
163+
Number of parallel children to be used for all forms of fetching.
164+
+
165+
If the `--multiple` option was specified, the different remotes will be fetched
166+
in parallel. If multiple submodules are fetched, they will be fetched in
167+
parallel. To control them independently, use the config settings
168+
`fetch.parallel` and `submodule.fetchJobs` (see linkgit:git-config[1]).
169+
+
170+
Typically, parallel recursive and multi-remote fetches will be faster. By
171+
default fetches are performed sequentially, not in parallel.
167172

168173
--no-recurse-submodules::
169174
Disable recursive fetching of submodules (this has the same effect as

builtin/fetch.c

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ static int verbosity, deepen_relative, set_upstream;
6060
static int progress = -1;
6161
static int enable_auto_gc = 1;
6262
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
63-
static int max_children = 1;
63+
static int max_jobs = -1, submodule_fetch_jobs_config = -1;
64+
static int fetch_parallel_config = 1;
6465
static enum transport_family family;
6566
static const char *depth;
6667
static const char *deepen_since;
@@ -102,13 +103,20 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
102103
}
103104

104105
if (!strcmp(k, "submodule.fetchjobs")) {
105-
max_children = parse_submodule_fetchjobs(k, v);
106+
submodule_fetch_jobs_config = parse_submodule_fetchjobs(k, v);
106107
return 0;
107108
} else if (!strcmp(k, "fetch.recursesubmodules")) {
108109
recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
109110
return 0;
110111
}
111112

113+
if (!strcmp(k, "fetch.parallel")) {
114+
fetch_parallel_config = git_config_int(k, v);
115+
if (fetch_parallel_config < 0)
116+
die(_("fetch.parallel cannot be negative"));
117+
return 0;
118+
}
119+
112120
return git_default_config(k, v, cb);
113121
}
114122

@@ -142,7 +150,7 @@ static struct option builtin_fetch_options[] = {
142150
N_("fetch all tags and associated objects"), TAGS_SET),
143151
OPT_SET_INT('n', NULL, &tags,
144152
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
145-
OPT_INTEGER('j', "jobs", &max_children,
153+
OPT_INTEGER('j', "jobs", &max_jobs,
146154
N_("number of submodules fetched in parallel")),
147155
OPT_BOOL('p', "prune", &prune,
148156
N_("prune remote-tracking branches no longer on remote")),
@@ -1526,7 +1534,62 @@ static void add_options_to_argv(struct argv_array *argv)
15261534

15271535
}
15281536

1529-
static int fetch_multiple(struct string_list *list)
1537+
/* Fetch multiple remotes in parallel */
1538+
1539+
struct parallel_fetch_state {
1540+
const char **argv;
1541+
struct string_list *remotes;
1542+
int next, result;
1543+
};
1544+
1545+
static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
1546+
void *cb, void **task_cb)
1547+
{
1548+
struct parallel_fetch_state *state = cb;
1549+
char *remote;
1550+
1551+
if (state->next < 0 || state->next >= state->remotes->nr)
1552+
return 0;
1553+
1554+
remote = state->remotes->items[state->next++].string;
1555+
*task_cb = remote;
1556+
1557+
argv_array_pushv(&cp->args, state->argv);
1558+
argv_array_push(&cp->args, remote);
1559+
cp->git_cmd = 1;
1560+
1561+
if (verbosity >= 0)
1562+
printf(_("Fetching %s\n"), remote);
1563+
1564+
return 1;
1565+
}
1566+
1567+
static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
1568+
{
1569+
struct parallel_fetch_state *state = cb;
1570+
const char *remote = task_cb;
1571+
1572+
state->result = error(_("Could not fetch %s"), remote);
1573+
1574+
return 0;
1575+
}
1576+
1577+
static int fetch_finished(int result, struct strbuf *out,
1578+
void *cb, void *task_cb)
1579+
{
1580+
struct parallel_fetch_state *state = cb;
1581+
const char *remote = task_cb;
1582+
1583+
if (result) {
1584+
strbuf_addf(out, _("could not fetch '%s' (exit code: %d)\n"),
1585+
remote, result);
1586+
state->result = -1;
1587+
}
1588+
1589+
return 0;
1590+
}
1591+
1592+
static int fetch_multiple(struct string_list *list, int max_children)
15301593
{
15311594
int i, result = 0;
15321595
struct argv_array argv = ARGV_ARRAY_INIT;
@@ -1540,20 +1603,34 @@ static int fetch_multiple(struct string_list *list)
15401603
argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc", NULL);
15411604
add_options_to_argv(&argv);
15421605

1543-
for (i = 0; i < list->nr; i++) {
1544-
const char *name = list->items[i].string;
1545-
argv_array_push(&argv, name);
1546-
if (verbosity >= 0)
1547-
printf(_("Fetching %s\n"), name);
1548-
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
1549-
error(_("Could not fetch %s"), name);
1550-
result = 1;
1606+
if (max_children != 1 && list->nr != 1) {
1607+
struct parallel_fetch_state state = { argv.argv, list, 0, 0 };
1608+
1609+
argv_array_push(&argv, "--end-of-options");
1610+
result = run_processes_parallel_tr2(max_children,
1611+
&fetch_next_remote,
1612+
&fetch_failed_to_start,
1613+
&fetch_finished,
1614+
&state,
1615+
"fetch", "parallel/fetch");
1616+
1617+
if (!result)
1618+
result = state.result;
1619+
} else
1620+
for (i = 0; i < list->nr; i++) {
1621+
const char *name = list->items[i].string;
1622+
argv_array_push(&argv, name);
1623+
if (verbosity >= 0)
1624+
printf(_("Fetching %s\n"), name);
1625+
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
1626+
error(_("Could not fetch %s"), name);
1627+
result = 1;
1628+
}
1629+
argv_array_pop(&argv);
15511630
}
1552-
argv_array_pop(&argv);
1553-
}
15541631

15551632
argv_array_clear(&argv);
1556-
return result;
1633+
return !!result;
15571634
}
15581635

15591636
/*
@@ -1690,7 +1767,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
16901767
for (i = 1; i < argc; i++)
16911768
strbuf_addf(&default_rla, " %s", argv[i]);
16921769

1693-
fetch_config_from_gitmodules(&max_children, &recurse_submodules);
1770+
fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
1771+
&recurse_submodules);
16941772
git_config(git_fetch_config, NULL);
16951773

16961774
argc = parse_options(argc, argv, prefix,
@@ -1756,15 +1834,27 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
17561834
fetch_one_setup_partial(remote);
17571835
result = fetch_one(remote, argc, argv, prune_tags_ok);
17581836
} else {
1837+
int max_children = max_jobs;
1838+
17591839
if (filter_options.choice)
17601840
die(_("--filter can only be used with the remote "
17611841
"configured in extensions.partialclone"));
1842+
1843+
if (max_children < 0)
1844+
max_children = fetch_parallel_config;
1845+
17621846
/* TODO should this also die if we have a previous partial-clone? */
1763-
result = fetch_multiple(&list);
1847+
result = fetch_multiple(&list, max_children);
17641848
}
17651849

17661850
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
17671851
struct argv_array options = ARGV_ARRAY_INIT;
1852+
int max_children = max_jobs;
1853+
1854+
if (max_children < 0)
1855+
max_children = submodule_fetch_jobs_config;
1856+
if (max_children < 0)
1857+
max_children = fetch_parallel_config;
17681858

17691859
add_options_to_argv(&options);
17701860
result = fetch_populated_submodules(the_repository,

t/t5514-fetch-multiple.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,15 @@ test_expect_success 'git fetch --all --tags' '
183183
test_cmp expect test8/output
184184
'
185185

186+
test_expect_success 'parallel' '
187+
git remote add one ./bogus1 &&
188+
git remote add two ./bogus2 &&
189+
190+
test_must_fail env GIT_TRACE="$PWD/trace" \
191+
git fetch --jobs=2 --multiple one two 2>err &&
192+
grep "2 tasks" trace &&
193+
grep "one.*128" err &&
194+
grep "two.*128" err
195+
'
196+
186197
test_done

0 commit comments

Comments
 (0)