Merge branch 'pz/fetch-submodule-errors-config' into seen
The 'git fetch' command has been updated to allow configuring how submodule fetch errors are handled. A new configuration variable 'fetch.submoduleErrors' and a corresponding '--submodule-errors' command-line option have been introduced, allowing users to make submodule fetch errors non-fatal (warn instead of fail). Additionally, a premature failure during recursive submodule fetches has been fixed by deferring the error until the OID-based retry phase also fails. * pz/fetch-submodule-errors-config: fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal submodule: fix premature failure in recursive submodule fetchseen
commit
a41900afd4
|
|
@ -10,6 +10,20 @@
|
|||
reference.
|
||||
Defaults to `on-demand`, or to the value of `submodule.recurse` if set.
|
||||
|
||||
`fetch.submoduleErrors`::
|
||||
Controls how errors from submodule fetches are handled when
|
||||
`--recurse-submodules` is in effect. When set to `fail` (the default),
|
||||
any submodule fetch error causes the overall `git fetch` or `git pull`
|
||||
to exit with a non-zero status. When set to `warn`, submodule fetch
|
||||
errors are reported to standard error but do not affect the exit
|
||||
status of the command. This is useful when working in repositories
|
||||
where some branches reference submodule commits that are not yet
|
||||
available on the submodule remote, but those commits are not needed
|
||||
for the currently checked-out branch.
|
||||
+
|
||||
The value of this option can be overridden by the `--submodule-errors`
|
||||
option of linkgit:git-fetch[1].
|
||||
|
||||
`fetch.fsckObjects`::
|
||||
If it is set to true, git-fetch-pack will check all fetched
|
||||
objects. See `transfer.fsckObjects` for what's
|
||||
|
|
|
|||
|
|
@ -294,6 +294,14 @@ ifndef::git-pull[]
|
|||
`--no-recurse-submodules`::
|
||||
Disable recursive fetching of submodules (this has the same effect as
|
||||
using the `--recurse-submodules=no` option).
|
||||
|
||||
`--submodule-errors=(fail|warn)`::
|
||||
Control how errors from submodule fetches are handled when
|
||||
`--recurse-submodules` is in effect. When set to `fail` (the default),
|
||||
any submodule fetch error causes the overall `git fetch` to exit with a
|
||||
non-zero status. When set to `warn`, submodule fetch errors are reported
|
||||
to standard error but do not affect the exit status of the command. Can
|
||||
also be configured via `fetch.submoduleErrors`. See linkgit:git-config[1].
|
||||
endif::git-pull[]
|
||||
|
||||
`--set-upstream`::
|
||||
|
|
|
|||
|
|
@ -111,8 +111,30 @@ struct fetch_config {
|
|||
int recurse_submodules;
|
||||
int parallel;
|
||||
int submodule_fetch_jobs;
|
||||
int submodule_errors;
|
||||
};
|
||||
|
||||
/* really private - use accessors below to parse and format */
|
||||
static const char *submodule_error_name[] = {
|
||||
[SUBMODULE_ERRORS_FAIL] = "fail",
|
||||
[SUBMODULE_ERRORS_WARN] = "warn",
|
||||
};
|
||||
|
||||
static const char *submodule_error(unsigned num)
|
||||
{
|
||||
if (ARRAY_SIZE(submodule_error_name) <= num)
|
||||
BUG("invalid submodule errors mode %u", num);
|
||||
return submodule_error_name[num];
|
||||
}
|
||||
|
||||
static int parse_submodule_error(const char *name)
|
||||
{
|
||||
for (unsigned num = 0; num < ARRAY_SIZE(submodule_error_name); num++)
|
||||
if (!strcmp(submodule_error_name[num], name))
|
||||
return num;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int git_fetch_config(const char *k, const char *v,
|
||||
const struct config_context *ctx, void *cb)
|
||||
{
|
||||
|
|
@ -153,6 +175,19 @@ static int git_fetch_config(const char *k, const char *v,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(k, "fetch.submoduleerrors")) {
|
||||
int mode;
|
||||
|
||||
if (!v)
|
||||
return config_error_nonbool(k);
|
||||
mode = parse_submodule_error(v);
|
||||
if (mode < 0)
|
||||
die(_("invalid value for '%s': '%s'"),
|
||||
"fetch.submoduleErrors", v);
|
||||
fetch_config->submodule_errors = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(k, "fetch.parallel")) {
|
||||
fetch_config->parallel = git_config_int(k, v, ctx->kvi);
|
||||
if (fetch_config->parallel < 0)
|
||||
|
|
@ -2243,6 +2278,9 @@ static void add_options_to_argv(struct strvec *argv,
|
|||
strvec_push(argv, "--no-recurse-submodules");
|
||||
else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
|
||||
strvec_push(argv, "--recurse-submodules=on-demand");
|
||||
if (config->submodule_errors != -1)
|
||||
strvec_pushf(argv, "--submodule-errors=%s",
|
||||
submodule_error(config->submodule_errors));
|
||||
if (tags == TAGS_SET)
|
||||
strvec_push(argv, "--tags");
|
||||
else if (tags == TAGS_UNSET)
|
||||
|
|
@ -2502,6 +2540,23 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
static int option_parse_submodule_errors(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
int *v = opt->value;
|
||||
int mode;
|
||||
|
||||
if (unset) {
|
||||
*v = SUBMODULE_ERRORS_FAIL;
|
||||
return 0;
|
||||
}
|
||||
mode = parse_submodule_error(arg);
|
||||
if (mode < 0)
|
||||
die(_("invalid value for '%s': '%s'"), "--submodule-errors", arg);
|
||||
*v = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_fetch(int argc,
|
||||
const char **argv,
|
||||
const char *prefix,
|
||||
|
|
@ -2516,6 +2571,7 @@ int cmd_fetch(int argc,
|
|||
.recurse_submodules = RECURSE_SUBMODULES_DEFAULT,
|
||||
.parallel = 1,
|
||||
.submodule_fetch_jobs = -1,
|
||||
.submodule_errors = -1, /* unset */
|
||||
};
|
||||
const char *submodule_prefix = "";
|
||||
const char *bundle_uri;
|
||||
|
|
@ -2530,6 +2586,7 @@ int cmd_fetch(int argc,
|
|||
int max_jobs = -1;
|
||||
int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
|
||||
int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
|
||||
int submodule_errors_cli = -1; /* -1: not set on command line */
|
||||
int fetch_write_commit_graph = -1;
|
||||
int stdin_refspecs = 0;
|
||||
int negotiate_only = 0;
|
||||
|
|
@ -2566,6 +2623,10 @@ int cmd_fetch(int argc,
|
|||
OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
|
||||
N_("control recursive fetching of submodules"),
|
||||
PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
|
||||
OPT_CALLBACK_F(0, "submodule-errors", &submodule_errors_cli,
|
||||
N_("(fail|warn)"),
|
||||
N_("control how submodule fetch errors are handled"),
|
||||
0, option_parse_submodule_errors),
|
||||
OPT_BOOL(0, "dry-run", &dry_run,
|
||||
N_("dry run")),
|
||||
OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
|
||||
|
|
@ -2657,6 +2718,9 @@ int cmd_fetch(int argc,
|
|||
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
|
||||
config.recurse_submodules = recurse_submodules_cli;
|
||||
|
||||
if (submodule_errors_cli != -1)
|
||||
config.submodule_errors = submodule_errors_cli;
|
||||
|
||||
if (negotiate_only) {
|
||||
switch (recurse_submodules_cli) {
|
||||
case RECURSE_SUBMODULES_OFF:
|
||||
|
|
@ -2860,11 +2924,14 @@ int cmd_fetch(int argc,
|
|||
if (!result && remote && (config.recurse_submodules != RECURSE_SUBMODULES_OFF)) {
|
||||
struct strvec options = STRVEC_INIT;
|
||||
int max_children = max_jobs;
|
||||
int submodule_errors = config.submodule_errors;
|
||||
|
||||
if (max_children < 0)
|
||||
max_children = config.submodule_fetch_jobs;
|
||||
if (max_children < 0)
|
||||
max_children = config.parallel;
|
||||
if (submodule_errors < 0)
|
||||
submodule_errors = SUBMODULE_ERRORS_FAIL;
|
||||
|
||||
add_options_to_argv(&options, &config);
|
||||
trace2_region_enter_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
|
||||
|
|
@ -2874,7 +2941,8 @@ int cmd_fetch(int argc,
|
|||
config.recurse_submodules,
|
||||
recurse_submodules_default,
|
||||
verbosity < 0,
|
||||
max_children);
|
||||
max_children,
|
||||
submodule_errors);
|
||||
trace2_region_leave_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
|
||||
strvec_clear(&options);
|
||||
}
|
||||
|
|
|
|||
58
submodule.c
58
submodule.c
|
|
@ -1409,6 +1409,7 @@ struct submodule_parallel_fetch {
|
|||
int oid_fetch_tasks_nr, oid_fetch_tasks_alloc;
|
||||
|
||||
struct strbuf submodules_with_errors;
|
||||
int submodule_errors;
|
||||
};
|
||||
#define SPF_INIT { \
|
||||
.args = STRVEC_INIT, \
|
||||
|
|
@ -1562,6 +1563,14 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void record_fetch_error(struct submodule_parallel_fetch *spf,
|
||||
const char *name)
|
||||
{
|
||||
if (spf->submodule_errors == SUBMODULE_ERRORS_FAIL)
|
||||
spf->result = 1;
|
||||
strbuf_addf(&spf->submodules_with_errors, "\t%s\n", name);
|
||||
}
|
||||
|
||||
static struct fetch_task *
|
||||
get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
|
||||
struct strbuf *err)
|
||||
|
|
@ -1599,7 +1608,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
|
|||
ce->name);
|
||||
if (S_ISGITLINK(ce->ce_mode) &&
|
||||
!is_empty_dir(empty_submodule_path.buf)) {
|
||||
spf->result = 1;
|
||||
record_fetch_error(spf, ce->name);
|
||||
strbuf_addf(err,
|
||||
_("Could not access submodule '%s'\n"),
|
||||
ce->name);
|
||||
|
|
@ -1753,7 +1762,7 @@ static int fetch_start_failure(struct strbuf *err UNUSED,
|
|||
struct submodule_parallel_fetch *spf = cb;
|
||||
struct fetch_task *task = task_cb;
|
||||
|
||||
spf->result = 1;
|
||||
record_fetch_error(spf, task->sub->name);
|
||||
|
||||
fetch_task_free(task);
|
||||
return 0;
|
||||
|
|
@ -1779,18 +1788,12 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
|
|||
if (!task || !task->sub)
|
||||
BUG("callback cookie bogus");
|
||||
|
||||
if (retvalue) {
|
||||
if (retvalue && task->commits) {
|
||||
/*
|
||||
* NEEDSWORK: This indicates that the overall fetch
|
||||
* failed, even though there may be a subsequent fetch
|
||||
* by commit hash that might work. It may be a good
|
||||
* idea to not indicate failure in this case, and only
|
||||
* indicate failure if the subsequent fetch fails.
|
||||
* This is the second pass (OID-based fetch) and it failed.
|
||||
* The commits are genuinely unavailable from the remote.
|
||||
*/
|
||||
spf->result = 1;
|
||||
|
||||
strbuf_addf(&spf->submodules_with_errors, "\t%s\n",
|
||||
task->sub->name);
|
||||
record_fetch_error(spf, task->sub->name);
|
||||
}
|
||||
|
||||
/* Is this the second time we process this submodule? */
|
||||
|
|
@ -1798,9 +1801,17 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
|
|||
goto out;
|
||||
|
||||
it = string_list_lookup(&spf->changed_submodule_names, task->sub->name);
|
||||
if (!it)
|
||||
/* Could be an unchanged submodule, not contained in the list */
|
||||
if (!it) {
|
||||
/*
|
||||
* This submodule is not in the changed list (e.g. it was
|
||||
* fetched because RECURSE_SUBMODULES_ON fetches all populated
|
||||
* submodules). A phase 1 failure here has no OID-based retry
|
||||
* to fall back on, so it is a genuine error.
|
||||
*/
|
||||
if (retvalue)
|
||||
record_fetch_error(spf, task->sub->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cs_data = it->util;
|
||||
oid_array_filter(&cs_data->new_commits,
|
||||
|
|
@ -1809,6 +1820,11 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
|
|||
|
||||
/* Are there commits we want, but do not exist? */
|
||||
if (cs_data->new_commits.nr) {
|
||||
/*
|
||||
* Schedule an OID-based phase 2 fetch to retrieve the missing
|
||||
* commits directly. Defer any error from phase 1: if phase 2
|
||||
* succeeds, the overall operation should still succeed.
|
||||
*/
|
||||
task->commits = &cs_data->new_commits;
|
||||
ALLOC_GROW(spf->oid_fetch_tasks,
|
||||
spf->oid_fetch_tasks_nr + 1,
|
||||
|
|
@ -1818,6 +1834,16 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* All required commits are already present locally (they were either
|
||||
* fetched by phase 1 or existed beforehand), so there is no phase 2
|
||||
* retry to defer to. If phase 1 failed, the fetch itself went wrong
|
||||
* (e.g. a transport error) and must still be reported, even though
|
||||
* the gitlinked commits are available.
|
||||
*/
|
||||
if (retvalue)
|
||||
record_fetch_error(spf, task->sub->name);
|
||||
|
||||
out:
|
||||
fetch_task_free(task);
|
||||
return 0;
|
||||
|
|
@ -1827,7 +1853,8 @@ int fetch_submodules(struct repository *r,
|
|||
const struct strvec *options,
|
||||
const char *prefix, int command_line_option,
|
||||
int default_option,
|
||||
int quiet, int max_parallel_jobs)
|
||||
int quiet, int max_parallel_jobs,
|
||||
int submodule_errors)
|
||||
{
|
||||
struct submodule_parallel_fetch spf = SPF_INIT;
|
||||
const struct run_process_parallel_opts opts = {
|
||||
|
|
@ -1847,6 +1874,7 @@ int fetch_submodules(struct repository *r,
|
|||
spf.default_option = default_option;
|
||||
spf.quiet = quiet;
|
||||
spf.prefix = prefix;
|
||||
spf.submodule_errors = submodule_errors;
|
||||
|
||||
if (!r->worktree)
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -90,12 +90,17 @@ int should_update_submodules(void);
|
|||
*/
|
||||
const struct submodule *submodule_from_ce(const struct cache_entry *ce);
|
||||
void check_for_new_submodule_commits(struct object_id *oid);
|
||||
/* Values for the submodule_errors parameter of fetch_submodules(). */
|
||||
#define SUBMODULE_ERRORS_FAIL 0 /* submodule fetch errors are fatal (default) */
|
||||
#define SUBMODULE_ERRORS_WARN 1 /* submodule fetch errors are non-fatal warnings */
|
||||
|
||||
int fetch_submodules(struct repository *r,
|
||||
const struct strvec *options,
|
||||
const char *prefix,
|
||||
int command_line_option,
|
||||
int default_option,
|
||||
int quiet, int max_parallel_jobs);
|
||||
int quiet, int max_parallel_jobs,
|
||||
int submodule_errors);
|
||||
unsigned is_submodule_modified(const char *path, int ignore_untracked);
|
||||
int submodule_uses_gitfile(const char *path);
|
||||
|
||||
|
|
|
|||
|
|
@ -1262,4 +1262,165 @@ test_expect_success "fetch --all with --no-recurse-submodules only fetches super
|
|||
test_grep ! "Fetching submodule" fetch-log
|
||||
'
|
||||
|
||||
# Create an isolated environment for submodule fetch error tests.
|
||||
#
|
||||
# Sets up sub_bare (the submodule upstream), super_bare (the superproject
|
||||
# upstream), super_work (a working clone of super_bare with an initialized
|
||||
# submodule), and clone (a clone of super_bare with an initialized submodule
|
||||
# at a reachable commit). The caller can then create an unreachable commit
|
||||
# and push the superproject to put the clone one commit behind a state it
|
||||
# cannot fully fetch.
|
||||
#
|
||||
# Usage: create_err_env <envdir>
|
||||
create_err_env () {
|
||||
local envdir="$1" &&
|
||||
mkdir "$envdir" &&
|
||||
|
||||
git init --bare "$envdir/sub_bare" &&
|
||||
git clone "$envdir/sub_bare" "$envdir/sub_work" &&
|
||||
test_commit -C "$envdir/sub_work" "${envdir}_base" &&
|
||||
git -C "$envdir/sub_work" push &&
|
||||
|
||||
git init --bare "$envdir/super_bare" &&
|
||||
git clone "$envdir/super_bare" "$envdir/super_work" &&
|
||||
git -C "$envdir/super_work" submodule add \
|
||||
"$pwd/$envdir/sub_bare" sub &&
|
||||
git -C "$envdir/super_work" commit -m "add submodule" &&
|
||||
git -C "$envdir/super_work" push &&
|
||||
|
||||
git clone "$envdir/super_bare" "$envdir/clone" &&
|
||||
git -C "$envdir/clone" submodule update --init
|
||||
}
|
||||
|
||||
# Push a commit to <envdir>/super_bare that records a submodule SHA that is
|
||||
# present locally in super_work/sub but NOT pushed to sub_bare, making the
|
||||
# submodule commit unreachable from clone's sub remote.
|
||||
push_unreachable_commit () {
|
||||
local envdir="$1" &&
|
||||
git -C "$envdir/super_work/sub" commit --allow-empty -m "unreachable" &&
|
||||
git -C "$envdir/super_work" add sub &&
|
||||
git -C "$envdir/super_work" commit -m "point sub to unreachable commit" &&
|
||||
git -C "$envdir/super_work" push
|
||||
}
|
||||
|
||||
test_expect_success 'setup for submodule fetch error tests' '
|
||||
git config --global protocol.file.allow always
|
||||
'
|
||||
|
||||
test_expect_success 'fetch --recurse-submodules fails when submodule commit is unreachable (default)' '
|
||||
test_when_finished "rm -fr env_default" &&
|
||||
create_err_env env_default &&
|
||||
push_unreachable_commit env_default &&
|
||||
test_must_fail git -C env_default/clone fetch --recurse-submodules 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success 'fetch.submoduleErrors=warn: unreachable submodule commit is non-fatal' '
|
||||
test_when_finished "rm -fr env_warn_cfg" &&
|
||||
create_err_env env_warn_cfg &&
|
||||
push_unreachable_commit env_warn_cfg &&
|
||||
git -C env_warn_cfg/clone -c fetch.submoduleErrors=warn \
|
||||
fetch --recurse-submodules 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success '--submodule-errors=warn: unreachable submodule commit is non-fatal' '
|
||||
test_when_finished "rm -fr env_warn_cli" &&
|
||||
create_err_env env_warn_cli &&
|
||||
push_unreachable_commit env_warn_cli &&
|
||||
git -C env_warn_cli/clone fetch --recurse-submodules \
|
||||
--submodule-errors=warn 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success '--submodule-errors=fail: unreachable submodule commit is fatal' '
|
||||
test_when_finished "rm -fr env_fail_cli" &&
|
||||
create_err_env env_fail_cli &&
|
||||
push_unreachable_commit env_fail_cli &&
|
||||
test_must_fail git -C env_fail_cli/clone fetch --recurse-submodules \
|
||||
--submodule-errors=fail 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success 'fetch.submoduleErrors=warn does not suppress successful fetch' '
|
||||
# A new reachable submodule commit (pushed to sub_bare) should be
|
||||
# fetched without any error summary.
|
||||
test_when_finished "rm -fr env_ok" &&
|
||||
create_err_env env_ok &&
|
||||
test_commit -C env_ok/sub_work reachable_ok &&
|
||||
git -C env_ok/sub_work push &&
|
||||
git -C env_ok/super_work submodule update --remote &&
|
||||
git -C env_ok/super_work add sub &&
|
||||
git -C env_ok/super_work commit -m "point sub to reachable commit" &&
|
||||
git -C env_ok/super_work push &&
|
||||
git -C env_ok/clone -c fetch.submoduleErrors=warn \
|
||||
fetch --recurse-submodules 2>err &&
|
||||
test_grep ! "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success 'failed submodule fetch is fatal even when its commits are present locally' '
|
||||
# Create the same commit (unreferenced, via commit-tree with fixed
|
||||
# dates) in both super_work/sub and clone/sub, point the gitlink at
|
||||
# it, and break clone/sub'\''s remote. The commit exists in clone/sub
|
||||
# but is unreachable, so the submodule stays in the changed list; the
|
||||
# fetch failure must still be reported even though there is nothing
|
||||
# left to fetch by commit hash.
|
||||
test_when_finished "rm -fr env_phase1" &&
|
||||
create_err_env env_phase1 &&
|
||||
commit=$(GIT_AUTHOR_DATE="1234567890 +0000" \
|
||||
GIT_COMMITTER_DATE="1234567890 +0000" \
|
||||
git -C env_phase1/super_work/sub commit-tree \
|
||||
"HEAD^{tree}" -p HEAD -m present) &&
|
||||
present=$(GIT_AUTHOR_DATE="1234567890 +0000" \
|
||||
GIT_COMMITTER_DATE="1234567890 +0000" \
|
||||
git -C env_phase1/clone/sub commit-tree \
|
||||
"HEAD^{tree}" -p HEAD -m present) &&
|
||||
test "$commit" = "$present" &&
|
||||
git -C env_phase1/super_work/sub checkout "$commit" &&
|
||||
git -C env_phase1/super_work add sub &&
|
||||
git -C env_phase1/super_work commit -m "gitlink to locally-present commit" &&
|
||||
git -C env_phase1/super_work push &&
|
||||
git -C env_phase1/clone/sub remote set-url origin "$pwd/env_phase1/missing" &&
|
||||
test_must_fail git -C env_phase1/clone fetch --recurse-submodules 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success '--submodule-errors=warn is honored by fetch --all' '
|
||||
# A second remote forces fetch_multiple(), which hands the submodule
|
||||
# recursion off to per-remote child processes; the option must be
|
||||
# forwarded to them.
|
||||
test_when_finished "rm -fr env_all" &&
|
||||
create_err_env env_all &&
|
||||
push_unreachable_commit env_all &&
|
||||
git -C env_all/clone remote add second "$pwd/env_all/super_bare" &&
|
||||
git -C env_all/clone fetch --all --recurse-submodules \
|
||||
--submodule-errors=warn 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success '--submodule-errors=fail overrides warn config for fetch --all' '
|
||||
# The per-remote child processes re-read the repository config, so
|
||||
# the command-line override must be forwarded to them explicitly.
|
||||
test_when_finished "rm -fr env_override" &&
|
||||
create_err_env env_override &&
|
||||
push_unreachable_commit env_override &&
|
||||
git -C env_override/clone remote add second "$pwd/env_override/super_bare" &&
|
||||
git -C env_override/clone config fetch.submoduleErrors warn &&
|
||||
test_must_fail git -C env_override/clone fetch --all --recurse-submodules \
|
||||
--submodule-errors=fail 2>err &&
|
||||
test_grep "Errors during submodule fetch" err
|
||||
'
|
||||
|
||||
test_expect_success 'fetch.submoduleErrors=warn: inaccessible submodule is non-fatal' '
|
||||
test_when_finished "rm -fr env_access" &&
|
||||
create_err_env env_access &&
|
||||
rm env_access/clone/sub/.git &&
|
||||
rm -r env_access/clone/.git/modules/sub &&
|
||||
git -C env_access/clone -c fetch.submoduleErrors=warn \
|
||||
fetch --recurse-submodules 2>err &&
|
||||
test_grep "Could not access submodule" err &&
|
||||
test_must_fail git -C env_access/clone fetch --recurse-submodules 2>err &&
|
||||
test_grep "Could not access submodule" err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
Loading…
Reference in New Issue