Skip to content

Conversation

@delilahw
Copy link

@delilahw delilahw commented Jun 27, 2025

Hi!

As reported in [1]: `$HOME/.gitconfig` and `$XDG_CONFIG_HOME/git/config` are both valid global config locations, but `git config list --global` only includes the former in its output.

Suppose we have this config in `$HOME/.gitconfig`:

[home]
    config = true

And this config in `$XDG_CONFIG_HOME/git/config`:

[xdg]
    config = true

Then, to reproduce the issue that `--global` only shows the home config:

$ git config list --global --show-scope --show-origin
global  file:/Users/delilah/.gitconfig    home.config=true

Git correctly applies the XDG config in its effective configuration, but it doesn't show up when `--global` is specified. We can confirm this by checking the output without the `--global` flag:

$ git config list --show-scope --show-origin
global  file:/Users/delilah/.config/git/config    xdg.config=true
global  file:/Users/delilah/.gitconfig            home.config=true

The expected behaviour is both configs should be shown when `--global` is specified, so we'd expect its output to look the same as above. This was confirmed in [2], which quoted the `git config` documentation:

> OPTIONS
>     --global::
>         For writing options: write to global `~/.gitconfig` file
>         rather than the repository `.git/config`, write to
>         `$XDG_CONFIG_HOME/git/config` file if this file exists and the
>         `~/.gitconfig` file doesn't.
>
>         For reading options: read only from global `~/.gitconfig` and from
>         `$XDG_CONFIG_HOME/git/config` rather than from all available files.

The first patch fixes forward slash normalisation on Windows paths. The second patch introduces tests and regression checks. The third and fourth patches implement the fix to include both config files when `--global` is specified. Johannes has kindly pre-reviewed this patch series via GitHub on GitGitGadget #1938 [3]. You'll notice some force-pushes after the review, but I only changed commit messages.

[1]: https://lore.kernel.org/git/CAFA9we-QLQRzJdGMMCPatmfrk1oHeiUu9msMRXXk1MLE5HRxBQ@mail.gmail.com/
[2]: https://lore.kernel.org/git/xmqqmt5lezi3.fsf@gitster.g/
[3]: #1938

Thank you all for your time!
Delilah

cc: Delilah Ashley Wu delilahwu@microsoft.com
cc: Derrick Stolee stolee@gmail.com
cc: Johannes Schindelin johannes.schindelin@gmx.de
cc: Patrick Steinhardt ps@pks.im
cc: "Kristoffer Haugsbakk" kristofferhaugsbakk@fastmail.com

@gitgitgadget
Copy link

gitgitgadget bot commented Jun 27, 2025

Welcome to GitGitGadget

Hi @delilahw, and welcome to GitGitGadget, the GitHub App to send patch series to the Git mailing list from GitHub Pull Requests.

Please make sure that either:

  • Your Pull Request has a good description, if it consists of multiple commits, as it will be used as cover letter.
  • Your Pull Request description is empty, if it consists of a single commit, as the commit message should be descriptive enough by itself.

You can CC potential reviewers by adding a footer to the PR description with the following syntax:

CC: Revi Ewer <revi.ewer@example.com>, Ill Takalook <ill.takalook@example.net>

NOTE: DO NOT copy/paste your CC list from a previous GGG PR's description,
because it will result in a malformed CC list on the mailing list. See
example.

Also, it is a good idea to review the commit messages one last time, as the Git project expects them in a quite specific form:

  • the lines should not exceed 76 columns,
  • the first line should be like a header and typically start with a prefix like "tests:" or "revisions:" to state which subsystem the change is about, and
  • the commit messages' body should be describing the "why?" of the change.
  • Finally, the commit messages should end in a Signed-off-by: line matching the commits' author.

It is in general a good idea to await the automated test ("Checks") in this Pull Request before contributing the patches, e.g. to avoid trivial issues such as unportable code.

Contributing the patches

Before you can contribute the patches, your GitHub username needs to be added to the list of permitted users. Any already-permitted user can do that, by adding a comment to your PR of the form /allow. A good way to find other contributors is to locate recent pull requests where someone has been /allowed:

Both the person who commented /allow and the PR author are able to /allow you.

An alternative is the channel #git-devel on the Libera Chat IRC network:

<newcontributor> I've just created my first PR, could someone please /allow me? https://github.com/gitgitgadget/git/pull/12345
<veteran> newcontributor: it is done
<newcontributor> thanks!

Once on the list of permitted usernames, you can contribute the patches to the Git mailing list by adding a PR comment /submit.

If you want to see what email(s) would be sent for a /submit request, add a PR comment /preview to have the email(s) sent to you. You must have a public GitHub email address for this. Note that any reviewers CC'd via the list in the PR description will not actually be sent emails.

After you submit, GitGitGadget will respond with another comment that contains the link to the cover letter mail in the Git mailing list archive. Please make sure to monitor the discussion in that thread and to address comments and suggestions (while the comments and suggestions will be mirrored into the PR by GitGitGadget, you will still want to reply via mail).

If you do not want to subscribe to the Git mailing list just to be able to respond to a mail, you can download the mbox from the Git mailing list archive (click the (raw) link), then import it into your mail program. If you use GMail, you can do this via:

curl -g --user "<EMailAddress>:<Password>" \
    --url "imaps://imap.gmail.com/INBOX" -T /path/to/raw.txt

To iterate on your change, i.e. send a revised patch or patch series, you will first want to (force-)push to the same branch. You probably also want to modify your Pull Request description (or title). It is a good idea to summarize the revision by adding something like this to the cover letter (read: by editing the first comment on the PR, i.e. the PR description):

Changes since v1:
- Fixed a typo in the commit message (found by ...)
- Added a code comment to ... as suggested by ...
...

To send a new iteration, just add another PR comment with the contents: /submit.

Need help?

New contributors who want advice are encouraged to join git-mentoring@googlegroups.com, where volunteers who regularly contribute to Git are willing to answer newbie questions, give advice, or otherwise provide mentoring to interested contributors. You must join in order to post or view messages, but anyone can join.

You may also be able to find help in real time in the developer IRC channel, #git-devel on Libera Chat. Remember that IRC does not support offline messaging, so if you send someone a private message and log out, they cannot respond to you. The scrollback of #git-devel is archived, though.

@gitgitgadget
Copy link

gitgitgadget bot commented Jun 27, 2025

There are issues in commit 3a615ee:
config: read from config sequence for global scope
Lines in the body of the commit messages should be wrapped between 60 and 76 characters.
Indented lines, and lines without whitespace, are exempt

@delilahw delilahw force-pushed the lilah/fix-config-list-global-home-and-xdg/patchset branch 4 times, most recently from 3f97f81 to a44ef7c Compare June 27, 2025 07:59
@dscho
Copy link
Member

dscho commented Jun 28, 2025

/allow

@gitgitgadget
Copy link

gitgitgadget bot commented Jun 28, 2025

User delilahw is now allowed to use GitGitGadget.

Copy link

@derrickstolee derrickstolee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your code looks pretty good. I haven't validated it locally, but I only have a few stylistic things to recommend and some extra testing to try. Feel free to submit when you're ready.

@delilahw delilahw force-pushed the lilah/fix-config-list-global-home-and-xdg/patchset branch 3 times, most recently from aed07f9 to 5b253d6 Compare September 15, 2025 07:32
@delilahw
Copy link
Author

naauurrr the --show-origin path for XDG uses back slashes on windows, but the $HOME/.gitconfig path still uses forward slashes. will investigate this discrepancy.

@delilahw delilahw force-pushed the lilah/fix-config-list-global-home-and-xdg/patchset branch from 5b253d6 to 6d205b9 Compare September 19, 2025 07:05
Copy link
Member

@dscho dscho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@delilahw delilahw force-pushed the lilah/fix-config-list-global-home-and-xdg/patchset branch 2 times, most recently from 8fd6c76 to 85c6914 Compare September 25, 2025 23:15
@delilahw
Copy link
Author

/preview

@gitgitgadget
Copy link

gitgitgadget bot commented Sep 25, 2025

