Skip to content

Commit f847d00

Browse files
committed
config: read from config sequence for global scope
The output of `git config list --global` should include both the home (`$HOME/.gitconfig`) and XDG (`$XDG_CONFIG_HOME/git/config`) configs, but it only reads from the former. We assumed each config scope corresponds to a single config file. Under this assumption, `git config list --global` reads the global config by calling `git_config_from_file_with_options(...,"~/.gitconfig", ...)`. This function usage restricts us to a single config file. Because the global scope includes two files, we should read the configs via another method. The output of `git config list --show-scope --show-origin` (without `--global`) correctly includes both the home and XDG config files. So there's existing code that respects both locations, namely the `do_git_config_sequence()` function which reads from all scopes. Introduce flags to make it possible to ignore all but the global scope (i.e. ignore system, local, worktree, and cmdline). Then, reuse the function to read only the global scope when `--global` is specified. This was the suggested solution in the bug report: https://lore.kernel.org/git/[email protected]. Then, modify the tests to check that `git config list --global` includes both home and XDG configs. This change introduces a regression: if both global config files are unreadable, then `git config list --global` should exit non-zero. This is no longer the case, so mark the corresponding test as a "TODO known breakage" and address the issue in the next patch. Implementation notes: 1. The `ignore_global` flag is not set anywhere, so the `if (!opts->ignore_global)` condition is always met. We can remove this flag if desired. 2. I've assumed that `config_source->scope == CONFIG_SCOPE_GLOBAL` iff `--global` is specified. This comparison determines whether to call `do_git_config_sequence()` for the global scope, or to keep calling `git_config_from_file_with_options()` for other scopes. 3. Keep populating `opts->source.file` in `builtin/config.c` because it is used as the destination confile file for write operations. The proposed changes could convolute the code because there is no single source of truth for the config file locations in the global scope. Add a comment to help clarify this. Please let me know if it's unclear. Reported-by: Jade Lovelace <[email protected]> Helped-by: Derrick Stolee <[email protected]> Suggested-by: Glen Choo <[email protected]> Signed-off-by: Delilah Ashley Wu <[email protected]>
1 parent e364c8c commit f847d00

File tree

5 files changed

+33
-15
lines changed

5 files changed

+33
-15
lines changed

builtin/config.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,18 @@ static void location_options_init(struct config_location_options *opts,
768768
}
769769

770770
if (opts->use_global_config) {
771+
/*
772+
* Since global config is sourced from more than one location,
773+
* use `config.c#do_git_config_sequence()` with `opts->options`
774+
* to read it. However, writing global config should point to a
775+
* single destination, set in `opts->source.file`.
776+
*/
777+
opts->options.ignore_repo = 1;
778+
opts->options.ignore_cmdline= 1;
779+
opts->options.ignore_worktree = 1;
780+
opts->options.ignore_system = 1;
781+
opts->source.scope = CONFIG_SCOPE_GLOBAL;
782+
771783
opts->source.file = opts->file_to_free = git_global_config();
772784
if (!opts->source.file)
773785
/*

config.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,22 +1526,27 @@ static int do_git_config_sequence(const struct config_options *opts,
15261526
worktree_config = NULL;
15271527
}
15281528

1529-
if (git_config_system() && system_config &&
1529+
if (!opts->ignore_system && git_config_system() && system_config &&
15301530
!access_or_die(system_config, R_OK,
15311531
opts->system_gently ? ACCESS_EACCES_OK : 0))
15321532
ret += git_config_from_file_with_options(fn, system_config,
15331533
data, CONFIG_SCOPE_SYSTEM,
15341534
NULL);
15351535

1536-
git_global_config_paths(&user_config, &xdg_config);
1536+
if (!opts->ignore_global) {
1537+
git_global_config_paths(&user_config, &xdg_config);
1538+
1539+
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
1540+
ret += git_config_from_file_with_options(fn, xdg_config, data,
1541+
CONFIG_SCOPE_GLOBAL, NULL);
15371542

1538-
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
1539-
ret += git_config_from_file_with_options(fn, xdg_config, data,
1540-
CONFIG_SCOPE_GLOBAL, NULL);
1543+
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
1544+
ret += git_config_from_file_with_options(fn, user_config, data,
1545+
CONFIG_SCOPE_GLOBAL, NULL);
15411546

1542-
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
1543-
ret += git_config_from_file_with_options(fn, user_config, data,
1544-
CONFIG_SCOPE_GLOBAL, NULL);
1547+
free(xdg_config);
1548+
free(user_config);
1549+
}
15451550

15461551
if (!opts->ignore_repo && repo_config &&
15471552
!access_or_die(repo_config, R_OK, 0))
@@ -1560,8 +1565,6 @@ static int do_git_config_sequence(const struct config_options *opts,
15601565
die(_("unable to parse command-line config"));
15611566

15621567
free(system_config);
1563-
free(xdg_config);
1564-
free(user_config);
15651568
free(repo_config);
15661569
free(worktree_config);
15671570
return ret;
@@ -1591,7 +1594,8 @@ int config_with_options(config_fn_t fn, void *data,
15911594
*/
15921595
if (config_source && config_source->use_stdin) {
15931596
ret = git_config_from_stdin(fn, data, config_source->scope);
1594-
} else if (config_source && config_source->file) {
1597+
} else if (config_source && config_source->file &&
1598+
config_source->scope != CONFIG_SCOPE_GLOBAL) {
15951599
ret = git_config_from_file_with_options(fn, config_source->file,
15961600
data, config_source->scope,
15971601
NULL);

config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ typedef int (*config_parser_event_fn_t)(enum config_event_t type,
8787

8888
struct config_options {
8989
unsigned int respect_includes : 1;
90+
unsigned int ignore_system : 1;
91+
unsigned int ignore_global : 1;
9092
unsigned int ignore_repo : 1;
9193
unsigned int ignore_worktree : 1;
9294
unsigned int ignore_cmdline : 1;

t/t1300-config.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,7 +2372,7 @@ test_expect_success 'list with nonexistent global config' '
23722372
git config ${mode_prefix}list --show-scope
23732373
'
23742374

2375-
test_expect_success 'list --global with nonexistent global config' '
2375+
test_expect_failure 'list --global with nonexistent global config' '
23762376
rm -rf "$HOME"/.gitconfig "$HOME"/.config/git/config &&
23772377
test_must_fail git config ${mode_prefix}list --global --show-scope
23782378
'
@@ -2429,7 +2429,7 @@ test_expect_success 'list --global with both home and xdg' '
24292429
global file:$HOME/.gitconfig home.config=true
24302430
EOF
24312431
git config ${mode_prefix}list --global --show-scope --show-origin >output &&
2432-
! test_cmp expect output
2432+
test_cmp expect output
24332433
'
24342434

24352435
test_expect_success 'override global and system config' '
@@ -2483,7 +2483,7 @@ test_expect_success 'override global and system config' '
24832483
test_cmp expect output
24842484
'
24852485

2486-
test_expect_success 'override global and system config with missing file' '
2486+
test_expect_failure 'override global and system config with missing file' '
24872487
test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config ${mode_prefix}list --global &&
24882488
test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config ${mode_prefix}list --system &&
24892489
GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version

t/t1306-xdg-files.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists'
7171
echo user.name=read_config >expected &&
7272
echo user.name=read_gitconfig >>expected &&
7373
git config --global --list >actual &&
74-
! test_cmp expected actual
74+
test_cmp expected actual
7575
'
7676

7777

0 commit comments

Comments
 (0)