config: let sequence require a successful file

Teach `do_git_config_sequence()` to optionally report an error if no
configuration files in the sequence were successfully processed. Gate
this new behaviour with a flag and keep it disabled for now.

Add tests to record existing behaviour and prevent regressions in the
next patch, "config: read global scope via config_sequence", which adds
a code path that enables the flag. When no global configuration file
exists, `git config list` succeeds whereas `git config list --global`
fails. The command output is irrelevant, so only check the exit code.

Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
jch
Delilah Ashley Wu 2026-08-23 20:28:27 +10:00 committed by Junio C Hamano
parent f0a16901bd
commit 36e859020c
2 changed files with 52 additions and 17 deletions

View File

@ -1544,11 +1544,27 @@ int git_config_system(void)
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}

static void attempt_git_config_from_file_with_options(config_fn_t fn,
const char *filename,
void *data,
enum config_scope scope,
const struct config_options *opts,
int *success_count,
int *cumulative_ret)
{
int ret = git_config_from_file_with_options(fn, filename, data,
scope, opts);
if (!ret)
(*success_count)++;
*cumulative_ret += ret;
}

static int do_git_config_sequence(const struct config_options *opts,
const struct repository *repo,
config_fn_t fn, void *data)
const struct repository *repo, config_fn_t fn,
void *data, int require_successful_config)
{
int ret = 0;
int success_count = 0;
char *system_config = git_system_config();
char *xdg_config = NULL;
char *user_config = NULL;
@ -1574,32 +1590,35 @@ static int do_git_config_sequence(const struct config_options *opts,
if (git_config_system() && system_config &&
!access_or_die(system_config, R_OK,
opts->system_gently ? ACCESS_EACCES_OK : 0))
ret += git_config_from_file_with_options(fn, system_config,
data, CONFIG_SCOPE_SYSTEM,
NULL);
attempt_git_config_from_file_with_options(fn, system_config, data,
CONFIG_SCOPE_SYSTEM, NULL,
&success_count, &ret);

git_global_config_paths(&user_config, &xdg_config);

if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
ret += git_config_from_file_with_options(fn, xdg_config, data,
CONFIG_SCOPE_GLOBAL, NULL);
attempt_git_config_from_file_with_options(fn, xdg_config,
data,
CONFIG_SCOPE_GLOBAL,
NULL, &success_count, &ret);

if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
ret += git_config_from_file_with_options(fn, user_config, data,
CONFIG_SCOPE_GLOBAL, NULL);
attempt_git_config_from_file_with_options(fn, user_config,
data,
CONFIG_SCOPE_GLOBAL,
NULL, &success_count, &ret);

if (!opts->ignore_repo && repo_config &&
!access_or_die(repo_config, R_OK, 0))
ret += git_config_from_file_with_options(fn, repo_config, data,
CONFIG_SCOPE_LOCAL, NULL);
attempt_git_config_from_file_with_options(fn, repo_config, data,
CONFIG_SCOPE_LOCAL, NULL, &success_count, &ret);

if (!opts->ignore_worktree && worktree_config &&
repo && repo->repository_format_worktree_config &&
!access_or_die(worktree_config, R_OK, 0)) {
ret += git_config_from_file_with_options(fn, worktree_config, data,
CONFIG_SCOPE_WORKTREE,
NULL);
}
!access_or_die(worktree_config, R_OK, 0))
attempt_git_config_from_file_with_options(fn, worktree_config, data,
CONFIG_SCOPE_WORKTREE,
NULL, &success_count, &ret);

if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
die(_("unable to parse command-line config"));
@ -1609,6 +1628,10 @@ static int do_git_config_sequence(const struct config_options *opts,
free(user_config);
free(repo_config);
free(worktree_config);

if (require_successful_config && !success_count && !ret)
ret = -1;

return ret;
}

@ -1644,7 +1667,7 @@ int config_with_options(config_fn_t fn, void *data,
ret = git_config_from_blob_ref(fn, repo, config_source->blob,
data, config_source->scope);
} else {
ret = do_git_config_sequence(opts, repo, fn, data);
ret = do_git_config_sequence(opts, repo, fn, data, 0);
}

if (inc.remote_urls) {

View File

@ -2457,6 +2457,18 @@ test_expect_success '--show-scope with --default' '
test_cmp expect actual
'

test_expect_success 'list with nonexistent global config gracefully exits' '
rm -f "$HOME"/.gitconfig "$HOME"/.config/git/config &&
git config ${mode_prefix}list &&
git config ${mode_prefix}list --show-scope
'

test_expect_success 'list --global with nonexistent global config fails' '
rm -f "$HOME"/.gitconfig "$HOME"/.config/git/config &&
test_must_fail git config ${mode_prefix}list --global &&
test_must_fail git config ${mode_prefix}list --global --show-scope
'

test_expect_success 'override global and system config' '
test_when_finished rm -f \"\$HOME\"/.gitconfig &&
cat >"$HOME"/.gitconfig <<-EOF &&