diff --git a/Documentation/config.adoc b/Documentation/config.adoc index 000f4301ca..a80e7db46d 100644 --- a/Documentation/config.adoc +++ b/Documentation/config.adoc @@ -146,46 +146,6 @@ 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. - -`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 @@ -284,14 +244,6 @@ 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 c250e56214..a1b92fe083 100644 --- a/config.c +++ b/config.c @@ -235,20 +235,23 @@ static int prepare_include_condition_pattern(const struct key_value_info *kvi, return 0; } -static int include_by_path(const struct key_value_info *kvi, - const char *path, - const char *cond, size_t cond_len, int icase) +static int include_by_gitdir(const struct key_value_info *kvi, + const struct config_options *opts, + const char *cond, size_t cond_len, int icase) { struct strbuf text = STRBUF_INIT; struct strbuf pattern = STRBUF_INIT; size_t prefix; int ret = 0; + const char *git_dir; int already_tried_absolute = 0; - if (!path) + if (opts->git_dir) + git_dir = opts->git_dir; + else goto done; - strbuf_realpath(&text, path, 1); + strbuf_realpath(&text, git_dir, 1); strbuf_add(&pattern, cond, cond_len); ret = prepare_include_condition_pattern(kvi, &pattern, &prefix); if (ret < 0) @@ -281,7 +284,7 @@ again: * which'll do the right thing */ strbuf_reset(&text); - strbuf_add_absolute_path(&text, path); + strbuf_add_absolute_path(&text, git_dir); already_tried_absolute = 1; goto again; } @@ -397,15 +400,9 @@ static int include_condition_is_true(const struct key_value_info *kvi, const struct config_options *opts = inc->opts; if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len)) - return include_by_path(kvi, opts->git_dir, cond, cond_len, 0); + return include_by_gitdir(kvi, opts, 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); + return include_by_gitdir(kvi, opts, 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 8ea410278e..f3892578e4 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -396,117 +396,4 @@ 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