config: match both symlink & realpath versions in IncludeIf.gitdir:*
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Tue, 16 May 2017 08:28:46 +0000 (08:28 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 May 2017 01:32:26 +0000 (10:32 +0900)
Change the conditional inclusion mechanism to support
e.g. gitdir:~/git_tree/repo where ~/git_tree is a symlink to
/mnt/stuff/repo.

This worked in the initial version of this facility[1], but regressed
later in the series while solving a related bug[2].

Now gitdir: will match against the symlinked
path (e.g. gitdir:~/git_tree/repo) in addition to the current
/mnt/stuff/repo path.

Since this is already in a release version note in the documentation
that this behavior changed, so users who expect their configuration to
work on both v2.13.0 and some future version of git with this fix
aren't utterly confused.

1. commit 3efd0bedc6 ("config: add conditional include", 2017-03-01)
2. commit 86f9515708 ("config: resolve symlinks in conditional
include's patterns", 2017-04-05)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
config.c
t/t1305-config-include.sh
index 475e874d51550eba26a578c0ce3b17b61384fddc..302b8af192da7ae73e13af164c7630444a9c28fe 100644 (file)
@@ -140,6 +140,16 @@ A few more notes on matching via `gitdir` and `gitdir/i`:
 
  * Symlinks in `$GIT_DIR` are not resolved before matching.
 
+ * Both the symlink & realpath versions of paths will be matched
+   outside of `$GIT_DIR`. E.g. if ~/git is a symlink to
+   /mnt/storage/git, both `gitdir:~/git` and `gitdir:/mnt/storage/git`
+   will match.
++
+This was not the case in the initial release of this feature in
+v2.13.0, which only matched the realpath version. Configuration that
+wants to be compatible with the initial release of this feature needs
+to either specify only the realpath version, or both versions.
+
  * Note that "../" is not special and will match literally, which is
    unlikely what you want.
 
index b4a3205da32faf43db1ab990f08c0bb941af87d0..f97842869546bfe79610814c8709341ff4b73738 100644 (file)
--- a/config.c
+++ b/config.c
@@ -214,6 +214,7 @@ static int include_by_gitdir(const struct config_options *opts,
        struct strbuf pattern = STRBUF_INIT;
        int ret = 0, prefix;
        const char *git_dir;
+       int already_tried_absolute = 0;
 
        if (opts->git_dir)
                git_dir = opts->git_dir;
@@ -226,6 +227,7 @@ static int include_by_gitdir(const struct config_options *opts,
        strbuf_add(&pattern, cond, cond_len);
        prefix = prepare_include_condition_pattern(&pattern);
 
+again:
        if (prefix < 0)
                goto done;
 
@@ -245,6 +247,20 @@ static int include_by_gitdir(const struct config_options *opts,
        ret = !wildmatch(pattern.buf + prefix, text.buf + prefix,
                         icase ? WM_CASEFOLD : 0, NULL);
 
+       if (!ret && !already_tried_absolute) {
+               /*
+                * We've tried e.g. matching gitdir:~/work, but if
+                * ~/work is a symlink to /mnt/storage/work
+                * strbuf_realpath() will expand it, so the rule won't
+                * match. Let's match against a
+                * strbuf_add_absolute_path() version of the path,
+                * which'll do the right thing
+                */
+               strbuf_reset(&text);
+               strbuf_add_absolute_path(&text, git_dir);
+               already_tried_absolute = 1;
+               goto again;
+       }
 done:
        strbuf_release(&pattern);
        strbuf_release(&text);
index 933915ec06ec725f7cf6a9ed3e251f6ff2390f76..d9d2f545a4ed735e02f7d5cd6ceee7d873fdec94 100755 (executable)
@@ -273,6 +273,29 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'
        )
 '
 
+test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
+       ln -s foo bar &&
+       (
+               cd bar &&
+               echo "[includeIf \"gitdir:bar/\"]path=bar7" >>.git/config &&
+               echo "[test]seven=7" >.git/bar7 &&
+               echo 7 >expect &&
+               git config test.seven >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '
+       (
+               cd bar &&
+               echo "[includeIf \"gitdir/i:BAR/\"]path=bar8" >>.git/config &&
+               echo "[test]eight=8" >.git/bar8 &&
+               echo 8 >expect &&
+               git config test.eight >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_expect_success 'include cycles are detected' '
        cat >.gitconfig <<-\EOF &&
        [test]value = gitconfig