Skip to content

Commit d96e31e

Browse files
committed
Merge branch 'js/fetch-jobs'
"git fetch --jobs=<n>" allowed <n> parallel jobs when fetching submodules, but this did not apply to "git fetch --multiple" that fetches from multiple remote repositories. It now does. * js/fetch-jobs: fetch: let --jobs=<n> parallelize --multiple, too
2 parents 280bd44 + d54dea7 commit d96e31e

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
@@ -59,7 +59,8 @@ static int verbosity, deepen_relative, set_upstream;
5959
static int progress = -1;
6060
static int enable_auto_gc = 1;
6161
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
62-
static int max_children = 1;
62+
static int max_jobs = -1, submodule_fetch_jobs_config = -1;
63+
static int fetch_parallel_config = 1;
6364
static enum transport_family family;
6465
static const char *depth;
6566
static const char *deepen_since;
@@ -101,13 +102,20 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
101102
}
102103

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

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

@@ -141,7 +149,7 @@ static struct option builtin_fetch_options[] = {
141149
N_("fetch all tags and associated objects"), TAGS_SET),
142150
OPT_SET_INT('n', NULL, &tags,
143151
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
144-
OPT_INTEGER('j', "jobs", &max_children,
152+
OPT_INTEGER('j', "jobs", &max_jobs,
145153
N_("number of submodules fetched in parallel")),
146154
OPT_BOOL('p', "prune", &prune,
147155
N_("prune remote-tracking branches no longer on remote")),
@@ -1513,7 +1521,62 @@ static void add_options_to_argv(struct argv_array *argv)
15131521

15141522
}
15151523

1516-
static int fetch_multiple(struct string_list *list)
1524+
/* Fetch multiple remotes in parallel */
1525+
1526+
struct parallel_fetch_state {
1527+
const char **argv;
1528+
struct string_list *remotes;
1529+
int next, result;
1530+
};
1531+
1532+
static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
1533+
void *cb, void **task_cb)
1534+
{
1535+
struct parallel_fetch_state *state = cb;
1536+
char *remote;
1537+
1538+
if (state->next < 0 || state->next >= state->remotes->nr)
1539+
return 0;
1540+
1541+
remote = state->remotes->items[state->next++].string;
1542+
*task_cb = remote;
1543+
1544+
argv_array_pushv(&cp->args, state->argv);
1545+
argv_array_push(&cp->args, remote);
1546+
cp->git_cmd = 1;
1547+
1548+
if (verbosity >= 0)
1549+
printf(_("Fetching %s\n"), remote);
1550+
1551+
return 1;
1552+
}
1553+
1554+
static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
1555+
{
1556+
struct parallel_fetch_state *state = cb;
1557+
const char *remote = task_cb;
1558+
1559+
state->result = error(_("Could not fetch %s"), remote);
1560+
1561+
return 0;
1562+
}
1563+
1564+
static int fetch_finished(int result, struct strbuf *out,
1565+
void *cb, void *task_cb)
1566+
{
1567+
struct parallel_fetch_state *state = cb;
1568+
const char *remote = task_cb;
1569+
1570+
if (result) {
1571+
strbuf_addf(out, _("could not fetch '%s' (exit code: %d)\n"),
1572+
remote, result);
1573+
state->result = -1;
1574+
}
1575+
1576+
return 0;
1577+
}
1578+
1579+
static int fetch_multiple(struct string_list *list, int max_children)
15171580
{
15181581
int i, result = 0;
15191582
struct argv_array argv = ARGV_ARRAY_INIT;
@@ -1527,20 +1590,34 @@ static int fetch_multiple(struct string_list *list)
15271590
argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc", NULL);
15281591
add_options_to_argv(&argv);
15291592

1530-
for (i = 0; i < list->nr; i++) {
1531-
const char *name = list->items[i].string;
1532-
argv_array_push(&argv, name);
1533-
if (verbosity >= 0)
1534-
printf(_("Fetching %s\n"), name);
1535-
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
1536-
error(_("Could not fetch %s"), name);
1537-
result = 1;
1593+
if (max_children != 1 && list->nr != 1) {
1594+
struct parallel_fetch_state state = { argv.argv, list, 0, 0 };
1595+
1596+
argv_array_push(&argv, "--end-of-options");
1597+
result = run_processes_parallel_tr2(max_children,
1598+
&fetch_next_remote,
1599+
&fetch_failed_to_start,
1600+
&fetch_finished,
1601+
&state,
1602+
"fetch", "parallel/fetch");
1603+
1604+
if (!result)
1605+
result = state.result;
1606+
} else
1607+
for (i = 0; i < list->nr; i++) {
1608+
const char *name = list->items[i].string;
1609+
argv_array_push(&argv, name);
1610+
if (verbosity >= 0)
1611+
printf(_("Fetching %s\n"), name);
1612+
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
1613+
error(_("Could not fetch %s"), name);
1614+
result = 1;
1615+
}
1616+
argv_array_pop(&argv);
15381617
}
1539-
argv_array_pop(&argv);
1540-
}
15411618

15421619
argv_array_clear(&argv);
1543-
return result;
1620+
return !!result;
15441621
}
15451622

15461623
/*
@@ -1673,7 +1750,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
16731750
for (i = 1; i < argc; i++)
16741751
strbuf_addf(&default_rla, " %s", argv[i]);
16751752

1676-
fetch_config_from_gitmodules(&max_children, &recurse_submodules);
1753+
fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
1754+
&recurse_submodules);
16771755
git_config(git_fetch_config, NULL);
16781756

16791757
argc = parse_options(argc, argv, prefix,
@@ -1739,15 +1817,27 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
17391817
fetch_one_setup_partial(remote);
17401818
result = fetch_one(remote, argc, argv, prune_tags_ok);
17411819
} else {
1820+
int max_children = max_jobs;
1821+
17421822
if (filter_options.choice)
17431823
die(_("--filter can only be used with the remote "
17441824
"configured in extensions.partialclone"));
1825+
1826+
if (max_children < 0)
1827+
max_children = fetch_parallel_config;
1828+
17451829
/* TODO should this also die if we have a previous partial-clone? */
1746-
result = fetch_multiple(&list);
1830+
result = fetch_multiple(&list, max_children);
17471831
}
17481832

17491833
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
17501834
struct argv_array options = ARGV_ARRAY_INIT;
1835+
int max_children = max_jobs;
1836+
1837+
if (max_children < 0)
1838+
max_children = submodule_fetch_jobs_config;
1839+
if (max_children < 0)
1840+
max_children = fetch_parallel_config;
17511841

17521842
add_options_to_argv(&options);
17531843
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 "preparing to run up to 2 tasks" trace &&
193+
test_i18ngrep "could not fetch .one.*128" err &&
194+
test_i18ngrep "could not fetch .two.*128" err
195+
'
196+
186197
test_done

0 commit comments

Comments
 (0)