Merge branch 'ds/config-no-includes' into seen

Two new mechanisms, the GIT_CONFIG_INCLUDES environment variable and
the top-level --no-includes command-line option, have been introduced
to ignore configuration include directives.

* ds/config-no-includes:
  git: add --no-includes top-level option
  config: add GIT_CONFIG_INCLUDES
  git-config.adoc: fix paragraph break
This commit is contained in:
Junio C Hamano
2026-06-12 15:58:17 -07:00
6 changed files with 63 additions and 4 deletions

View File

@@ -476,7 +476,7 @@ GIT_CONFIG_SYSTEM::
GIT_CONFIG_NOSYSTEM::
Whether to skip reading settings from the system-wide
$(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
+
See also <<FILES>>.
GIT_CONFIG_COUNT::
@@ -502,6 +502,11 @@ GIT_CONFIG::
historical compatibility; there is generally no reason to use it
instead of the `--file` option.
GIT_CONFIG_INCLUDES::
If GIT_CONFIG_INCLUDES is set to 0, then Git will not follow
`include.path` or `includeIf.*.path` directives when reading
configuration files.
[[EXAMPLES]]
EXAMPLES
--------

View File

@@ -12,7 +12,7 @@ SYNOPSIS
'git' [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]
[--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]
[--no-optional-locks] [--no-advice] [--no-includes] [--bare] [--git-dir=<path>]
[--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]
<command> [<args>]
@@ -194,6 +194,10 @@ If you just want to run git as if it was started in `<path>` then use
--no-advice::
Disable all advice hints from being printed.
--no-includes::
Disable all `include.path` and `includeIf.*` config directives.
See linkgit:git-config[1] for more information.
--literal-pathspecs::
Treat pathspecs literally (i.e. no globbing, no pathspec magic).
This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment

View File

@@ -1618,9 +1618,14 @@ int config_with_options(config_fn_t fn, void *data,
const struct config_options *opts)
{
struct config_include_data inc = CONFIG_INCLUDE_INIT;
int respect_includes = opts->respect_includes;
int ret;
if (opts->respect_includes) {
if (respect_includes &&
!git_env_bool(CONFIG_INCLUDES_ENVIRONMENT, 1))
respect_includes = 0;
if (respect_includes) {
inc.fn = fn;
inc.data = data;
inc.opts = opts;

View File

@@ -52,6 +52,12 @@
*/
#define GIT_ADVICE_ENVIRONMENT "GIT_ADVICE"
/*
* Environment variable used to prevent following include.path or includeIf.*
* config directives.
*/
#define CONFIG_INCLUDES_ENVIRONMENT "GIT_CONFIG_INCLUDES"
/*
* Environment variable used in handshaking the wire protocol.
* Contains a colon ':' separated list of keys with optional values

6
git.c
View File

@@ -40,7 +40,7 @@ const char git_usage_string[] =
N_("git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]\n"
" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
" [--no-optional-locks] [--no-advice] [--no-includes] [--bare] [--git-dir=<path>]\n"
" [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]\n"
" <command> [<args>]");
@@ -354,6 +354,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
setenv(GIT_ADVICE_ENVIRONMENT, "0", 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--no-includes")) {
setenv(CONFIG_INCLUDES_ENVIRONMENT, "0", 1);
if (envchanged)
*envchanged = 1;
} else {
fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);

View File

@@ -522,4 +522,39 @@ test_expect_success 'conditional include, worktree without repository but explic
test_must_fail nongit git --git-dir=nonexistent config get foo.bar
'
test_expect_success 'GIT_CONFIG_INCLUDES=0 disables include.path and includeIf' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
git config set include.path config.inc &&
git config set "includeIf.gitdir:*.path" config2.inc &&
git config set -f .git/config.inc foo.bar from-include &&
git config set -f .git/config2.inc foo.baz from-includeif &&
git config get foo.bar &&
git config get foo.baz &&
test_must_fail env GIT_CONFIG_INCLUDES=0 git config get foo.bar &&
test_must_fail env GIT_CONFIG_INCLUDES=0 git config get foo.baz &&
test_must_fail git --no-includes config get foo.bar &&
test_must_fail git --no-includes config get foo.baz &&
git config get --includes foo.bar &&
test_must_fail env GIT_CONFIG_INCLUDES=0 git config get --includes foo.bar &&
test_must_fail git --no-includes config get --includes foo.bar
)
'
test_expect_success 'GIT_CONFIG_INCLUDES=0 blocks included alias override' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
git config set alias.test false &&
git config set include.path config.inc &&
git config set -f .git/config.inc alias.test status &&
git test &&
test_must_fail env GIT_CONFIG_INCLUDES=0 git test &&
test_must_fail git --no-includes test
)
'
test_done