From: Patrick Steinhardt <hidden> Date: 2021-04-08 14:18:20
While it's already possible to stop git from reading the system config
via GIT_CONFIG_NOSYSTEM, doing the same for global config files requires
the user to unset both HOME and XDG_CONFIG_HOME. This is an awkward
interface and may even pose a problem e.g. when git hooks rely on these
variables to be present.
Introduce a new GIT_CONFIG_NOGLOBAL envvar, which is the simple
equivalent to GIT_CONFIG_NOSYSTEM. If set to true, git will skip reading
both `~/.gitconfig` and `$XDG_CONFIG_HOME/git/config`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Documentation/git-config.txt | 4 ++++
Documentation/git.txt | 16 ++++++++++++----
config.c | 9 +++++++--
t/t1300-config.sh | 31 +++++++++++++++++++++++++++++++
4 files changed, 54 insertions(+), 6 deletions(-)
@@ -340,6 +340,10 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_NOGLOBAL::+ Whether to skip reading settings from the global ~/.gitconfig and+ $XDG_CONFIG_HOME/git/config files. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,13 +670,21 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_NOGLOBAL`::+ Whether to skip reading settings from the system-wide `~/.gitconfig`+ and `$XDG_CONFIG_HOME/git/config` files. This environment variable can+ be used along with `$GIT_CONFIG_NOSYSTEM` to create a predictable+ environment for a picky script, or you can set it temporarily to avoid+ using a buggy global config file while waiting for someone with+ sufficient permissions to fix it.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can- be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a- predictable environment for a picky script, or you can set it- temporarily to avoid using a buggy `/etc/gitconfig` file while- waiting for someone with sufficient permissions to fix it.+ be used along with `$GIT_CONFIG_NOGLOBAL` to create a predictable+ environment for a picky script, or you can set it temporarily to avoid+ using a buggy `/etc/gitconfig` file while waiting for someone with+ sufficient permissions to fix it. `GIT_FLUSH`:: If this environment variable is set to "1", then commands such
From: Eric Sunshine <hidden> Date: 2021-04-08 16:44:56
On Thu, Apr 8, 2021 at 10:18 AM Patrick Steinhardt [off-list ref] wrote:
quoted hunk
While it's already possible to stop git from reading the system config
via GIT_CONFIG_NOSYSTEM, doing the same for global config files requires
the user to unset both HOME and XDG_CONFIG_HOME. This is an awkward
interface and may even pose a problem e.g. when git hooks rely on these
variables to be present.
Introduce a new GIT_CONFIG_NOGLOBAL envvar, which is the simple
equivalent to GIT_CONFIG_NOSYSTEM. If set to true, git will skip reading
both `~/.gitconfig` and `$XDG_CONFIG_HOME/git/config`.
Signed-off-by: Patrick Steinhardt <redacted>
---
@@ -670,13 +670,21 @@ for further details.+`GIT_CONFIG_NOGLOBAL`::+ Whether to skip reading settings from the system-wide `~/.gitconfig`+ and `$XDG_CONFIG_HOME/git/config` files. This environment variable can+ be used along with `$GIT_CONFIG_NOSYSTEM` to create a predictable+ environment for a picky script, or you can set it temporarily to avoid+ using a buggy global config file while waiting for someone with+ sufficient permissions to fix it.
Not necessarily a new problem since you mostly copied the new text
from GIT_CONFIG_NOSYSTEM, but this doesn't tell the reader what value
to assign to this variable. As currently written, I would end up
having to consult the source code to figure out how to use this
variable, which makes the documentation less useful than it should be.
Perhaps it could be rewritten something like:
If set to any value, suppress reading global configuration
from `~/.gitconfig` and `$XDG_CONFIG_HOME/git/config`
files. This environment variable...
The bit about waiting for someone to fix a buggy ~/.gitconfig is
somewhat questionable; it might make sense to drop everything after
"picky script".
`GIT_CONFIG_NOSYSTEM`::
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
- be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
- predictable environment for a picky script, or you can set it
- temporarily to avoid using a buggy `/etc/gitconfig` file while
- waiting for someone with sufficient permissions to fix it.
+ be used along with `$GIT_CONFIG_NOGLOBAL` to create a predictable
+ environment for a picky script, or you can set it temporarily to avoid
+ using a buggy `/etc/gitconfig` file while waiting for someone with
+ sufficient permissions to fix it.
This suffers the same problem of not telling the reader what value to
assign. A similar rewrite could improve it, as well.
+`GIT_CONFIG_NOGLOBAL`::
+ Whether to skip reading settings from the system-wide `~/.gitconfig`
+ and `$XDG_CONFIG_HOME/git/config` files. This environment variable can
Let's not call ~/.gitconfig system-wide with /etc/gitconfig being,
saying "global" is consistent with git-config's own
--global/--system/--local etc. Still a bit odd, but at least the same
nomenclature.
From: Patrick Steinhardt <hidden> Date: 2021-04-09 13:43:30
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 2 +-
config.c | 6 +++---
config.h | 3 ++-
3 files changed, 6 insertions(+), 5 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-09 13:43:31
Hi,
this is the second version of my patch series to provide a way of
overriding the global system configuration.
Instead of going for GIT_CONFIG_NOGLOBAL, I've adopted Junio's proposal
of going with GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM, which allow a
user to modify the locations of those files. Thanks for the discussion,
this solution feels a lot nicer to me!
Patrick
Patrick Steinhardt (3):
config: rename `git_etc_config()`
config: unify code paths to get global config paths
config: allow overriding of global and system configuration
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 8 ++--
config.c | 56 ++++++++++++++++++++++-----
config.h | 4 +-
t/t1300-config.sh | 75 ++++++++++++++++++++++++++++++++++++
6 files changed, 143 insertions(+), 15 deletions(-)
--
2.31.1
From: Patrick Steinhardt <hidden> Date: 2021-04-09 13:43:31
There's two callsites which assemble global config paths, once in the
config loading code and once in the git-config(1) builtin. We're about
to implement a way to override global config paths via an environment
variable which would require us to adjust both sites.
Unify both code paths into a single `git_global_config()` function which
returns both paths for `~/.gitconfig` and the XDG config file. This will
make the subsequent patch which introduces the new envvar easier to
implement.
No functional changes are expected from this patch.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 6 ++----
config.c | 20 ++++++++++++++++----
config.h | 1 +
3 files changed, 19 insertions(+), 8 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-09 13:43:35
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOSYSTEM`
as an equivalent to `GIT_CONFIG_NOGLOBAL`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. This path must
exist and be readable to ensure that the user didn't typo.
- If set to `/dev/null`, we do not load either global- or
system-level configuration at all.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
config.c | 34 ++++++++++++++--
t/t1300-config.sh | 75 ++++++++++++++++++++++++++++++++++++
4 files changed, 120 insertions(+), 4 deletions(-)
@@ -340,6 +340,11 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_GLOBAL::+GIT_CONFIG_SYSTEM::+ Take the configuration from the given files instead from global or+ system-level configuration. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. The files must exist and be readable+ by the current user. If `GIT_CONFIG_SYSTEM` is set, `/etc/gitconfig`+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can
@@ -2059,6 +2059,81 @@ test_expect_success '--show-scope with --show-origin' 'test_cmpexpectoutput'+test_expect_success'override global and system config''+test_when_finishedrm-f"$HOME"/.config/git&&++cat>"$HOME"/.gitconfig<<-EOF&&+[home]+config=true+EOF+mkdir-p"$HOME"/.config/git&&+cat>"$HOME"/.config/git/config<<-EOF&&+[xdg]+config=true+EOF+cat>.git/config<<-EOF&&+[local]+config=true+EOF+cat>custom-global-config<<-EOF&&+[global]+config=true+EOF+cat>custom-system-config<<-EOF&&+[system]+config=true+EOF++cat>expect<<-EOF&&+globalxdg.config=true+globalhome.config=true+locallocal.config=true+EOF+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++sane_unsetGIT_CONFIG_NOSYSTEM&&++cat>expect<<-EOF&&+systemsystem.config=true+globalglobal.config=true+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++cat>expect<<-EOF&&+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+test_cmpexpectoutput+'++test_expect_success'override global and system config with missing file''+sane_unsetGIT_CONFIG_NOSYSTEM&&+test_must_failenvGIT_CONFIG_GLOBAL=does-not-existgitversion&&+test_must_failenvGIT_CONFIG_SYSTEM=does-not-existgitversion&&+GIT_CONFIG_NOSYSTEM=trueGIT_CONFIG_SYSTEM=does-not-existgitversion+'++test_expect_success'write to overridden global and system config''+cat>expect<<EOF&&+[config]+key=value+EOF++test_must_failenvGIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+touchwrite-to-global&&+GIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+test_cmpexpectwrite-to-global&&++test_must_failenvGIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+touchwrite-to-system&&+GIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+test_cmpexpectwrite-to-system+'+foroptin--local--worktreedotest_expect_success"$opt requires a repo"'
From: Jeff King <hidden> Date: 2021-04-09 15:13:24
On Fri, Apr 09, 2021 at 03:43:21PM +0200, Patrick Steinhardt wrote:
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
Looks good. This name has been a minor annoyance for years. :)
-Peff
From: Jeff King <hidden> Date: 2021-04-09 15:21:20
On Fri, Apr 09, 2021 at 03:43:25PM +0200, Patrick Steinhardt wrote:
There's two callsites which assemble global config paths, once in the
config loading code and once in the git-config(1) builtin. We're about
to implement a way to override global config paths via an environment
variable which would require us to adjust both sites.
Unify both code paths into a single `git_global_config()` function which
returns both paths for `~/.gitconfig` and the XDG config file. This will
make the subsequent patch which introduces the new envvar easier to
implement.
Seems like a good step forward. There is one minor issue with the
implementation, though.
The pointer out-parameters make sense here, since we need to return two
values. I notice they became const, so the function will hold on to
ownership of the memory.
And here in the implementation we hold on to the static values forever.
I think your "did we initialize already" check isn't robust, though.
expand_user_path() can return NULL, in which case every call would
trigger a re-initialization (even leaking xdg_config if it was set in
the last round).
So I think you'd need a separate "static int initialized" variable.
That said, I wonder if we should just pass ownership of the memory to
the caller. It is a minor inconvenience that they will have to free()
the result, but we're already doing that. And it removes any possibility
of thread unsafety.
I guess it doesn't match git_system_config() as well, then. But arguably
it should also just pass ownership (it also has only a handful of
callers, and freeing the result would not be a big deal).
I'm OK with either solution, though.
-Peff
From: Jeff King <hidden> Date: 2021-04-09 15:38:34
On Fri, Apr 09, 2021 at 03:43:30PM +0200, Patrick Steinhardt wrote:
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOSYSTEM`
as an equivalent to `GIT_CONFIG_NOGLOBAL`. But in the past, it has
I think you have NOSYSTEM and NOGLOBAL mixed up in both paragraphs here?
Otherwise the motivation and description here look very good (and I like
the overall direction).
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. The files must exist and be readable+ by the current user. If `GIT_CONFIG_SYSTEM` is set, `/etc/gitconfig`+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.
Makes sense. The reference to `/etc/gitconfig` here may not be accurate,
depending on the build parameters. I notice below in the context that we
say:
`GIT_CONFIG_NOSYSTEM`::
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
which is _also_ not quite right (if $(prefix) is "/usr", then the file
really is /etc/gitconfig).
I think it might be possible to pull the value of the ETC_GITCONFIG
Makefile variable into the documentation, so we could probably give the
"real" value. But I wonder if it would suffice to just say:
...the system config (usually `/etc/gitconfig`) will not be read.
Or is that too confusing (it invites the question "when is it not
/etc/gitconfig")? I guess we could say "the system config file defined
at build-time (usually `/etc/gitconfig`)", which is perhaps more clear.
quoted hunk
@@ -1847,8 +1847,22 @@ static int git_config_from_blob_ref(config_fn_t fn, const char *git_system_config(void) { static const char *system_wide;- if (!system_wide)- system_wide = system_path(ETC_GITCONFIG);++ if (!system_wide) {+ system_wide = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
I wondered, given the "const char *" return values in the last patch, if
you might pass back the result of getenv() directly. But you duplicate
it here, which is good, as it avoids portability problems hanging on to
the result of getenv().
+ if (system_wide) {
+ /*
+ * If GIT_CONFIG_SYSTEM is set, it overrides the
+ * /etc/gitconfig. Furthermore, the file must exist in
+ * order to prevent any typos by the user.
+ */
+ if (access(system_wide, R_OK))
+ die(_("cannot access '%s'"), system_wide);
+ } else {
+ system_wide = system_path(ETC_GITCONFIG);
+ }
+ }
I was on the fence about whether to enforce the "this file must exist"
property, with respect to the overall design. But seeing how we must
actually add extra code here to handle it makes me want to just treat it
exactly like the other files.
Using a separate access() here is also a TOCTOU race, but I'm pretty
sure the existing config code makes the same mistake (and it's not that
big a deal in this context).
quoted hunk
@@ -1857,8 +1871,20 @@ void git_global_config(const char **user, const char **xdg) static const char *user_config, *xdg_config; if (!user_config) {- user_config = expand_user_path("~/.gitconfig", 0);- xdg_config = xdg_config_home("config");+ user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));+ if (user_config) {+ /*+ * If GIT_CONFIG_GLOBAL is set, then it overrides both+ * the ~/.gitconfig and the XDG configuration file.+ * Furthermore, the file must exist in order to prevent+ * any typos by the user.+ */+ if (access(user_config, R_OK))+ die(_("cannot access '%s'"), user_config);+ } else {+ user_config = expand_user_path("~/.gitconfig", 0);+ xdg_config = xdg_config_home("config");+ } }
And this looks as I'd expect (but the same comments as above apply, of
course).
Minor style nit, but we usually prefer non-interpolating "\EOF" if we
don't intend to interpolate within the here-doc. It does look like
t1300 has quite a mix of styles, though.
And this test covers all of the new stuff we care about. Good.
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist git version &&
+ test_must_fail env GIT_CONFIG_SYSTEM=does-not-exist git version &&
+ GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=does-not-exist git version
+'
Makes sense to test given the patch, though if we rip out the "missing"
check, then obviously this goes away.
+test_expect_success 'write to overridden global and system config' '
Hmm. I hadn't really considered _writing_ to these files (after all, you
can just use "git config --file" to do so). I guess it is consistent,
and would probably be more work (and more error-prone) to try to
distinguish reading versus writing in the code.
In the writing case, the "must exist" thing makes it even weirder, since
we might be intending to create the file! If we leave in the writing,
that makes me even more convinced that we should drop the "must exist"
check.
-Peff
From: Jeff King <hidden> Date: 2021-04-09 15:41:22
On Fri, Apr 09, 2021 at 03:43:16PM +0200, Patrick Steinhardt wrote:
Instead of going for GIT_CONFIG_NOGLOBAL, I've adopted Junio's proposal
of going with GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM, which allow a
user to modify the locations of those files. Thanks for the discussion,
this solution feels a lot nicer to me!
Thanks, I like this much better. I left a few comments on the patches
themselves. Mostly small suggestions, but design-wise I'm of the opinion
we should drop the "file must exist" requirement; see the response to
patch 3.
-Peff
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:04:11
On Fri, Apr 09, 2021 at 11:38:31AM -0400, Jeff King wrote:
On Fri, Apr 09, 2021 at 03:43:30PM +0200, Patrick Steinhardt wrote:
quoted
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOSYSTEM`
as an equivalent to `GIT_CONFIG_NOGLOBAL`. But in the past, it has
I think you have NOSYSTEM and NOGLOBAL mixed up in both paragraphs here?
Otherwise the motivation and description here look very good (and I like
the overall direction).
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. The files must exist and be readable+ by the current user. If `GIT_CONFIG_SYSTEM` is set, `/etc/gitconfig`+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.
Makes sense. The reference to `/etc/gitconfig` here may not be accurate,
depending on the build parameters. I notice below in the context that we
say:
quoted
`GIT_CONFIG_NOSYSTEM`::
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
which is _also_ not quite right (if $(prefix) is "/usr", then the file
really is /etc/gitconfig).
I think it might be possible to pull the value of the ETC_GITCONFIG
Makefile variable into the documentation, so we could probably give the
"real" value. But I wonder if it would suffice to just say:
...the system config (usually `/etc/gitconfig`) will not be read.
Or is that too confusing (it invites the question "when is it not
/etc/gitconfig")? I guess we could say "the system config file defined
at build-time (usually `/etc/gitconfig`)", which is perhaps more clear.
quoted
@@ -1847,8 +1847,22 @@ static int git_config_from_blob_ref(config_fn_t fn, const char *git_system_config(void) { static const char *system_wide;- if (!system_wide)- system_wide = system_path(ETC_GITCONFIG);++ if (!system_wide) {+ system_wide = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
I wondered, given the "const char *" return values in the last patch, if
you might pass back the result of getenv() directly. But you duplicate
it here, which is good, as it avoids portability problems hanging on to
the result of getenv().
quoted
+ if (system_wide) {
+ /*
+ * If GIT_CONFIG_SYSTEM is set, it overrides the
+ * /etc/gitconfig. Furthermore, the file must exist in
+ * order to prevent any typos by the user.
+ */
+ if (access(system_wide, R_OK))
+ die(_("cannot access '%s'"), system_wide);
+ } else {
+ system_wide = system_path(ETC_GITCONFIG);
+ }
+ }
I was on the fence about whether to enforce the "this file must exist"
property, with respect to the overall design. But seeing how we must
actually add extra code here to handle it makes me want to just treat it
exactly like the other files.
Using a separate access() here is also a TOCTOU race, but I'm pretty
sure the existing config code makes the same mistake (and it's not that
big a deal in this context).
quoted
@@ -1857,8 +1871,20 @@ void git_global_config(const char **user, const char **xdg) static const char *user_config, *xdg_config; if (!user_config) {- user_config = expand_user_path("~/.gitconfig", 0);- xdg_config = xdg_config_home("config");+ user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));+ if (user_config) {+ /*+ * If GIT_CONFIG_GLOBAL is set, then it overrides both+ * the ~/.gitconfig and the XDG configuration file.+ * Furthermore, the file must exist in order to prevent+ * any typos by the user.+ */+ if (access(user_config, R_OK))+ die(_("cannot access '%s'"), user_config);+ } else {+ user_config = expand_user_path("~/.gitconfig", 0);+ xdg_config = xdg_config_home("config");+ } }
And this looks as I'd expect (but the same comments as above apply, of
course).
Minor style nit, but we usually prefer non-interpolating "\EOF" if we
don't intend to interpolate within the here-doc. It does look like
t1300 has quite a mix of styles, though.
And this test covers all of the new stuff we care about. Good.
quoted
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist git version &&
+ test_must_fail env GIT_CONFIG_SYSTEM=does-not-exist git version &&
+ GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=does-not-exist git version
+'
Makes sense to test given the patch, though if we rip out the "missing"
check, then obviously this goes away.
quoted
+test_expect_success 'write to overridden global and system config' '
Hmm. I hadn't really considered _writing_ to these files (after all, you
can just use "git config --file" to do so). I guess it is consistent,
and would probably be more work (and more error-prone) to try to
distinguish reading versus writing in the code.
In the writing case, the "must exist" thing makes it even weirder, since
we might be intending to create the file! If we leave in the writing,
that makes me even more convinced that we should drop the "must exist"
check.
-Peff
I do agree that for the writing side it's limiting to require the file
to exist. The question is really what's gained by it. The worst thing
that could happen is that the user writes to a file he didn't intend to
write to -- this can happen regardless of whether or not the file
exists, and in fact the worse case is where we overwrite values of a
file which the user didn't intend to overwrite. The case where we create
a new file by accident doesn't seem to be that interesting to me.
In any case, the user would probably use `git config -f` anyway. Which
raises the question whether it's sensible to allow writing to the file
in the first place. And for the sake of scripts, I lean towards "yes":
the dev can set up envvars once, and then use the config for both
reading and writing.
On the reading side, I can relate with Junio's argument that there's now
two possibilities for typos: once in the envvar, and once in the file
path. But given that git won't check the envvar's key for typos, we
cannot really reduce the chance for typos down to zero anyway.
So I do tend towards just allowing for the file to not exist: when
reading, we silentely ignore it, and when writing we create it.
Patrick
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:46:50
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
While at it, the function is also refactored to pass memory ownership to
the caller. This is done to better match semantics of
`git_global_config()`, which is going to be introduced in the next
commit.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 2 +-
config.c | 18 ++++++++----------
config.h | 3 ++-
3 files changed, 11 insertions(+), 12 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:46:50
Hi,
this is the third version of my patch series to provide a way of
overriding the global system configuration.
Changes compared to v2:
- `/dev/null` is now truly special-cased to skip reading any file
such that it's possible to use it e.g. in environments where this
special file does not exist.
- There is no explicit requirement for the given files to exist
anymore. On the reading side, it will in most cases just be
ignored (except for e.g. `git config --global --list` and similar,
where we'd also fail if the normal global config didn't exist). On
the writing site, we now create the config file it it's missing.
- Both `git_system_config()` and `git_global_config()` now pass
memory ownership to the caller.
Patrick
Patrick Steinhardt (3):
config: rename `git_etc_config()`
config: unify code paths to get global config paths
config: allow overriding of global and system configuration
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 12 ++++--
config.c | 48 ++++++++++++++++++------
config.h | 4 +-
t/t1300-config.sh | 71 ++++++++++++++++++++++++++++++++++++
6 files changed, 133 insertions(+), 17 deletions(-)
Range-diff against v2:
1: da0b8ce6f0 ! 1: 34bdbc27d6 config: rename `git_etc_config()`
@@ Commit message
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
+ While at it, the function is also refactored to pass memory ownership to
+ the caller. This is done to better match semantics of
+ `git_global_config()`, which is going to be introduced in the next
+ commit.
Signed-off-by: Patrick Steinhardt [off-list ref]
@@ config.c: static int git_config_from_blob_ref(config_fn_t fn,
}
-const char *git_etc_gitconfig(void)
-+const char *git_system_config(void)
++char *git_system_config(void)
{
- static const char *system_wide;
- if (!system_wide)
+- static const char *system_wide;
+- if (!system_wide)
+- system_wide = system_path(ETC_GITCONFIG);
+- return system_wide;
++ return system_path(ETC_GITCONFIG);
+ }
+
+ /*
+@@ config.c: static int do_git_config_sequence(const struct config_options *opts,
+ config_fn_t fn, void *data)
+ {
+ int ret = 0;
++ char *system_config = git_system_config();
+ char *xdg_config = xdg_config_home("config");
+ char *user_config = expand_user_path("~/.gitconfig", 0);
+ char *repo_config;
@@ config.c: static int do_git_config_sequence(const struct config_options *opts,
repo_config = NULL;
current_parsing_scope = CONFIG_SCOPE_SYSTEM;
- if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK,
-+ if (git_config_system() && !access_or_die(git_system_config(), R_OK,
- opts->system_gently ?
- ACCESS_EACCES_OK : 0))
+- opts->system_gently ?
+- ACCESS_EACCES_OK : 0))
- ret += git_config_from_file(fn, git_etc_gitconfig(),
-+ ret += git_config_from_file(fn, git_system_config(),
- data);
+- data);
++ if (system_config && !access_or_die(system_config, R_OK,
++ opts->system_gently ?
++ ACCESS_EACCES_OK : 0))
++ ret += git_config_from_file(fn, system_config, data);
current_parsing_scope = CONFIG_SCOPE_GLOBAL;
+ if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
+@@ config.c: static int do_git_config_sequence(const struct config_options *opts,
+ die(_("unable to parse command-line config"));
+
+ current_parsing_scope = prev_parsing_scope;
++ free(system_config);
+ free(xdg_config);
+ free(user_config);
+ free(repo_config);
## config.h ##
@@ config.h: int git_config_rename_section(const char *, const char *);
@@ config.h: int config_error_nonbool(const char *);
#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
#endif
-+const char *git_system_config(void);
++char *git_system_config(void);
+
int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
2: dddc85bcf5 < -: ---------- config: unify code paths to get global config paths
-: ---------- > 2: 30f18679bd config: unify code paths to get global config paths
3: 272a3b31aa ! 3: af663640ae config: allow overriding of global and system configuration
@@ Commit message
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
- The obvious way to fix this would be to introduce `GIT_CONFIG_NOSYSTEM`
- as an equivalent to `GIT_CONFIG_NOGLOBAL`. But in the past, it has
+ The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
+ as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
@@ Commit message
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
- configuration files and instead take the path. This path must
- exist and be readable to ensure that the user didn't typo.
+ configuration files and instead take the path.
- If set to `/dev/null`, we do not load either global- or
system-level configuration at all.
@@ Documentation/git.txt: for further details.
+`GIT_CONFIG_GLOBAL`::
+`GIT_CONFIG_SYSTEM`::
+ Take the configuration from the given files instead from global or
-+ system-level configuration files. The files must exist and be readable
-+ by the current user. If `GIT_CONFIG_SYSTEM` is set, `/etc/gitconfig`
++ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the
++ system config file defined at build time (usually `/etc/gitconfig`)
+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither
+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can
+ be set to `/dev/null` to skip reading configuration files of the
@@ Documentation/git.txt: for further details.
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
+ ## builtin/config.c ##
+@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
+ char *user_config, *xdg_config;
+
+ git_global_config(&user_config, &xdg_config);
+- if (!user_config)
++ if (!user_config) {
++ if (getenv("GIT_CONFIG_GLOBAL"))
++ die(_("GIT_CONFIG_GLOBAL=/dev/null set"));
++
+ /*
+ * It is unknown if HOME/.gitconfig exists, so
+ * we do not know if we should write to XDG
+@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
+ * is set and points at a sane location.
+ */
+ die(_("$HOME not set"));
++ }
+
+ given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
+
## config.c ##
@@ config.c: static int git_config_from_blob_ref(config_fn_t fn,
- const char *git_system_config(void)
+
+ char *git_system_config(void)
{
- static const char *system_wide;
-- if (!system_wide)
-- system_wide = system_path(ETC_GITCONFIG);
-+
-+ if (!system_wide) {
-+ system_wide = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
-+ if (system_wide) {
-+ /*
-+ * If GIT_CONFIG_SYSTEM is set, it overrides the
-+ * /etc/gitconfig. Furthermore, the file must exist in
-+ * order to prevent any typos by the user.
-+ */
-+ if (access(system_wide, R_OK))
-+ die(_("cannot access '%s'"), system_wide);
-+ } else {
-+ system_wide = system_path(ETC_GITCONFIG);
-+ }
++ char *system_config = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
++ if (system_config) {
++ if (!strcmp(system_config, "/dev/null"))
++ FREE_AND_NULL(system_config);
++ return system_config;
+ }
-+
- return system_wide;
+ return system_path(ETC_GITCONFIG);
}
-@@ config.c: void git_global_config(const char **user, const char **xdg)
- static const char *user_config, *xdg_config;
+-void git_global_config(char **user_config, char **xdg_config)
++void git_global_config(char **user_out, char **xdg_out)
+ {
+- *user_config = expand_user_path("~/.gitconfig", 0);
+- *xdg_config = xdg_config_home("config");
++ char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
++ char *xdg_config = NULL;
++
++ if (user_config) {
++ if (!strcmp(user_config, "/dev/null"))
++ FREE_AND_NULL(user_config);
++ xdg_config = NULL;
++ } else {
++ user_config = expand_user_path("~/.gitconfig", 0);
++ xdg_config = xdg_config_home("config");
++ }
++
++ *user_out = user_config;
++ *xdg_out = xdg_config;
+ }
- if (!user_config) {
-- user_config = expand_user_path("~/.gitconfig", 0);
-- xdg_config = xdg_config_home("config");
-+ user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
-+ if (user_config) {
-+ /*
-+ * If GIT_CONFIG_GLOBAL is set, then it overrides both
-+ * the ~/.gitconfig and the XDG configuration file.
-+ * Furthermore, the file must exist in order to prevent
-+ * any typos by the user.
-+ */
-+ if (access(user_config, R_OK))
-+ die(_("cannot access '%s'"), user_config);
-+ } else {
-+ user_config = expand_user_path("~/.gitconfig", 0);
-+ xdg_config = xdg_config_home("config");
-+ }
- }
-
- *user = user_config;
+ /*
## t/t1300-config.sh ##
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
+
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
-+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist git version &&
-+ test_must_fail env GIT_CONFIG_SYSTEM=does-not-exist git version &&
-+ GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=does-not-exist git version
++ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list >actual &&
++ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list >actual &&
++ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
+
+test_expect_success 'write to overridden global and system config' '
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
+ key = value
+EOF
+
-+ test_must_fail env GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
-+ touch write-to-global &&
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
+ test_cmp expect write-to-global &&
+
-+ test_must_fail env GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
-+ touch write-to-system &&
+ GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
+ test_cmp expect write-to-system
+'
--
2.31.1
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:46:52
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. This path must
exist and be readable to ensure that the user didn't typo.
- If set to `/dev/null`, we do not load either global- or
system-level configuration at all.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Range-diff against v2:
1: da0b8ce6f0 < -: ---------- config: rename `git_etc_config()`
2: dddc85bcf5 < -: ---------- config: unify code paths to get global config paths
3: 272a3b31aa ! 1: aa0f2957e6 config: allow overriding of global and system configuration
@@ Commit message
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
- The obvious way to fix this would be to introduce `GIT_CONFIG_NOSYSTEM`
- as an equivalent to `GIT_CONFIG_NOGLOBAL`. But in the past, it has
+ The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
+ as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
@@ Documentation/git.txt: for further details.
+`GIT_CONFIG_GLOBAL`::
+`GIT_CONFIG_SYSTEM`::
+ Take the configuration from the given files instead from global or
-+ system-level configuration files. The files must exist and be readable
-+ by the current user. If `GIT_CONFIG_SYSTEM` is set, `/etc/gitconfig`
++ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the
++ system config file defined at build time (usually `/etc/gitconfig`)
+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither
+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can
+ be set to `/dev/null` to skip reading configuration files of the
@@ Documentation/git.txt: for further details.
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
+ ## builtin/config.c ##
+@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
+ char *user_config, *xdg_config;
+
+ git_global_config(&user_config, &xdg_config);
+- if (!user_config)
++ if (!user_config) {
++ if (!strcmp(getenv("GIT_CONFIG_GLOBAL"), "/dev/null"))
++ die(_("GIT_CONFIG_GLOBAL=/dev/null set"));
++
+ /*
+ * It is unknown if HOME/.gitconfig exists, so
+ * we do not know if we should write to XDG
+@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
+ * is set and points at a sane location.
+ */
+ die(_("$HOME not set"));
++ }
+
+ given_config_source.scope = CONFIG_SCOPE_GLOBAL;
+
+
## config.c ##
@@ config.c: static int git_config_from_blob_ref(config_fn_t fn,
- const char *git_system_config(void)
+
+ char *git_system_config(void)
{
- static const char *system_wide;
-- if (!system_wide)
-- system_wide = system_path(ETC_GITCONFIG);
-+
-+ if (!system_wide) {
-+ system_wide = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
-+ if (system_wide) {
-+ /*
-+ * If GIT_CONFIG_SYSTEM is set, it overrides the
-+ * /etc/gitconfig. Furthermore, the file must exist in
-+ * order to prevent any typos by the user.
-+ */
-+ if (access(system_wide, R_OK))
-+ die(_("cannot access '%s'"), system_wide);
-+ } else {
-+ system_wide = system_path(ETC_GITCONFIG);
-+ }
++ char *system_config = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
++ if (system_config) {
++ if (!strcmp(system_config, "/dev/null"))
++ FREE_AND_NULL(system_config);
++ return system_config;
+ }
-+
- return system_wide;
+ return system_path(ETC_GITCONFIG);
}
-@@ config.c: void git_global_config(const char **user, const char **xdg)
- static const char *user_config, *xdg_config;
+-void git_global_config(char **user_config, char **xdg_config)
++void git_global_config(char **user_out, char **xdg_out)
+ {
+- *user_config = expand_user_path("~/.gitconfig", 0);
+- *xdg_config = xdg_config_home("config");
++ char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
++ char *xdg_config = NULL;
++
++ if (user_config) {
++ if (!strcmp(user_config, "/dev/null"))
++ FREE_AND_NULL(user_config);
++ xdg_config = NULL;
++ } else {
++ user_config = expand_user_path("~/.gitconfig", 0);
++ xdg_config = xdg_config_home("config");
++ }
++
++ *user_out = user_config;
++ *xdg_out = xdg_config;
+ }
- if (!user_config) {
-- user_config = expand_user_path("~/.gitconfig", 0);
-- xdg_config = xdg_config_home("config");
-+ user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
-+ if (user_config) {
-+ /*
-+ * If GIT_CONFIG_GLOBAL is set, then it overrides both
-+ * the ~/.gitconfig and the XDG configuration file.
-+ * Furthermore, the file must exist in order to prevent
-+ * any typos by the user.
-+ */
-+ if (access(user_config, R_OK))
-+ die(_("cannot access '%s'"), user_config);
-+ } else {
-+ user_config = expand_user_path("~/.gitconfig", 0);
-+ xdg_config = xdg_config_home("config");
-+ }
- }
-
- *user = user_config;
+ /*
## t/t1300-config.sh ##
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
+
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
-+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist git version &&
-+ test_must_fail env GIT_CONFIG_SYSTEM=does-not-exist git version &&
-+ GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=does-not-exist git version
++ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list >actual &&
++ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list >actual &&
++ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
+
+test_expect_success 'write to overridden global and system config' '
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
+ key = value
+EOF
+
-+ test_must_fail env GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
-+ touch write-to-global &&
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
+ test_cmp expect write-to-global &&
+
-+ test_must_fail env GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
-+ touch write-to-system &&
+ GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
+ test_cmp expect write-to-system
+'
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 6 ++-
config.c | 24 ++++++++++--
t/t1300-config.sh | 71 ++++++++++++++++++++++++++++++++++++
5 files changed, 112 insertions(+), 4 deletions(-)
@@ -340,6 +340,11 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_GLOBAL::+GIT_CONFIG_SYSTEM::+ Take the configuration from the given files instead from global or+ system-level configuration. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the+ system config file defined at build time (usually `/etc/gitconfig`)+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can
@@ -2059,6 +2059,77 @@ test_expect_success '--show-scope with --show-origin' 'test_cmpexpectoutput'+test_expect_success'override global and system config''+test_when_finishedrm-f"$HOME"/.config/git&&++cat>"$HOME"/.gitconfig<<-EOF&&+[home]+config=true+EOF+mkdir-p"$HOME"/.config/git&&+cat>"$HOME"/.config/git/config<<-EOF&&+[xdg]+config=true+EOF+cat>.git/config<<-EOF&&+[local]+config=true+EOF+cat>custom-global-config<<-EOF&&+[global]+config=true+EOF+cat>custom-system-config<<-EOF&&+[system]+config=true+EOF++cat>expect<<-EOF&&+globalxdg.config=true+globalhome.config=true+locallocal.config=true+EOF+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++sane_unsetGIT_CONFIG_NOSYSTEM&&++cat>expect<<-EOF&&+systemsystem.config=true+globalglobal.config=true+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++cat>expect<<-EOF&&+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+test_cmpexpectoutput+'++test_expect_success'override global and system config with missing file''+sane_unsetGIT_CONFIG_NOSYSTEM&&+test_must_failenvGIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=/dev/nullgitconfig--global--list>actual&&+test_must_failenvGIT_CONFIG_GLOBAL=/dev/nullGIT_CONFIG_SYSTEM=does-not-existgitconfig--system--list>actual&&+GIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=does-not-existgitversion+'++test_expect_success'write to overridden global and system config''+cat>expect<<EOF&&+[config]+key=value+EOF++GIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+test_cmpexpectwrite-to-global&&++GIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+test_cmpexpectwrite-to-system+'+foroptin--local--worktreedotest_expect_success"$opt requires a repo"'
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:46:54
There's two callsites which assemble global config paths, once in the
config loading code and once in the git-config(1) builtin. We're about
to implement a way to override global config paths via an environment
variable which would require us to adjust both sites.
Unify both code paths into a single `git_global_config()` function which
returns both paths for `~/.gitconfig` and the XDG config file. This will
make the subsequent patch which introduces the new envvar easier to
implement.
No functional changes are expected from this patch.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 4 ++--
config.c | 12 ++++++++++--
config.h | 1 +
3 files changed, 13 insertions(+), 4 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-12 14:46:59
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path.
- If set to `/dev/null`, we do not load either global- or
system-level configuration at all.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 6 ++-
config.c | 24 ++++++++++--
t/t1300-config.sh | 71 ++++++++++++++++++++++++++++++++++++
5 files changed, 112 insertions(+), 4 deletions(-)
@@ -340,6 +340,11 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_GLOBAL::+GIT_CONFIG_SYSTEM::+ Take the configuration from the given files instead from global or+ system-level configuration. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the+ system config file defined at build time (usually `/etc/gitconfig`)+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can
@@ -2059,6 +2059,77 @@ test_expect_success '--show-scope with --show-origin' 'test_cmpexpectoutput'+test_expect_success'override global and system config''+test_when_finishedrm-f"$HOME"/.config/git&&++cat>"$HOME"/.gitconfig<<-EOF&&+[home]+config=true+EOF+mkdir-p"$HOME"/.config/git&&+cat>"$HOME"/.config/git/config<<-EOF&&+[xdg]+config=true+EOF+cat>.git/config<<-EOF&&+[local]+config=true+EOF+cat>custom-global-config<<-EOF&&+[global]+config=true+EOF+cat>custom-system-config<<-EOF&&+[system]+config=true+EOF++cat>expect<<-EOF&&+globalxdg.config=true+globalhome.config=true+locallocal.config=true+EOF+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++sane_unsetGIT_CONFIG_NOSYSTEM&&++cat>expect<<-EOF&&+systemsystem.config=true+globalglobal.config=true+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++cat>expect<<-EOF&&+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+test_cmpexpectoutput+'++test_expect_success'override global and system config with missing file''+sane_unsetGIT_CONFIG_NOSYSTEM&&+test_must_failenvGIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=/dev/nullgitconfig--global--list>actual&&+test_must_failenvGIT_CONFIG_GLOBAL=/dev/nullGIT_CONFIG_SYSTEM=does-not-existgitconfig--system--list>actual&&+GIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=does-not-existgitversion+'++test_expect_success'write to overridden global and system config''+cat>expect<<EOF&&+[config]+key=value+EOF++GIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+test_cmpexpectwrite-to-global&&++GIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+test_cmpexpectwrite-to-system+'+foroptin--local--worktreedotest_expect_success"$opt requires a repo"'
From: Patrick Steinhardt <hidden> Date: 2021-04-13 07:11:50
Hi,
this is the fourth version of my patch series to provide a way of
overriding the global system configuration.
Compared to v3, I only dropped the special-casing of `/dev/null`. As
Junio rightly pointed out, the special-casing was incomplete and would
have required more work to do the right thing for all cases. It can
still be re-added at a later point if the usecase actually comes up.
Patrick
Patrick Steinhardt (3):
config: rename `git_etc_config()`
config: unify code paths to get global config paths
config: allow overriding of global and system configuration
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 6 +--
config.c | 41 +++++++++++++++------
config.h | 4 +-
t/t1300-config.sh | 71 ++++++++++++++++++++++++++++++++++++
6 files changed, 121 insertions(+), 16 deletions(-)
Range-diff against v3:
1: 34bdbc27d6 = 1: 34bdbc27d6 config: rename `git_etc_config()`
2: 30f18679bd = 2: 30f18679bd config: unify code paths to get global config paths
3: af663640ae ! 3: d27efc0aa8 config: allow overriding of global and system configuration
@@ Commit message
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
- configuration files and instead take the path.
-
- - If set to `/dev/null`, we do not load either global- or
- system-level configuration at all.
+ configuration files and instead take the path. By setting the path
+ to `/dev/null`, no configuration will be loaded for the respective
+ level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
@@ Documentation/git.txt: for further details.
Whether to skip reading settings from the system-wide
`$(prefix)/etc/gitconfig` file. This environment variable can
- ## builtin/config.c ##
-@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
- char *user_config, *xdg_config;
-
- git_global_config(&user_config, &xdg_config);
-- if (!user_config)
-+ if (!user_config) {
-+ if (getenv("GIT_CONFIG_GLOBAL"))
-+ die(_("GIT_CONFIG_GLOBAL=/dev/null set"));
-+
- /*
- * It is unknown if HOME/.gitconfig exists, so
- * we do not know if we should write to XDG
-@@ builtin/config.c: int cmd_config(int argc, const char **argv, const char *prefix)
- * is set and points at a sane location.
- */
- die(_("$HOME not set"));
-+ }
-
- given_config_source.scope = CONFIG_SCOPE_GLOBAL;
-
-
## config.c ##
@@ config.c: static int git_config_from_blob_ref(config_fn_t fn,
char *git_system_config(void)
{
+ char *system_config = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
-+ if (system_config) {
-+ if (!strcmp(system_config, "/dev/null"))
-+ FREE_AND_NULL(system_config);
++ if (system_config)
+ return system_config;
-+ }
return system_path(ETC_GITCONFIG);
}
@@ config.c: static int git_config_from_blob_ref(config_fn_t fn,
+ char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
+ char *xdg_config = NULL;
+
-+ if (user_config) {
-+ if (!strcmp(user_config, "/dev/null"))
-+ FREE_AND_NULL(user_config);
-+ xdg_config = NULL;
-+ } else {
++ if (!user_config) {
+ user_config = expand_user_path("~/.gitconfig", 0);
+ xdg_config = xdg_config_home("config");
+ }
--
2.31.1
From: Patrick Steinhardt <hidden> Date: 2021-04-13 07:11:50
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
While at it, the function is also refactored to pass memory ownership to
the caller. This is done to better match semantics of
`git_global_config()`, which is going to be introduced in the next
commit.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 2 +-
config.c | 18 ++++++++----------
config.h | 3 ++-
3 files changed, 11 insertions(+), 12 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-13 07:11:52
There's two callsites which assemble global config paths, once in the
config loading code and once in the git-config(1) builtin. We're about
to implement a way to override global config paths via an environment
variable which would require us to adjust both sites.
Unify both code paths into a single `git_global_config()` function which
returns both paths for `~/.gitconfig` and the XDG config file. This will
make the subsequent patch which introduces the new envvar easier to
implement.
No functional changes are expected from this patch.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 4 ++--
config.c | 12 ++++++++++--
config.h | 1 +
3 files changed, 13 insertions(+), 4 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-13 07:11:58
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
config.c | 17 +++++++--
t/t1300-config.sh | 71 ++++++++++++++++++++++++++++++++++++
4 files changed, 100 insertions(+), 3 deletions(-)
@@ -340,6 +340,11 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_GLOBAL::+GIT_CONFIG_SYSTEM::+ Take the configuration from the given files instead from global or+ system-level configuration. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the+ system config file defined at build time (usually `/etc/gitconfig`)+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can
@@ -2059,6 +2059,77 @@ test_expect_success '--show-scope with --show-origin' 'test_cmpexpectoutput'+test_expect_success'override global and system config''+test_when_finishedrm-f"$HOME"/.config/git&&++cat>"$HOME"/.gitconfig<<-EOF&&+[home]+config=true+EOF+mkdir-p"$HOME"/.config/git&&+cat>"$HOME"/.config/git/config<<-EOF&&+[xdg]+config=true+EOF+cat>.git/config<<-EOF&&+[local]+config=true+EOF+cat>custom-global-config<<-EOF&&+[global]+config=true+EOF+cat>custom-system-config<<-EOF&&+[system]+config=true+EOF++cat>expect<<-EOF&&+globalxdg.config=true+globalhome.config=true+locallocal.config=true+EOF+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++sane_unsetGIT_CONFIG_NOSYSTEM&&++cat>expect<<-EOF&&+systemsystem.config=true+globalglobal.config=true+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++cat>expect<<-EOF&&+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+test_cmpexpectoutput+'++test_expect_success'override global and system config with missing file''+sane_unsetGIT_CONFIG_NOSYSTEM&&+test_must_failenvGIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=/dev/nullgitconfig--global--list>actual&&+test_must_failenvGIT_CONFIG_GLOBAL=/dev/nullGIT_CONFIG_SYSTEM=does-not-existgitconfig--system--list>actual&&+GIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=does-not-existgitversion+'++test_expect_success'write to overridden global and system config''+cat>expect<<EOF&&+[config]+key=value+EOF++GIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+test_cmpexpectwrite-to-global&&++GIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+test_cmpexpectwrite-to-system+'+foroptin--local--worktreedotest_expect_success"$opt requires a repo"'
From: Jeff King <hidden> Date: 2021-04-13 07:25:08
On Tue, Apr 13, 2021 at 09:11:44AM +0200, Patrick Steinhardt wrote:
While at it, the function is also refactored to pass memory ownership to
the caller. This is done to better match semantics of
`git_global_config()`, which is going to be introduced in the next
commit.
I think this turned out nicely. There are only two callers, one of which
is already handling freeing the global config. In the other:
We "leak" the result, but I think it is actually an improvement. As you
can see in the context, we are sometimes allocating the field in other
code paths, so this is takes us closer to a world where we can actually
call free(given_config_source.file) to fix the leak in all of the other
code paths. :)
(I don't think any of that needs to be dealt with in this series, of
course).
-Peff
From: Jeff King <hidden> Date: 2021-04-13 07:33:12
On Tue, Apr 13, 2021 at 09:11:52AM +0200, Patrick Steinhardt wrote:
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list >actual &&
+ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list >actual &&
+ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
I was slightly surprised to see these still marked as test_must_fail.
But it's because git-config, when given a _specific_ file to read, will
complain if the file doesn't exist. And that is true independent of your
patch.
There is one interesting implication there. Running:
GIT_CONFIG_SYSTEM=/dev/null git config --system --list
does _not_ complain, even though:
GIT_CONFIG_NOSYSTEM=1 git config --system --list
does. IMHO that is quite sensible, but I wanted to point it out, as
using /dev/null is not an exact replacement for GIT_CONFIG_NOSYSTEM (in
my opinion it is even better ;) ).
-Peff
From: Jeff King <hidden> Date: 2021-04-13 07:33:56
On Tue, Apr 13, 2021 at 09:11:37AM +0200, Patrick Steinhardt wrote:
this is the fourth version of my patch series to provide a way of
overriding the global system configuration.
Compared to v3, I only dropped the special-casing of `/dev/null`. As
Junio rightly pointed out, the special-casing was incomplete and would
have required more work to do the right thing for all cases. It can
still be re-added at a later point if the usecase actually comes up.
This version looks good to me. Thanks for working on this!
-Peff
From: Patrick Steinhardt <hidden> Date: 2021-04-13 07:55:12
On Tue, Apr 13, 2021 at 03:33:08AM -0400, Jeff King wrote:
On Tue, Apr 13, 2021 at 09:11:52AM +0200, Patrick Steinhardt wrote:
quoted
+test_expect_success 'override global and system config with missing file' '
+ sane_unset GIT_CONFIG_NOSYSTEM &&
+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list >actual &&
+ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list >actual &&
+ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
I was slightly surprised to see these still marked as test_must_fail.
But it's because git-config, when given a _specific_ file to read, will
complain if the file doesn't exist. And that is true independent of your
patch.
Yeah, surprising at first but then again it does feel sensible when
thinking about it: we ask git-config(1) to explitly list the
global/system-level configuration, and when it does not exist it does
feel sane to complain.
There is one interesting implication there. Running:
GIT_CONFIG_SYSTEM=/dev/null git config --system --list
does _not_ complain, even though:
GIT_CONFIG_NOSYSTEM=1 git config --system --list
does. IMHO that is quite sensible, but I wanted to point it out, as
using /dev/null is not an exact replacement for GIT_CONFIG_NOSYSTEM (in
my opinion it is even better ;) ).
Whereas this is the other edge case: we do ask it to explicitly list the
system-level configuration, and it _does_ exist even though it's empty.
I wouldn't expect to get an error here, and I do prefer this behaviour
to NOSYSTEM, too.
Patrick
From: SZEDER Gábor <hidden> Date: 2021-04-16 21:14:56
On Tue, Apr 13, 2021 at 09:11:44AM +0200, Patrick Steinhardt wrote:
quoted hunk
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
While at it, the function is also refactored to pass memory ownership to
the caller. This is done to better match semantics of
`git_global_config()`, which is going to be introduced in the next
commit.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 2 +-
config.c | 18 ++++++++----------
config.h | 3 ++-
3 files changed, 11 insertions(+), 12 deletions(-)
@@ -1844,12 +1844,9 @@ static int git_config_from_blob_ref(config_fn_t fn,returngit_config_from_blob_oid(fn,name,&oid,data);}-constchar*git_etc_gitconfig(void)+char*git_system_config(void){-staticconstchar*system_wide;-if(!system_wide)-system_wide=system_path(ETC_GITCONFIG);-returnsystem_wide;+returnsystem_path(ETC_GITCONFIG);}/*
@@ -1883,6 +1880,7 @@ static int do_git_config_sequence(const struct config_options *opts,config_fn_tfn,void*data){intret=0;+char*system_config=git_system_config();char*xdg_config=xdg_config_home("config");char*user_config=expand_user_path("~/.gitconfig",0);char*repo_config;
@@ -1896,11 +1894,10 @@ static int do_git_config_sequence(const struct config_options *opts,repo_config=NULL;current_parsing_scope=CONFIG_SCOPE_SYSTEM;-if(git_config_system()&&!access_or_die(git_etc_gitconfig(),R_OK,
Removing git_config_system() from the condition breaks
GIT_CONFIG_NOSYSTEM:
expecting success of 9999.1 'test':
cat /usr/local/etc/gitconfig &&
git config --list --show-origin --show-scope
+ cat /usr/local/etc/gitconfig
[foo]
bar = baz
+ git config --list --show-origin --show-scope
system file:/usr/local/etc/gitconfig foo.bar=baz
local file:.git/config core.repositoryformatversion=0
local file:.git/config core.filemode=true
local file:.git/config core.bare=false
local file:.git/config core.logallrefupdates=true
ok 1 - test
And breaks just about everything the Linux32 job on Travis CI:
https://travis-ci.org/github/git/git/jobs/767207687#L1218
Removing git_config_system() from the condition breaks
GIT_CONFIG_NOSYSTEM:
Good catch. My gut feeling is that the new git_system_config() should
check NOSYSTEM and return NULL if it's set, and then we can get rid of
git_config_system() entirely.
That is slightly different than the old behavior; right now
GIT_CONFIG_NOSYSTEM only prevents reading during the normal sequence,
and not reading (or writing!) via "git config --system". But I think it
would be an improvement to prevent those (the whole point of the feature
was to avoid the test suite accidentally accessing the larger
environment).
-Peff
From: Patrick Steinhardt <hidden> Date: 2021-04-19 12:31:15
The `git_etc_gitconfig()` function retrieves the system-level path of
the configuration file. We're about to introduce a way to override it
via an environment variable, at which point the name of this function
would start to become misleading.
Rename the function to `git_system_config()` as a preparatory step.
While at it, the function is also refactored to pass memory ownership to
the caller. This is done to better match semantics of
`git_global_config()`, which is going to be introduced in the next
commit.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 2 +-
config.c | 18 ++++++++----------
config.h | 3 ++-
3 files changed, 11 insertions(+), 12 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-19 12:31:16
Hi,
this is the fifth version of my patch series to provide a way of
overriding the global system configuration.
Changes to v4:
- Readded the call to `git_config_system()`, which I've previously
dropped by accident. I didn't move it into the new
`git_system_config()` function as it would change semantics of
`git config --system`.
- Added a testcase which verifies that GIT_CONFIG_NOSYSTEM and
GIT_CONFIG_SYSTEM properly interact with each other: if
GIT_CONFIG_NOSYSTEM is set, no system-level configuration shall be
read. This is different than the tests for `git config --system`
which used to and still does ignore GIT_CONFIG_NOSYSTEM.
- Small fixups for another testcase to drop needless redirects and
the `sane_unset` of GIT_CONFIG_NOSYSTEM.
Patrick
Patrick Steinhardt (3):
config: rename `git_etc_config()`
config: unify code paths to get global config paths
config: allow overriding of global and system configuration
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
builtin/config.c | 6 +--
config.c | 41 ++++++++++++-----
config.h | 4 +-
t/t1300-config.sh | 86 ++++++++++++++++++++++++++++++++++++
6 files changed, 136 insertions(+), 16 deletions(-)
Range-diff against v4:
1: 34bdbc27d6 ! 1: 1e8899408a config: rename `git_etc_config()`
@@ config.c: static int do_git_config_sequence(const struct config_options *opts,
- ACCESS_EACCES_OK : 0))
- ret += git_config_from_file(fn, git_etc_gitconfig(),
- data);
-+ if (system_config && !access_or_die(system_config, R_OK,
-+ opts->system_gently ?
-+ ACCESS_EACCES_OK : 0))
++ 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(fn, system_config, data);
current_parsing_scope = CONFIG_SCOPE_GLOBAL;
2: 30f18679bd = 2: 39468f45d2 config: unify code paths to get global config paths
3: d27efc0aa8 ! 3: 7e7506217e config: allow overriding of global and system configuration
@@ t/t1300-config.sh: test_expect_success '--show-scope with --show-origin' '
+'
+
+test_expect_success 'override global and system config with missing file' '
-+ sane_unset GIT_CONFIG_NOSYSTEM &&
-+ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list >actual &&
-+ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list >actual &&
++ test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list &&
++ test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list &&
+ GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version
+'
+
++test_expect_success 'system override has no effect with GIT_CONFIG_NOSYSTEM' '
++ # `git config --system` has different semantics compared to other
++ # commands as it ignores GIT_CONFIG_NOSYSTEM. We thus test whether the
++ # variable has an effect via a different proxy.
++ cat >alias-config <<-EOF &&
++ [alias]
++ hello-world = !echo "hello world"
++ EOF
++ test_must_fail env GIT_CONFIG_NOSYSTEM=true GIT_CONFIG_SYSTEM=alias-config \
++ git hello-world &&
++ GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=alias-config \
++ git hello-world >actual &&
++ echo "hello world" >expect &&
++ test_cmp expect actual
++'
++
+test_expect_success 'write to overridden global and system config' '
+ cat >expect <<EOF &&
+[config]
--
2.31.1
From: Patrick Steinhardt <hidden> Date: 2021-04-19 12:31:19
There's two callsites which assemble global config paths, once in the
config loading code and once in the git-config(1) builtin. We're about
to implement a way to override global config paths via an environment
variable which would require us to adjust both sites.
Unify both code paths into a single `git_global_config()` function which
returns both paths for `~/.gitconfig` and the XDG config file. This will
make the subsequent patch which introduces the new envvar easier to
implement.
No functional changes are expected from this patch.
Signed-off-by: Patrick Steinhardt <redacted>
---
builtin/config.c | 4 ++--
config.c | 12 ++++++++++--
config.h | 1 +
3 files changed, 13 insertions(+), 4 deletions(-)
From: Patrick Steinhardt <hidden> Date: 2021-04-19 12:31:23
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <redacted>
---
Documentation/git-config.txt | 5 +++
Documentation/git.txt | 10 +++++
config.c | 17 +++++--
t/t1300-config.sh | 86 ++++++++++++++++++++++++++++++++++++
4 files changed, 115 insertions(+), 3 deletions(-)
@@ -340,6 +340,11 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig.+GIT_CONFIG_GLOBAL::+GIT_CONFIG_SYSTEM::+ Take the configuration from the given files instead from global or+ system-level configuration. See linkgit:git[1] for details.+ GIT_CONFIG_NOSYSTEM:: Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
@@ -670,6 +670,16 @@ for further details. If this environment variable is set to `0`, git will not prompt on the terminal (e.g., when asking for HTTP authentication).+`GIT_CONFIG_GLOBAL`::+`GIT_CONFIG_SYSTEM`::+ Take the configuration from the given files instead from global or+ system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the+ system config file defined at build time (usually `/etc/gitconfig`)+ will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither+ `$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can+ be set to `/dev/null` to skip reading configuration files of the+ respective level.+ `GIT_CONFIG_NOSYSTEM`:: Whether to skip reading settings from the system-wide `$(prefix)/etc/gitconfig` file. This environment variable can
@@ -2059,6 +2059,92 @@ test_expect_success '--show-scope with --show-origin' 'test_cmpexpectoutput'+test_expect_success'override global and system config''+test_when_finishedrm-f"$HOME"/.config/git&&++cat>"$HOME"/.gitconfig<<-EOF&&+[home]+config=true+EOF+mkdir-p"$HOME"/.config/git&&+cat>"$HOME"/.config/git/config<<-EOF&&+[xdg]+config=true+EOF+cat>.git/config<<-EOF&&+[local]+config=true+EOF+cat>custom-global-config<<-EOF&&+[global]+config=true+EOF+cat>custom-system-config<<-EOF&&+[system]+config=true+EOF++cat>expect<<-EOF&&+globalxdg.config=true+globalhome.config=true+locallocal.config=true+EOF+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++sane_unsetGIT_CONFIG_NOSYSTEM&&++cat>expect<<-EOF&&+systemsystem.config=true+globalglobal.config=true+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+gitconfig--show-scope--list>output&&+test_cmpexpectoutput&&++cat>expect<<-EOF&&+locallocal.config=true+EOF+GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+test_cmpexpectoutput+'++test_expect_success'override global and system config with missing file''+test_must_failenvGIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=/dev/nullgitconfig--global--list&&+test_must_failenvGIT_CONFIG_GLOBAL=/dev/nullGIT_CONFIG_SYSTEM=does-not-existgitconfig--system--list&&+GIT_CONFIG_GLOBAL=does-not-existGIT_CONFIG_SYSTEM=does-not-existgitversion+'++test_expect_success'system override has no effect with GIT_CONFIG_NOSYSTEM''+# `git config --system` has different semantics compared to other+# commands as it ignores GIT_CONFIG_NOSYSTEM. We thus test whether the+# variable has an effect via a different proxy.+cat>alias-config<<-EOF&&+[alias]+hello-world=!echo"hello world"+EOF+test_must_failenvGIT_CONFIG_NOSYSTEM=trueGIT_CONFIG_SYSTEM=alias-config\+githello-world&&+GIT_CONFIG_NOSYSTEM=falseGIT_CONFIG_SYSTEM=alias-config\+githello-world>actual&&+echo"hello world">expect&&+test_cmpexpectactual+'++test_expect_success'write to overridden global and system config''+cat>expect<<EOF&&+[config]+key=value+EOF++GIT_CONFIG_GLOBAL=write-to-globalgitconfig--globalconfig.keyvalue&&+test_cmpexpectwrite-to-global&&++GIT_CONFIG_SYSTEM=write-to-systemgitconfig--systemconfig.keyvalue&&+test_cmpexpectwrite-to-system+'+foroptin--local--worktreedotest_expect_success"$opt requires a repo"'
From: Junio C Hamano <hidden> Date: 2021-04-19 21:55:08
Patrick Steinhardt [off-list ref] writes:
this is the fifth version of my patch series to provide a way of
overriding the global system configuration.
Hmm, this topic has been in next since April 15th. It is
preferrable to fix things with incremental updates (the reasoning
being that while in 'seen' the issues are "mistakes by the author
alone", which may not necessarily benefit others to learn from, but
what is in 'next' are supposed to have got enough review exposure,
so any mistakes found are both of the author and reviewers, i.e.
trickier than what is found before it hits 'next' and are more worth
documenting with incremental "oops that was wrong for such and such
reason, which even our reviews missed, and here is a fix").
But I'll have to go offline for a while soon, so let's make an
exception, revert the merge of the previous round out of 'next', and
queue this in 'seen'.
Thanks.
From: SZEDER Gábor <hidden> Date: 2021-04-21 20:46:45
On Mon, Apr 19, 2021 at 02:31:16PM +0200, Patrick Steinhardt wrote:
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Something is still not right with this patch series, because:
+test_expect_success 'write to overridden global and system config' '
+ cat >expect <<EOF &&
+[config]
+ key = value
+EOF
+
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
+ test_cmp expect write-to-global &&
+
+ GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
+ test_cmp expect write-to-system
+'
This test fails on Travis CI's Linux32 job:
expecting success of 1300.184 'write to overridden global and system config':
cat >expect <<EOF &&
[config]
key = value
EOF
GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
test_cmp expect write-to-global &&
GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
test_cmp expect write-to-system
+ cat
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value
fatal: unable to access '/root/etc/gitconfig': Permission denied
error: last command exited with $?=128
not ok 184 - write to overridden global and system config
Yeah, that job has a weird environment with Docker and 'su'
interacting in a way that ultimately builds Git with 'HOME=/root',
which in our build system means that 'sysconfdir=/root/etc'. To
reproduce at home just run:
make prefix=/root && cd t && ./t1300-config.sh -V -x -i
From: SZEDER Gábor <hidden> Date: 2021-04-21 21:06:19
On Wed, Apr 21, 2021 at 10:46:37PM +0200, SZEDER Gábor wrote:
On Mon, Apr 19, 2021 at 02:31:16PM +0200, Patrick Steinhardt wrote:
quoted
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Something is still not right with this patch series, because:
quoted
+test_expect_success 'write to overridden global and system config' '
+ cat >expect <<EOF &&
+[config]
+ key = value
+EOF
+
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
+ test_cmp expect write-to-global &&
+
+ GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
+ test_cmp expect write-to-system
+'
This test fails on Travis CI's Linux32 job:
expecting success of 1300.184 'write to overridden global and system config':
cat >expect <<EOF &&
[config]
key = value
EOF
GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value &&
test_cmp expect write-to-global &&
GIT_CONFIG_SYSTEM=write-to-system git config --system config.key value &&
test_cmp expect write-to-system
+ cat
+ GIT_CONFIG_GLOBAL=write-to-global git config --global config.key value
fatal: unable to access '/root/etc/gitconfig': Permission denied
error: last command exited with $?=128
not ok 184 - write to overridden global and system config
Yeah, that job has a weird environment with Docker and 'su'
interacting in a way that ultimately builds Git with 'HOME=/root',
which in our build system means that 'sysconfdir=/root/etc'. To
reproduce at home just run:
make prefix=/root && cd t && ./t1300-config.sh -V -x -i
Hrm, that's not the only test that fails, but I only ran it with
'-i'... but in fact most subsequent tests fail with the same error.
I think the culprit is the previous test case which I too eagerly
snipped from my previous email, so here it is again (copy-pasted,
whitespace-damaged):
Unsetting GIT_CONFIG_NOSYSTEM like this does affect the environment of
all subsequent tests and their git commands will then try to look at
the system config file.
Putting this 'sane_unset' and the rest of this test case in a subshell
seems to fix the issue.
Unsetting GIT_CONFIG_NOSYSTEM like this does affect the environment of
all subsequent tests and their git commands will then try to look at
the system config file.
Putting this 'sane_unset' and the rest of this test case in a subshell
seems to fix the issue.
Ah, that makes sense. Thanks for digging into the issue, I'll send a fix
for this later today.
Patrick
From: Patrick Steinhardt <hidden> Date: 2021-04-23 05:47:27
In order to test whether the new GIT_CONFIG_SYSTEM environment variable
behaves as expected, we unset GIT_CONFIG_NOSYSTEM in one of our tests in
t1300. But because tests are not executed in a subshell, this unset
leaks into all subsequent tests and may thus cause them to fail in some
environments. These failures are easily reproducable with `make
prefix=/root test`.
Fix the issue by not using `sane_unset GIT_CONFIG_NOSYSTEM`, but instead
just manually add it to the environment of the two command invocations
which need it.
Reported-by: SZEDER Gábor <redacted>
Signed-off-by: Patrick Steinhardt <redacted>
---
This patch applies on top of 47e6f16901 (Sync with master, 2021-04-20),
which is the tip of next at the time of writing.
t/t1300-config.sh | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
@@ -2092,21 +2092,20 @@ test_expect_success 'override global and system config' 'gitconfig--show-scope--list>output&&test_cmpexpectoutput&&-sane_unsetGIT_CONFIG_NOSYSTEM&&-cat>expect<<-EOF&&systemsystem.config=trueglobalglobal.config=truelocallocal.config=trueEOF-GIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\+GIT_CONFIG_NOSYSTEM=falseGIT_CONFIG_SYSTEM=custom-system-configGIT_CONFIG_GLOBAL=custom-global-config\gitconfig--show-scope--list>output&&test_cmpexpectoutput&&cat>expect<<-EOF&&locallocal.config=trueEOF-GIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/nullgitconfig--show-scope--list>output&&+GIT_CONFIG_NOSYSTEM=falseGIT_CONFIG_SYSTEM=/dev/nullGIT_CONFIG_GLOBAL=/dev/null\+gitconfig--show-scope--list>output&&test_cmpexpectoutput'
From: Jeff King <hidden> Date: 2021-04-23 09:32:24
On Mon, Apr 19, 2021 at 02:31:04PM +0200, Patrick Steinhardt wrote:
this is the fifth version of my patch series to provide a way of
overriding the global system configuration.
Changes to v4:
- Readded the call to `git_config_system()`, which I've previously
dropped by accident. I didn't move it into the new
`git_system_config()` function as it would change semantics of
`git config --system`.
- Added a testcase which verifies that GIT_CONFIG_NOSYSTEM and
GIT_CONFIG_SYSTEM properly interact with each other: if
GIT_CONFIG_NOSYSTEM is set, no system-level configuration shall be
read. This is different than the tests for `git config --system`
which used to and still does ignore GIT_CONFIG_NOSYSTEM.
- Small fixups for another testcase to drop needless redirects and
the `sane_unset` of GIT_CONFIG_NOSYSTEM.
With the extra fixup to avoid unsetting GIT_CONFIG_NOSYSTEM for the
whole test suite, this looks good to me.
-Peff