Preview email sent as pull.1938.git.1758842412.gitgitgadget@gmail.com

Git prefers forward slashes as directory separators across all
platforms. On Windows, the backslash is the native directory separator,
but all Windows versions supported by Git also accept the forward slash
in all but rare circumstances. Our tests expect forward slashes. Git
generates relative paths with forward slashes. Forward slashes are more
convenient to use in shell scripts.

For these reasons, we enforced forward slashes in `interpolate_path()`
in 5ca6b7b (config --show-origin: report paths with forward slashes,
2016-03-23). However, other code paths may generate paths containing
backslashes. For example, `config --show-origin` prints the XDG config
path with mixed slashes on Windows:

$ git config --list --show-origin
file:C:/Program Files/Git/etc/gitconfig         system.foo=bar
file:"C:\\Users\\delilah/.config/git/config"    xdg.foo=bar
file:C:/Users/delilah/.gitconfig                home.foo=bar
file:.git/config                                local.foo=bar

Let's enforce forward slashes in all code paths that directly or
indirectly call `cleanup_path()` by modifying it to use
`convert_slashes()` on Windows. Since `convert_slashes()` modifies the
path in-place, change the argument and return type of `cleanup_path()`
from `const char *` to `char *`. All existing callers of
`cleanup_path()` pass `char *` anyways, so this change is compatible.

The next patch, config: test home and xdg files in `list --global`, will
assert that the XDG config path uses forward slashes.

Suggested-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `git config list --global` output includes `$HOME/.gitconfig` (home
config), but ignores `$XDG_CONFIG_HOME/git/config` (XDG config). It
should include both files.

Modify tests to check the following and expect a failure:
  - `git config list --global` should include contents from both the
     home and XDG config locations (assuming they are readable), not
     just the former.

  - `--show-origin` should print correct paths to both config files,
    assuming they exist.

Also, add tests to ensure subsequent patches do not introduce
regressions to `git config list`. Specifically, check that:
  - The home config should take precedence over the XDG config.

  - Without `--global`, it should not bail on unreadable/non-existent
    global config files.

  - With `--global`, it should bail when both `$HOME/.gitconfig` and
    `$XDG_CONFIG_HOME/git/config` are unreadable. It should not bail if
    at least one of them is readable.

The next patch, config: read global scope via config_sequence, will
implement a fix to include both config files when `--global` is
specified.

Reported-by: Jade Lovelace <lists@jade.fyi>
Helped-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
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/kl6ly1oze7wb.fsf@chooglen-macbookpro.roam.corp.google.com.

Then, modify the tests to check that `git config list --global` includes
both home and XDG configs.

This patch 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, config: keep bailing
on unreadable global files.

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 config 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 <lists@jade.fyi>
Suggested-by: Glen Choo <glencbz@gmail.com>
Helped-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The expected behaviour for `git config list` is:
  A. Without `--global`, it should not bail on unreadable/non-existent
     global config files.

  B. With `--global`, it should bail when both `$HOME/.gitconfig` and
     `$XDG_CONFIG_HOME/git/config` are unreadable. It should not bail
     when one or more of them is readable.

The previous patch, config: read global scope via config_sequence,
introduced a regression in scenario B. When both global config files are
unreadable, running `git config list --global` would not fail. For
example, `GIT_CONFIG_GLOBAL=does-not-exist git config list --global`
exits with status code 0.

Assuming that `config_source->scope == CONFIG_SCOPE_GLOBAL` iff the
`--global` argument is specified, use this to determine whether to bail.
When reading only the global scope and both config files are unreadable,
then adjust the return code to be non-zero.

Note: When bailing, the exit code is not determined by sum of the return
codes of the underlying operations. Instead, the exit code is modified
via a single decrement. If this is undesirable, we can change it to sum
the return codes of the underlying operations instead.

Lastly, modify the tests to remove the known breakage/regression. The
tests for scenario B will now pass.

Helped-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@delilahw delilahw force-pushed the lilah/fix-config-list-global-home-and-xdg/patchset branch from 85c6914 to 6119cee Compare September 25, 2025 23:47
@delilahw
Copy link
Author

/preview

