From: Phillip Wood <phillip.wood123@gmail.com>
To: me@black-desk.cn, git@vger.kernel.org
Cc: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>,
Junio C Hamano <gitster@pobox.com>,
Patrick Steinhardt <ps@pks.im>,
Phillip Wood <phillip.wood@dunelm.org.uk>
Subject: Re: [PATCH v4 2/2] config: add "worktree" and "worktree/i" includeIf conditions
Date: Wed, 13 May 2026 14:59:00 +0100 [thread overview]
Message-ID: <2989eb07-2933-4b5a-9e5c-33ef9b805528@gmail.com> (raw)
In-Reply-To: <20260513-includeif-worktree-v4-2-f8e6212d1fba@black-desk.cn>
On 13/05/2026 09:08, Chen Linxuan via B4 Relay wrote:
> From: Chen Linxuan <me@black-desk.cn>
>
> diff --git a/Documentation/config.adoc b/Documentation/config.adoc
> index 62eebe7c5450..6299b1e3a019 100644
> --- a/Documentation/config.adoc
> +++ b/Documentation/config.adoc
> @@ -146,6 +146,46 @@ refer to linkgit:gitignore[5] for details. For convenience:
> This is the same as `gitdir` except that matching is done
> case-insensitively (e.g. on case-insensitive file systems)
>
> +`worktree`::
> + The data that follows the keyword `worktree` and a colon is used as a
> + glob pattern. If the working directory of the current worktree matches
> + the pattern, the include condition is met.
> ++
> +The worktree location is the path where files are checked out (as returned
> +by `git rev-parse --show-toplevel`). This is different from `gitdir`, which
> +matches the `.git` directory path. In a linked worktree, the worktree path
> +is the directory where that worktree's files are located, not the main
> +repository's `.git` directory.
> ++
> +The pattern uses the same glob syntax as `gitdir` (including `~/`, `./`,
> +`**/`, and trailing-`/` prefix matching). This condition will never match
> +in a bare repository (which has no worktree).
> ++
> +This is useful when you want to apply configuration based on where the
> +working tree is located on the filesystem. For example, a contributor who
> +works on the same project both personally and as an employee can use
> +different `user.name` and `user.email` values depending on which directory
> +the worktree is checked out under:
> ++
> +----
> +[includeIf "worktree:/home/user/work/"]
> + path = ~/.config/git/work.inc
> +[includeIf "worktree:/home/user/personal/"]
> + path = ~/.config/git/personal.inc
> +----
> ++
> +While `extensions.worktreeConfig` (see linkgit:git-worktree[1]) also supports
> +per-worktree configuration, it stores the config inside each repository's
> +`.git/config.worktree` file and requires running `git config --worktree`
> +inside each worktree individually. In contrast, `includeIf "worktree:..."`
> +can be set once in a global or system-level configuration file (e.g.
> +`~/.config/git/config`) and applies to all repositories at once based on
> +their worktree location.
Thanks for expanding the documentation - this looks good to me.
Phillip
> +`worktree/i`::
> + This is the same as `worktree` except that matching is done
> + case-insensitively (e.g. on case-insensitive file systems)
> +
> `onbranch`::
> The data that follows the keyword `onbranch` and a colon is taken to be a
> pattern with standard globbing wildcards and two additional
> @@ -244,6 +284,14 @@ Example
> [includeIf "gitdir:~/to/group/"]
> path = /path/to/foo.inc
>
> +; include if the worktree is at /path/to/project-build
> +[includeIf "worktree:/path/to/project-build"]
> + path = build-config.inc
> +
> +; include for all worktrees inside /path/to/group
> +[includeIf "worktree:/path/to/group/"]
> + path = group-config.inc
> +
> ; relative paths are always relative to the including
> ; file (if the condition is true); their location is not
> ; affected by the condition
> diff --git a/config.c b/config.c
> index 7d5dae0e8450..6d0c2d0725e4 100644
> --- a/config.c
> +++ b/config.c
> @@ -400,6 +400,12 @@ static int include_condition_is_true(const struct key_value_info *kvi,
> return include_by_path(kvi, opts->git_dir, cond, cond_len, 0);
> else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
> return include_by_path(kvi, opts->git_dir, cond, cond_len, 1);
> + else if (skip_prefix_mem(cond, cond_len, "worktree:", &cond, &cond_len))
> + return include_by_path(kvi, inc->repo ? repo_get_work_tree(inc->repo) : NULL,
> + cond, cond_len, 0);
> + else if (skip_prefix_mem(cond, cond_len, "worktree/i:", &cond, &cond_len))
> + return include_by_path(kvi, inc->repo ? repo_get_work_tree(inc->repo) : NULL,
> + cond, cond_len, 1);
> else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
> return include_by_branch(inc, cond, cond_len);
> else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
> diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
> index 6e51f892f320..07b6fb649cd2 100755
> --- a/t/t1305-config-include.sh
> +++ b/t/t1305-config-include.sh
> @@ -396,4 +396,117 @@ test_expect_success 'onbranch without repository but explicit nonexistent Git di
> test_must_fail nongit git --git-dir=nonexistent config get foo.bar
> '
>
> +# worktree: conditional include tests
> +
> +test_expect_success 'conditional include, worktree bare repo' '
> + git init --bare wt-bare &&
> + (
> + cd wt-bare &&
> + echo "[includeIf \"worktree:/\"]path=bar-bare" >>config &&
> + echo "[test]wtbare=1" >bar-bare &&
> + test_must_fail git config test.wtbare
> + )
> +'
> +
> +test_expect_success 'conditional include, worktree multiple worktrees' '
> + git init wt-multi &&
> + (
> + cd wt-multi &&
> + test_commit initial &&
> + git worktree add -b linked-branch ../wt-linked HEAD &&
> + git worktree add -b prefix-branch ../wt-prefix/linked HEAD
> + ) &&
> + wt_main="$(cd wt-multi && pwd)" &&
> + wt_linked="$(cd wt-linked && pwd)" &&
> + wt_prefix_parent="$(cd wt-prefix && pwd)" &&
> + cat >>wt-multi/.git/config <<-EOF &&
> + [includeIf "worktree:$wt_main"]
> + path = main-config
> + [includeIf "worktree:$wt_linked"]
> + path = linked-config
> + [includeIf "worktree:$wt_prefix_parent/"]
> + path = prefix-config
> + EOF
> + echo "[test]mainvar=main" >wt-multi/.git/main-config &&
> + echo "[test]linkedvar=linked" >wt-multi/.git/linked-config &&
> + echo "[test]prefixvar=prefix" >wt-multi/.git/prefix-config &&
> + echo main >expect &&
> + git -C wt-multi config test.mainvar >actual &&
> + test_cmp expect actual &&
> + test_must_fail git -C wt-multi config test.linkedvar &&
> + test_must_fail git -C wt-multi config test.prefixvar &&
> + echo linked >expect &&
> + git -C wt-linked config test.linkedvar >actual &&
> + test_cmp expect actual &&
> + test_must_fail git -C wt-linked config test.mainvar &&
> + test_must_fail git -C wt-linked config test.prefixvar &&
> + echo prefix >expect &&
> + git -C wt-prefix/linked config test.prefixvar >actual &&
> + test_cmp expect actual &&
> + test_must_fail git -C wt-prefix/linked config test.mainvar &&
> + test_must_fail git -C wt-prefix/linked config test.linkedvar
> +'
> +
> +test_expect_success SYMLINKS 'conditional include, worktree resolves symlinks' '
> + mkdir real-wt &&
> + ln -s real-wt link-wt &&
> + git init link-wt/repo &&
> + (
> + cd link-wt/repo &&
> + # repo->worktree resolves symlinks, so use real path in pattern
> + echo "[includeIf \"worktree:**/real-wt/repo\"]path=bar-link" >>.git/config &&
> + echo "[test]wtlink=2" >.git/bar-link &&
> + echo 2 >expect &&
> + git config test.wtlink >actual &&
> + test_cmp expect actual
> + )
> +'
> +
> +test_expect_success 'conditional include, worktree, icase' '
> + git init wt-icase &&
> + (
> + cd wt-icase &&
> + test_commit initial &&
> + wt_path="$(pwd)" &&
> + wt_upper=$(echo "$wt_path" | tr a-z A-Z) &&
> + echo "[includeIf \"worktree/i:$wt_upper\"]path=icase-inc" >>.git/config &&
> + echo "[test]wticase=1" >.git/icase-inc &&
> + echo 1 >expect &&
> + git config test.wticase >actual &&
> + test_cmp expect actual
> + )
> +'
> +
> +# The "worktree" condition cannot match during early config reading
> +# because the repository object is not yet fully initialized and
> +# repo_get_work_tree() returns NULL.
> +test_expect_success 'conditional include, worktree does not match in early config' '
> + git init wt-early &&
> + (
> + cd wt-early &&
> + test_commit initial &&
> + wt_path="$(pwd)" &&
> + echo "[includeIf \"worktree:$wt_path\"]path=early-inc" >>.git/config &&
> + echo "[test]wtearly=1" >.git/early-inc &&
> + test-tool config read_early_config test.wtearly >actual &&
> + test_must_be_empty actual
> + )
> +'
> +
> +test_expect_success 'conditional include, worktree without repository' '
> + test_when_finished "rm -f .gitconfig config.inc" &&
> + git config set -f .gitconfig "includeIf.worktree:/.path" config.inc &&
> + git config set -f config.inc foo.bar baz &&
> + git config get foo.bar &&
> + test_must_fail nongit git config get foo.bar
> +'
> +
> +test_expect_success 'conditional include, worktree without repository but explicit nonexistent Git directory' '
> + test_when_finished "rm -f .gitconfig config.inc" &&
> + git config set -f .gitconfig "includeIf.worktree:/.path" config.inc &&
> + git config set -f config.inc foo.bar baz &&
> + git config get foo.bar &&
> + test_must_fail nongit git --git-dir=nonexistent config get foo.bar
> +'
> +
> test_done
>
prev parent reply other threads:[~2026-05-13 13:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 8:08 [PATCH v4 0/2] includeIf: add "worktree" condition for matching working tree path Chen Linxuan via B4 Relay
2026-05-13 8:08 ` [PATCH v4 1/2] config: refactor include_by_gitdir() into include_by_path() Chen Linxuan via B4 Relay
2026-05-13 8:08 ` [PATCH v4 2/2] config: add "worktree" and "worktree/i" includeIf conditions Chen Linxuan via B4 Relay
2026-05-13 13:59 ` Phillip Wood [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2989eb07-2933-4b5a-9e5c-33ef9b805528@gmail.com \
--to=phillip.wood123@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=kristofferhaugsbakk@fastmail.com \
--cc=me@black-desk.cn \
--cc=phillip.wood@dunelm.org.uk \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox