]> git.ipfire.org Git - thirdparty/git.git/commitdiff
verify_filename(): handle backslashes in "wildcards are pathspecs" rule
authorJeff King <peff@peff.net>
Sat, 25 Jan 2020 00:00:51 +0000 (19:00 -0500)
committerJunio C Hamano <gitster@pobox.com>
Mon, 27 Jan 2020 18:46:35 +0000 (10:46 -0800)
Commit 28fcc0b71a (pathspec: avoid the need of "--" when wildcard is
used, 2015-05-02) allowed:

  git rev-parse '*.c'

without the double-dash. But the rule it uses to check for wildcards
actually looks for any glob special. This is overly liberal, as it means
that a pattern that doesn't actually do any wildcard matching, like
"a\b", will be considered a pathspec.

If you do have such a file on disk, that's presumably what you wanted.
But if you don't, the results are confusing: rather than say "there's no
such path a\b", we'll quietly accept it as a pathspec which very likely
matches nothing (or at least not what you intended). Likewise, looking
for path "a\*b" doesn't expand the search at all; it would only find a
single entry, "a*b".

This commit switches the rule to trigger only when glob metacharacters
would expand the search, meaning both of those cases will now report an
error (you can still disambiguate using "--", of course; we're just
tightening the DWIM heuristic).

Note that we didn't test the original feature in 28fcc0b71a at all. So
this patch not only tests for these corner cases, but also adds a
regression test for the existing behavior.

Reported-by: David Burström <davidburstrom@spotify.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
setup.c
t/t1506-rev-parse-diagnosis.sh

diff --git a/setup.c b/setup.c
index e2a479a64fa4076bad8eaf6cf0949d0ae263da9d..12228c0d9c1e3dfb91c474aba8e891f0836dc6d9 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -197,9 +197,26 @@ static void NORETURN die_verify_filename(struct repository *r,
  */
 static int looks_like_pathspec(const char *arg)
 {
-       /* anything with a wildcard character */
-       if (!no_wildcard(arg))
-               return 1;
+       const char *p;
+       int escaped = 0;
+
+       /*
+        * Wildcard characters imply the user is looking to match pathspecs
+        * that aren't in the filesystem. Note that this doesn't include
+        * backslash even though it's a glob special; by itself it doesn't
+        * cause any increase in the match. Likewise ignore backslash-escaped
+        * wildcard characters.
+        */
+       for (p = arg; *p; p++) {
+               if (escaped) {
+                       escaped = 0;
+               } else if (is_glob_special(*p)) {
+                       if (*p == '\\')
+                               escaped = 1;
+                       else
+                               return 1;
+               }
+       }
 
        /* long-form pathspec magic */
        if (starts_with(arg, ":("))
index 624d0a588fe6dda03b929cd4239f62e765efa04a..2c2bcb024fcf44c50670dcae42b3ffb5d154cbe4 100755 (executable)
@@ -222,4 +222,18 @@ test_expect_success 'reject Nth ancestor if N is too high' '
        test_must_fail git rev-parse HEAD~100000000000000000000000000000000
 '
 
+test_expect_success 'pathspecs with wildcards are not ambiguous' '
+       echo "*.c" >expect &&
+       git rev-parse "*.c" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'backslash does not trigger wildcard rule' '
+       test_must_fail git rev-parse "foo\\bar"
+'
+
+test_expect_success 'escaped char does not trigger wildcard rule' '
+       test_must_fail git rev-parse "foo\\*bar"
+'
+
 test_done