@gitgitgadget
Copy link

gitgitgadget bot commented Sep 25, 2025

Preview email sent as pull.1938.git.1758844142.gitgitgadget@gmail.com

@delilahw
Copy link
Author

/preview

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

Preview email sent as pull.1938.git.1760055956.gitgitgadget@gmail.com

@delilahw
Copy link
Author

/preview

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

Preview email sent as pull.1938.git.1760057555.gitgitgadget@gmail.com

@delilahw
Copy link
Author

/preview

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

Preview email sent as pull.1938.git.1760058139.gitgitgadget@gmail.com

@delilahw
Copy link
Author

/submit

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

Submitted as pull.1938.git.1760058849.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1938/delilahw/lilah/fix-config-list-global-home-and-xdg/patchset-v1

To fetch this version to local tag pr-1938/delilahw/lilah/fix-config-list-global-home-and-xdg/patchset-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1938/delilahw/lilah/fix-config-list-global-home-and-xdg/patchset-v1

@delilahw
Copy link
Author

Ohhhh a draft PR means RFC. Maybe we should write something in the initial GitGitGadget comment to mention that for newbies. Idea for the next patch, I suppose!

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

On the Git mailing list, "Kristoffer Haugsbakk" wrote (reply to this):

On Fri, Oct 10, 2025, at 03:14, Delilah Ashley Wu via GitGitGadget wrote:
> As reported in [1]: `$HOME/.gitconfig` and `$XDG_CONFIG_HOME/git/config` are
> both valid global config locations, but `git config list --global` only
> includes the former in its output.

Note only if both files exist.

-- 
Kristoffer Haugsbakk

@gitgitgadget
Copy link

gitgitgadget bot commented Oct 10, 2025

User "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> has been added to the cc: list.

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 17, 2025

On the Git mailing list, Johannes Schindelin wrote (reply to this):

Hi,

On Fri, 10 Oct 2025, Delilah Ashley Wu via GitGitGadget wrote:

> As reported in [1]: `$HOME/.gitconfig` and `$XDG_CONFIG_HOME/git/config` are
> both valid global config locations, but `git config list --global` only
> includes the former in its output.
> 
> Suppose we have this config in `$HOME/.gitconfig`:
> 
> [home]
>     config = true
> 
> 
> And this config in `$XDG_CONFIG_HOME/git/config`:
> 
> [xdg]
>     config = true
> 
> 
> Then, to reproduce the issue that `--global` only shows the home config:
> 
> $ git config list --global --show-scope --show-origin
> global  file:/Users/delilah/.gitconfig    home.config=true
> 
> 
> Git correctly applies the XDG config in its effective configuration, but it
> doesn't show up when `--global` is specified. We can confirm this by
> checking the output without the `--global` flag:
> 
> $ git config list --show-scope --show-origin
> global  file:/Users/delilah/.config/git/config    xdg.config=true
> global  file:/Users/delilah/.gitconfig            home.config=true
> 
> 
> The expected behaviour is both configs should be shown when `--global` is
> specified, so we'd expect its output to look the same as above. This was
> confirmed in [2], which quoted the `git config` documentation:
> 
> > OPTIONS
> >     --global::
> >         For writing options: write to global `~/.gitconfig` file
> >         rather than the repository `.git/config`, write to
> >         `$XDG_CONFIG_HOME/git/config` file if this file exists and the
> >         `~/.gitconfig` file doesn't.
> >
> >         For reading options: read only from global `~/.gitconfig` and from
> >         `$XDG_CONFIG_HOME/git/config` rather than from all available files.
> 
> 
> The first patch fixes forward slash normalisation on Windows paths. The
> second patch introduces tests and regression checks. The third and fourth
> patches implement the fix to include both config files when `--global` is
> specified. Johannes has kindly pre-reviewed this patch series via GitHub on
> GitGitGadget #1938 [3]. You'll notice some force-pushes after the review,
> but I only changed commit messages.
> 
> [1]:
> https://lore.kernel.org/git/CAFA9we-QLQRzJdGMMCPatmfrk1oHeiUu9msMRXXk1MLE5HRxBQ@mail.gmail.com/
> [2]: https://lore.kernel.org/git/xmqqmt5lezi3.fsf@gitster.g/
> [3]: https://github.com/gitgitgadget/git/pull/1938/
> 
> Thank you all for your time!

