pathspec: only match across submodule boundaries when requested
authorBrandon Williams <bmwill@google.com>
Tue, 5 Dec 2017 00:07:34 +0000 (16:07 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 5 Dec 2017 17:23:15 +0000 (09:23 -0800)
Commit 74ed43711fd (grep: enable recurse-submodules to work on <tree>
objects, 2016-12-16) taught 'tree_entry_interesting()' to be able to
match across submodule boundaries in the presence of wildcards. This is
done by performing literal matching up to the first wildcard and then
punting to the submodule itself to perform more accurate pattern
matching. Instead of introducing a new flag to request this behavior,
commit 74ed43711fd overloaded the already existing 'recursive' flag in
'struct pathspec' to request this behavior.

This leads to a bug where whenever any other caller has the 'recursive'
flag set as well as a pathspec with wildcards that all submodules will
be indicated as matches. One simple example of this is:

git init repo
cd repo

git init submodule
git -C submodule commit -m initial --allow-empty

touch "[bracket]"
git add "[bracket]"
git commit -m bracket
git add submodule
git commit -m submodule

git rev-list HEAD -- "[bracket]"

Fix this by introducing the new flag 'recurse_submodules' in 'struct
pathspec' and using this flag to determine if matches should be allowed
to cross submodule boundaries.

This fixes https://github.com/git-for-windows/git/issues/1371.

Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/grep.c
pathspec.h
t/t4208-log-magic-pathspec.sh
tree-walk.c
index 6946cf4bbc825cbd1335ab5464428f54483701f8..4bbbce2a642186b7de8d9653751e29b0aee617e7 100644 (file)
@@ -1015,6 +1015,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                       prefix, argv + i);
        pathspec.max_depth = opt.max_depth;
        pathspec.recursive = 1;
+       pathspec.recurse_submodules = !!recurse_submodules;
 
 #ifndef NO_PTHREADS
        if (list.nr || cached || show_in_pager)
index 60e6500401e687bc0d764c38c5d8b4928b7bfde8..d000b63d80df8bbed3c3f1d7b4f3082ad4bdc850 100644 (file)
@@ -24,6 +24,7 @@ struct pathspec {
        int nr;
        unsigned int has_wildcard:1;
        unsigned int recursive:1;
+       unsigned int recurse_submodules:1;
        unsigned magic;
        int max_depth;
        struct pathspec_item {
index 935df6a65cab2ba901856633baad7b2e38ebecfa..a1705f70cffe2332fc65f670797539986f330f70 100755 (executable)
@@ -93,4 +93,23 @@ test_expect_success 'command line pathspec parsing for "git log"' '
        git log --merge -- a
 '
 
+test_expect_success 'tree_entry_interesting does not match past submodule boundaries' '
+       test_when_finished "rm -rf repo submodule" &&
+       git init submodule &&
+       test_commit -C submodule initial &&
+       git init repo &&
+       >"repo/[bracket]" &&
+       git -C repo add "[bracket]" &&
+       test_tick &&
+       git -C repo commit -m bracket &&
+       git -C repo rev-list HEAD -- "[bracket]" >expect &&
+
+       git -C repo submodule add ../submodule &&
+       test_tick &&
+       git -C repo commit -m submodule &&
+
+       git -C repo rev-list HEAD -- "[bracket]" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 6a42e402b00a3da90a008adf6e4c68dc8c45e516..d6de5315be195ca248ba524dcfa4cfa99f0a6b7c 100644 (file)
@@ -1011,7 +1011,8 @@ static enum interesting do_match(const struct name_entry *entry,
                                 * character.  More accurate matching can then
                                 * be performed in the submodule itself.
                                 */
-                               if (ps->recursive && S_ISGITLINK(entry->mode) &&
+                               if (ps->recurse_submodules &&
+                                   S_ISGITLINK(entry->mode) &&
                                    !ps_strncmp(item, match + baselen,
                                                entry->path,
                                                item->nowildcard_len - baselen))
@@ -1060,7 +1061,7 @@ static enum interesting do_match(const struct name_entry *entry,
                 * character.  More accurate matching can then
                 * be performed in the submodule itself.
                 */
-               if (ps->recursive && S_ISGITLINK(entry->mode) &&
+               if (ps->recurse_submodules && S_ISGITLINK(entry->mode) &&
                    !ps_strncmp(item, match, base->buf + base_offset,
                                item->nowildcard_len)) {
                        strbuf_setlen(base, base_offset + baselen);