diff --git a/builtin/config.c b/builtin/config.c index 75852bd79d..166568420b 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -776,6 +776,18 @@ static void location_options_init(struct config_location_options *opts, } if (opts->use_global_config) { + /* + * Since global config is sourced from more than one location, + * use `config.c#do_git_config_sequence()` with `opts->options` + * to read it. However, writing global config should point to a + * single destination, set in `opts->source.file`. + */ + opts->options.ignore_repo = 1; + opts->options.ignore_cmdline= 1; + opts->options.ignore_worktree = 1; + opts->options.ignore_system = 1; + opts->source.scope = CONFIG_SCOPE_GLOBAL; + opts->source.file = opts->file_to_free = git_global_config(); if (!opts->source.file) /* diff --git a/config.c b/config.c index f1def0dcfb..084c62c82d 100644 --- a/config.c +++ b/config.c @@ -1538,22 +1538,27 @@ static int do_git_config_sequence(const struct config_options *opts, worktree_config = NULL; } - if (git_config_system() && system_config && + if (!opts->ignore_system && 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); - git_global_config_paths(&user_config, &xdg_config); + if (!opts->ignore_global) { + 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); + 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); - 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); + 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); + + free(xdg_config); + free(user_config); + } if (!opts->ignore_repo && repo_config && !access_or_die(repo_config, R_OK, 0)) @@ -1572,8 +1577,6 @@ static int do_git_config_sequence(const struct config_options *opts, die(_("unable to parse command-line config")); free(system_config); - free(xdg_config); - free(user_config); free(repo_config); free(worktree_config); return ret; @@ -1603,7 +1606,8 @@ int config_with_options(config_fn_t fn, void *data, */ if (config_source && config_source->use_stdin) { ret = git_config_from_stdin(fn, data, config_source->scope); - } else if (config_source && config_source->file) { + } else if (config_source && config_source->file && + config_source->scope != CONFIG_SCOPE_GLOBAL) { ret = git_config_from_file_with_options(fn, config_source->file, data, config_source->scope, NULL); diff --git a/config.h b/config.h index 19c87fc0bc..9425fe115d 100644 --- a/config.h +++ b/config.h @@ -87,6 +87,8 @@ typedef int (*config_parser_event_fn_t)(enum config_event_t type, struct config_options { unsigned int respect_includes : 1; + unsigned int ignore_system : 1; + unsigned int ignore_global : 1; unsigned int ignore_repo : 1; unsigned int ignore_worktree : 1; unsigned int ignore_cmdline : 1; diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 61e44027bc..6eaed6d62c 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -2367,7 +2367,7 @@ test_expect_success 'list with nonexistent global config' ' git config ${mode_prefix}list --show-scope ' -test_expect_success 'list --global with nonexistent global config' ' +test_expect_failure 'list --global with nonexistent global config' ' rm -rf "$HOME"/.gitconfig "$HOME"/.config/git/config && test_must_fail git config ${mode_prefix}list --global --show-scope ' @@ -2424,7 +2424,7 @@ test_expect_success 'list --global with both home and xdg' ' global file:$HOME/.gitconfig home.config=true EOF git config ${mode_prefix}list --global --show-scope --show-origin >output && - ! test_cmp expect output + test_cmp expect output ' test_expect_success 'override global and system config' ' @@ -2478,7 +2478,7 @@ test_expect_success 'override global and system config' ' test_cmp expect output ' -test_expect_success 'override global and system config with missing file' ' +test_expect_failure 'override global and system config with missing file' ' test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config ${mode_prefix}list --global && test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config ${mode_prefix}list --system && GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh index 0318755799..475bd26aba 100755 --- a/t/t1306-xdg-files.sh +++ b/t/t1306-xdg-files.sh @@ -71,7 +71,7 @@ test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' echo user.name=read_config >expected && echo user.name=read_gitconfig >>expected && git config --global --list >actual && - ! test_cmp expected actual + test_cmp expected actual '