For the record, my "Reviewed-by:" still stands, if lack of reviews should
be the reason why this patch series has not even entered the `seen`
branch.

Ciao,
Johannes

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 18, 2025

On the Git mailing list, Junio C Hamano wrote (reply to this):

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> For the record, my "Reviewed-by:" still stands, if lack of reviews should
> be the reason why this patch series has not even entered the `seen`
> branch.

Thanks for pinging.

"Why is it not in 'next'" is a legitimate question.  I think that is
because the topic has no discussion on the list in the thread.

"Why is it in 'seen'" is a question with no answer.  As I often say,
'seen' is merely what I happened to have seen and found it promising
but is not ready for 'next', and people should not read anything
more into it.

I didn't look at it primarily because nobody, not even one on a
handful of experienced contributors whose opinions are well regarded
in the community on the CC: list, responded to the thread at all.
Before the message I am responding to, that is ;-)

I wanted to see how well people receive the motivation behind the
proposed change, as I vaguely recalled that not using both at the
same time was deliberate to help those who migrate from historical
location to XDG layout, but did not have time and energy to do the
digging myself to become knowledgeable again to give any comment
worth reading.

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 19, 2025

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Delilah Ashley Wu via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> As reported in [1]: `$HOME/.gitconfig` and `$XDG_CONFIG_HOME/git/config` are
> both valid global config locations, but `git config list --global` only
> includes the former in its output.

... while "git config list" includes both, which is an inconsistency
without good reason.

Thanks for addressing this issue.  I haven't had a chance to look at
these patches yet, but both analysis and Glen's outline for the best
approach presented in the thread [1] do look very sensible.

What is the reason behind [RFC] in the title?  Are there things that
are iffy yourself in the patches that reviewers want to pay special
attention to?

Thanks.

struct strbuf *sb = &pathname_array[index];
index = (index + 1) % ARRAY_SIZE(pathname_array);
strbuf_reset(sb);
return sb;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Delilah Ashley Wu via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> All existing callers of
> `cleanup_path()` pass `char *` anyways, so this change is compatible.

Not just compatible ;-).  If there is a caller that wants
cleanup_path() not to munge what it passes, this change will
introduce a bug for them.  Have you made sure that none of these
callers mind that backslashes are converted into forward slashes?

> The next patch, config: test home and xdg files in `list --global`, will
> assert that the XDG config path uses forward slashes.

The path to the leaf-level blobs is always slash separated in the
index, a tree object sorts an entry that points at a subtree as if
its path component has terminating slash, etc., and only when these
paths are externalized, they are converted to filesystem dependent
hierarchy separator (by system call like creat(2) even on platforms
like Windows whose filesystem uses backslashes as the pathname
separator).  Canonicalizing end-user supplied path early at a
central place does make sense.

> -static const char *cleanup_path(const char *path)
> +static char *cleanup_path(char *path)
>  {
>  	/* Clean it up */
> -	if (skip_prefix(path, "./", &path)) {
> +	if (skip_prefix(path, "./", (const char **)&path))
>  		while (*path == '/')
>  			path++;
> -	}

Hmph, the need for cast is a bit annoying, but more importantly, why
don't we have to worry about leading ".\\\\" instead of ".////"?
Shouldn't we be stripping backslashes the same way on Windows?

> +#ifdef GIT_WINDOWS_NATIVE
> +	convert_slashes(path);
> +#endif

In other words, why do it here, not _before_ the loop that says "If
the path begins with dot (i.e. the thing is relative to the current
directory) followed by a directory separator, remove it together
with any extra directory separators that come immediately after it"?

>  	return path;
>  }

test_expect_success '--show-scope with --default' '
git config --show-scope --default foo some.key >actual &&
echo "command foo" >expect &&
test_cmp expect actual
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Delilah Ashley Wu via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Delilah Ashley Wu <delilahwu@microsoft.com>
>
> The `git config list --global` output includes `$HOME/.gitconfig` (home
> config), but ignores `$XDG_CONFIG_HOME/git/config` (XDG config). It
> should include both files.

Please be gentle to future readers of "git log" and help them with a
bit more explanation on the "should" here.  E.g., 

    should include both files, to be consistent with the output from
    `git config list` (not limited to `--global`) that lists entries
    from both files (in addition to system-wide and repository-specific
    entries, of course).

or something.

> Modify tests to check the following and expect a failure:
>   - `git config list --global` should include contents from both the
>      home and XDG config locations (assuming they are readable), not
>      just the former.
>
>   - `--show-origin` should print correct paths to both config files,
>     assuming they exist.

Testing these two combinations is a good thing, but "expect a
failure"?  There doesn't seem to be any test that is marked as
"test_expect_failure" in this patch.  Confused?

    Side note: we generally do not want test_expect_failure tests in
    one patch, followed by a code fix with changes to tests that
    flip s/test_expect_failure/test_expect_success/' in another
    patch, though.  The reason is primarily that such a two-patch
    series makes it harder to review the step that has the fix, by
    hiding the body of the test whose earlier failure gets fixed by
    the code change.

> Also, add tests to ensure subsequent patches do not introduce
> regressions to `git config list`. Specifically, check that:
>   - The home config should take precedence over the XDG config.
>
>   - Without `--global`, it should not bail on unreadable/non-existent
>     global config files.
>
>   - With `--global`, it should bail when both `$HOME/.gitconfig` and
>     `$XDG_CONFIG_HOME/git/config` are unreadable. It should not bail if
>     at least one of them is readable.

Good.

> The next patch, config: read global scope via config_sequence, will
> implement a fix to include both config files when `--global` is
> specified.
>
> Reported-by: Jade Lovelace <lists@jade.fyi>
> Helped-by: Derrick Stolee <stolee@gmail.com>
> Signed-off-by: Delilah Ashley Wu <delilahwu@microsoft.com>
> Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  t/t1300-config.sh    | 65 ++++++++++++++++++++++++++++++++++++++++++++
>  t/t1306-xdg-files.sh |  5 ++--
>  2 files changed, 68 insertions(+), 2 deletions(-)
>
> diff --git a/t/t1300-config.sh b/t/t1300-config.sh
> index f856821839..5fa0111bd9 100755
> --- a/t/t1300-config.sh
> +++ b/t/t1300-config.sh
> @@ -2367,6 +2367,71 @@ test_expect_success '--show-scope with --default' '
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'list with nonexistent global config' '
> +	rm -rf "$HOME"/.gitconfig "$HOME"/.config/git/config &&
> +	git config ${mode_prefix}list --show-scope
> +'

Do we expect an empty output, or are we happy as long as "git
config" does not segfault, even if it spews anything?  I guess that
at this late point in the test we have per-repository or system-wide
configuration files with something in them to test, so there would
be some output but we do not care?  If that is the case, not
checking the output, like this patch does, is the right thing.

> +test_expect_success '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
> +'

OK.  Do we require --show-scope to fail this, or do we fail with and
without --show-scope as long as --global is in effect?  If the latter,
test both ...

	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

... like this, perhaps?  Also, don't overuse '-r' with 'rm' (applies
other tests in this patch) when you know what you are removing
should not be a directory.

> +test_expect_success 'list --global with only home' '
> +	rm -rf "$HOME"/.config/git/config &&

Lose "r" from "-rf" or lose "/config".

> +	test_when_finished rm -f \"\$HOME\"/.gitconfig &&
> +	cat >"$HOME"/.gitconfig <<-EOF &&
> +	[home]
> +		config = true
> +	EOF
> +
> +	cat >expect <<-EOF &&
> +	global	home.config=true
> +	EOF
> +	git config ${mode_prefix}list --global --show-scope >output &&
> +	test_cmp expect output
> +'

OK.

