Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Documentation/git-config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand All @@ -502,6 +502,11 @@ GIT_CONFIG::
historical compatibility; there is generally no reason to use it
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Patrick Steinhardt wrote on the Git mailing list (how to reply to this email):

On Mon, Jun 08, 2026 at 01:57:05PM +0000, Derrick Stolee via GitGitGadget wrote:
> From: Derrick Stolee <stolee@gmail.com>
> 
> The config keys 'include.path' and 'includeIf.*' allow users to specify
> config stored in a location outside of the typical list of config files
> (system, global, local, etc.). For example, users who accept the risk
> can specify helpful aliases via a file checked into the repo by pointing
> 'include.path' to the position of that file in the working directory.
> This is dangerous, but people do it.

Huh, I never even considered this use case. But of course, this is
possible, even though it's quite scary.

> What becomes tricky is that this modifies all Git behavior, including
> operations that are intended to be limited in activity or sandboxed in
> some way. These include directives can provide surprising changes to
> behavior, especially when expecting a specific list of allowed file
> accesses. This could lead to failed builds, for instance.
> 
> To allow for these user-desired features when they are running commands,
> add a new GIT_CONFIG_INCLUDES environment variable that disables these
> redirections of config when set to zero. This variable can be set by
> automation, such as build tooling, to avoid these strange behaviors.
> This could be considered a recommended option for tools executing Git
> commands, the same as GIT_ADVICE=0.

I don't know about this part though. I could see use cases where the
tools _should_ read the project-relative configuration. It might also be
the case that the user may want to evaluate some includes, but not all
of them.

That raises the question whether we can introduce the configuration in a
way that it allows a bit more flexibility than just "yes"/"no", like for
example an allow-list of locations that should be evaluated. But maybe
I'm overthinking this.

Patrick

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
--------
Expand Down
6 changes: 5 additions & 1 deletion Documentation/git.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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>]

Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1595,9 +1595,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;
Expand Down
6 changes: 6 additions & 0 deletions environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion git.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>]");

Expand Down Expand Up @@ -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);
Expand Down
35 changes: 35 additions & 0 deletions t/t1305-config-include.sh
Original file line number Diff line number Diff line change
Expand Up @@ -396,4 +396,39 @@ test_expect_success 'onbranch without repository but explicit nonexistent Git di
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
Loading