From: Chen Linxuan via B4 Relay <devnull+me.black-desk.cn@kernel.org>
To: git@vger.kernel.org
Cc: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>,
Junio C Hamano <gitster@pobox.com>,
Patrick Steinhardt <ps@pks.im>, Chen Linxuan <me@black-desk.cn>,
Phillip Wood <phillip.wood@dunelm.org.uk>
Subject: [PATCH v7 0/3] includeIf: add "worktree" condition for matching working tree path
Date: Thu, 09 Jul 2026 10:41:40 +0800 [thread overview]
Message-ID: <20260709-includeif-worktree-v7-0-e87e705e8df6@black-desk.cn> (raw)
The `includeIf` mechanism already supports matching on the `.git`
directory path (`gitdir`) and the currently checked out branch
(`onbranch`). But in multi-worktree setups the `.git` directory of a
linked worktree points into the main repository's `.git/worktrees/`
area, which makes `gitdir` patterns cumbersome when one wants to
include config based on the working tree's checkout path instead.
Introduce two new condition keywords:
- `worktree:<pattern>` matches the working directory of the current
worktree against a glob pattern.
- `worktree/i:<pattern>` is the case-insensitive variant.
Supported pattern features: glob wildcards, `**/` and `/**`, `~`
expansion, `./` relative paths, and trailing-`/` prefix matching.
The condition never matches in a bare repository.
Signed-off-by: Chen Linxuan <me@black-desk.cn>
---
Changes in v7:
- Preserve the symlinked spelling of the worktree path and match
includeIf "worktree:" against it, so the condition now matches both
the symlinked and the real path, consistent with "gitdir:"
(Patrick Steinhardt, v6 review).
- Split the work into a preparatory commit that stores a non-realpath
worktree path and a follow-up that wires it into includeIf.
- Extend symlink test coverage to subdirectories and linked worktrees.
- Link to v6: https://lore.kernel.org/r/20260703-includeif-worktree-v6-0-a13893ad9a7f@black-desk.cn
Changes in v6:
- Rebase onto current `master` at Git 2.55.
- Add an in-code comment explaining why the non-repository worktree
tests use the loose `**.path` pattern (suggested by Junio C Hamano).
- Link to v5: https://lore.kernel.org/r/20260525-includeif-worktree-v5-0-1efe525d025a@black-desk.cn
Changes in v5:
- Fix Windows CI failure: use `**` glob pattern instead of `/` in the
"worktree without repository" tests, since `/` as a path pattern is
Unix-specific and does not match Windows paths.
Github CI pass: https://github.com/black-desk/git/actions/runs/26380466288
- Add a test verifying case-sensitive matching by default, with the
`!CASE_INSENSITIVE_FS` prerequisite (suggested by Patrick Steinhardt).
- Link to v4: https://lore.kernel.org/r/20260513-includeif-worktree-v4-0-f8e6212d1fba@black-desk.cn
Changes in v4:
- Deduplicate the worktree pattern documentation by referencing the
gitdir syntax instead of repeating the full pattern description
(suggested by Patrick Steinhardt).
- Add documentation comparing includeIf "worktree:" with
extensions.worktreeConfig, including a concrete use case example
(suggested by Phillip Wood, Junio C Hamano).
- Add a test verifying that the worktree condition does not match
during early config reading (suggested by Patrick Steinhardt).
- Add tests for the non-repository (nongit) scenario (suggested by
Patrick Steinhardt).
- Add a test for the case-insensitive "worktree/i" variant
- Link to v3: https://lore.kernel.org/r/20260403-includeif-worktree-v3-0-109ce5782b03@black-desk.cn
Changes in v3:
- Apply Junio's suggestion.
- Link to v2: https://lore.kernel.org/r/20260402-includeif-worktree-v2-0-36e339b898d7@black-desk.cn
Changes in v2:
- Add missing signed-off-by lines.
- Link to v1: https://lore.kernel.org/r/20260401-includeif-worktree-v1-0-906db69f2c79@black-desk.cn
---
Chen Linxuan (3):
config: refactor include_by_gitdir() into include_by_path()
repository: keep a symlink-preserving copy of the worktree path
config: add "worktree" and "worktree/i" includeIf conditions
Documentation/config.adoc | 48 +++++++++++++
config.c | 25 ++++---
repository.c | 26 +++++++
repository.h | 10 +++
setup.c | 86 ++++++++++++++++++++++-
t/t1305-config-include.sh | 171 ++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 354 insertions(+), 12 deletions(-)
Range-diff versus v6:
1: faa10baf8deb = 1: 47ee82d6a5bd config: refactor include_by_gitdir() into include_by_path()
-: ------------ > 2: 367d61f9b55f repository: keep a symlink-preserving copy of the worktree path
2: ee81d7aeee56 ! 3: 67d9c31d3817 config: add "worktree" and "worktree/i" includeIf conditions
@@ Commit message
Introduce two new condition keywords:
- - worktree:<pattern> matches the realpath of the current worktree's
- working directory (i.e. repo_get_work_tree()) against a glob
- pattern. This is the path returned by git rev-parse
- --show-toplevel.
+ - worktree:<pattern> matches the working directory of the current
+ worktree (the path returned by git rev-parse --show-toplevel)
+ against a glob pattern.
- worktree/i:<pattern> is the case-insensitive variant.
- The implementation reuses the include_by_path() helper introduced in
- the previous commit, passing the worktree path in place of the
- gitdir. The condition never matches in bare repositories (where
- there is no worktree) or during early config reading (where no
- repository is available).
+ The implementation reuses the include_by_path() helper, passing
+ repo_get_work_tree_original() (added in the previous commit; it keeps
+ the symlink-preserving spelling of the worktree path) in place of the
+ gitdir. As with gitdir, include_by_path() then matches both the
+ realpath and the original spelling, so a pattern may use either. The
+ condition never matches in bare repositories (where there is no
+ worktree) or during early config reading (where no repository is
+ available).
Add documentation describing the new conditions, including a comparison
with extensions.worktreeConfig. Add tests covering bare repositories,
- multiple worktrees, symlinked worktree paths, case-sensitive and
- case-insensitive matching, early config reading, and non-repository
- scenarios.
+ multiple worktrees, symlinked and subdir-of-symlinked worktree paths,
+ case-sensitive and case-insensitive matching, early config reading,
+ and non-repository scenarios.
Signed-off-by: Chen Linxuan <me@black-desk.cn>
@@ config.c: static int include_condition_is_true(const struct key_value_info *kvi,
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,
++ return include_by_path(kvi, inc->repo ? repo_get_work_tree_original(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,
++ return include_by_path(kvi, inc->repo ? repo_get_work_tree_original(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);
@@ t/t1305-config-include.sh: test_expect_success 'onbranch without repository but
+ 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 &&
++test_expect_success SYMLINKS 'conditional include, worktree matching symlink' '
++ mkdir sym-real &&
++ ln -s sym-real sym-link &&
++ git init sym-link/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
++ cd sym-link/repo &&
++ link_path="$(pwd)" &&
++ real_path="$(test-tool path-utils real_path "$link_path")" &&
++ cat >>.git/config <<-EOF &&
++ [includeIf "gitdir:$link_path/.git"]
++ path = gitdir-link
++ [includeIf "gitdir:$real_path/.git"]
++ path = gitdir-real
++ [includeIf "worktree:$link_path"]
++ path = worktree-link
++ [includeIf "worktree:$real_path"]
++ path = worktree-real
++ EOF
++ echo "[test]gitdirlink=1" >.git/gitdir-link &&
++ echo "[test]gitdirreal=1" >.git/gitdir-real &&
++ echo "[test]worktreelink=1" >.git/worktree-link &&
++ echo "[test]worktreereal=1" >.git/worktree-real &&
++ git config get test.gitdirlink &&
++ git config get test.gitdirreal &&
++ git config get test.worktreelink &&
++ git config get test.worktreereal &&
++ # from a subdirectory, the logical worktree path is recovered by
++ # stripping the below-root suffix, so both spellings still match
++ mkdir d &&
++ cd d &&
++ git config get test.worktreelink &&
++ git config get test.worktreereal
++ )
++'
++
++test_expect_success SYMLINKS 'conditional include, worktree matching symlink of a linked worktree' '
++ git init wt-main &&
++ ( cd wt-main && test_commit initial ) &&
++ git -C wt-main worktree add --detach ../wt-real &&
++ ln -s wt-real wt-link &&
++ wt_main="$(cd wt-main && pwd)" &&
++ (
++ cd wt-link &&
++ link_path="$(pwd)" &&
++ real_path="$(test-tool path-utils real_path "$link_path")" &&
++ cat >>"$wt_main/.git/config" <<-EOF &&
++ [includeIf "worktree:$link_path"]
++ path = wt-link
++ [includeIf "worktree:$real_path"]
++ path = wt-real
++ EOF
++ echo "[test]wtlink=1" >"$wt_main/.git/wt-link" &&
++ echo "[test]wtreal=1" >"$wt_main/.git/wt-real" &&
++ test "$(git config get test.wtlink)" = "1" &&
++ test "$(git config get test.wtreal)" = "1"
+ )
+'
+
---
base-commit: f85a7e662054a7b0d9070e432508831afa214b47
next reply other threads:[~2026-07-09 2:42 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 2:41 Chen Linxuan via B4 Relay [this message]
2026-07-09 2:41 ` [PATCH v7 1/3] config: refactor include_by_gitdir() into include_by_path() Chen Linxuan via B4 Relay
2026-07-09 2:41 ` [PATCH v7 2/3] repository: keep a symlink-preserving copy of the worktree path Chen Linxuan via B4 Relay
2026-07-09 10:09 ` Patrick Steinhardt
2026-07-09 2:41 ` [PATCH v7 3/3] config: add "worktree" and "worktree/i" includeIf conditions Chen Linxuan via B4 Relay
2026-07-09 10:09 ` [PATCH v7 0/3] includeIf: add "worktree" condition for matching working tree path Patrick Steinhardt
2026-07-09 20:40 ` Junio C Hamano
2026-07-10 6:43 ` [PATCH v8 0/2] " Chen Linxuan via B4 Relay
2026-07-10 6:43 ` [PATCH v8 1/2] config: refactor include_by_gitdir() into include_by_path() Chen Linxuan via B4 Relay
2026-07-10 6:43 ` [PATCH v8 2/2] config: add "worktree" and "worktree/i" includeIf conditions Chen Linxuan via B4 Relay
2026-07-13 11:16 ` Patrick Steinhardt
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=20260709-includeif-worktree-v7-0-e87e705e8df6@black-desk.cn \
--to=devnull+me.black-desk.cn@kernel.org \
--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