> +test_expect_success 'list --global with only xdg' '
> +	rm -f "$HOME"/.gitconfig &&
> +
> +	test_when_finished rm -rf \"\$HOME\"/.config/git &&
> +	mkdir -p "$HOME"/.config/git &&
> +	cat >"$HOME"/.config/git/config <<-EOF &&
> +	[xdg]
> +		config = true
> +	EOF
> +
> +	cat >expect <<-EOF &&
> +	global	xdg.config=true
> +	EOF
> +	git config ${mode_prefix}list --global --show-scope >output &&
> +	test_cmp expect output
> +'

OK.

> +test_expect_success 'list --global with both home and xdg' '
> +	test_when_finished rm -f \"\$HOME\"/.gitconfig &&
> +	cat >"$HOME"/.gitconfig <<-EOF &&
> +	[home]
> +		config = true
> +	EOF
> +
> +	test_when_finished rm -rf \"\$HOME\"/.config/git &&
> +	mkdir -p "$HOME"/.config/git &&
> +	cat >"$HOME"/.config/git/config <<-EOF &&
> +	[xdg]
> +		config = true
> +	EOF
> +
> +	cat >expect <<-EOF &&
> +	global	file:$HOME/.config/git/config	xdg.config=true
> +	global	file:$HOME/.gitconfig	home.config=true
> +	EOF
> +	git config ${mode_prefix}list --global --show-scope --show-origin >output &&
> +	! test_cmp expect output
> +'

Do not write a test this way.  If you want to document an existing
and unfixed breakage, instead of saying "we do want to see what is
in this expect file, but we know output does not unfortunately match
it", which is how the above test expresses it, start the whole thing
with "test_expect_failure" (instead of "test_expect_success"), and
have the body of the test express what you really want to see.  I.e.
the last steps should say

	git config ${mode_prefix}list --global --show-scope --show-origin >actual &&
	test_cmp expect actual

But an earier side note applies.  If "git config list --global" gets
corrected, this test will see update to turn "! test_cmp" into
"test_cmp" (or "test_expect_success" to "test_expect_failure"), and
such a patch that comes with the code fix will not show what is
being tested and forcing the reviewer to go back to the previous
step to see what the change is really about.  A test that
demonstrates and protects the behaviour corrected by the code change
is best added in the same patch as the code change.

> diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh
> index 40d3c42618..0318755799 100755
> --- a/t/t1306-xdg-files.sh
> +++ b/t/t1306-xdg-files.sh
> @@ -68,9 +68,10 @@ test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists'
>  	>.gitconfig &&
>  	echo "[user]" >.gitconfig &&
>  	echo "	name = read_gitconfig" >>.gitconfig &&
> -	echo user.name=read_gitconfig >expected &&
> +	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
>  '

I cannot quite tell from only half the test, but I suspect that this
shares exactly the same problem with the last one in the other file
I commented above?

Thanks.

opts->source.file = NULL;
opts->source.use_stdin = 1;
opts->source.scope = CONFIG_SCOPE_COMMAND;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Delilah Ashley Wu via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Delilah Ashley Wu <delilahwu@microsoft.com>
>
> 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.

", but" -> "to match the information given by the command without
--global, but".

> This patch 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, config: keep bailing
> on unreadable global files.

That is rather unfortunate, as we do try hard to avoid deliberate
regressions in our history.  The reason why this step cannot be done
without first introducing a regression is...?

If the reason is "it would make a single patch too big", perhaps we
can do it in two steps, one preliminary "git_config_sequence() learns
an extra barf-if-no-input parameter that causes it to return error if
no files in the specified sequence exists" step, followed by this
change that starts using git_config_sequence() to handle "--global",
which uses that new flag to ensure that there won't be a regression?

>  	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;

Very nicely done.

Thanks.

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 19, 2025

This patch series was integrated into seen via git@24ced25.

@gitgitgadget gitgitgadget bot added the seen label Nov 19, 2025
@gitgitgadget
Copy link

gitgitgadget bot commented Nov 20, 2025

This patch series was integrated into seen via git@873af45.

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 21, 2025

This branch is now known as dw/config-global-list.

@gitgitgadget
Copy link

gitgitgadget bot commented Nov 21, 2025

This patch series was integrated into seen via git@c398ad3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants