pathspec: support :(literal) syntax for noglob pathspec
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 14 Jul 2013 08:36:06 +0000 (15:36 +0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 15 Jul 2013 17:56:09 +0000 (10:56 -0700)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/glossary-content.txt
builtin/add.c
builtin/diff.c
dir.c
pathspec.c
pathspec.h
t/t6130-pathspec-noglob.sh
tree-diff.c
tree-walk.c
index dba5062b379cdfcdde31ee0f6809e964f979b5f5..ca9f20f25ff5e9fd153f91ff0e2ee66108ae2b74 100644 (file)
@@ -322,10 +322,22 @@ and a close parentheses `)`, and the remainder is the pattern to match
 against the path.
 +
 The "magic signature" consists of an ASCII symbol that is not
 against the path.
 +
 The "magic signature" consists of an ASCII symbol that is not
-alphanumeric. Currently only the slash `/` is recognized as a
-"magic signature": it makes the pattern match from the root of
-the working tree, even when you are running the command from
-inside a subdirectory.
+alphanumeric.
++
+--
+top `/`;;
+       The magic word `top` (mnemonic: `/`) makes the pattern match
+       from the root of the working tree, even when you are running
+       the command from inside a subdirectory.
+
+literal;;
+       Wildcards in the pattern such as `*` or `?` are treated
+       as literal characters.
+--
++
+Currently only the slash `/` is recognized as the "magic signature",
+but it is envisioned that we will support more types of magic in later
+versions of Git.
 +
 A pathspec with only a colon means "there is no pathspec". This form
 should not be combined with other pathspec.
 +
 A pathspec with only a colon means "there is no pathspec". This form
 should not be combined with other pathspec.
index 0b80fa8956c8833bffced2f413fd834097c9ba50..663ddd122cca1da02d891b85400d0819d13a9ca8 100644 (file)
@@ -541,7 +541,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                /*
                 * file_exists() assumes exact match
                 */
                /*
                 * file_exists() assumes exact match
                 */
-               GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);
+               GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
 
                for (i = 0; i < pathspec.nr; i++) {
                        const char *path = pathspec.items[i].match;
 
                for (i = 0; i < pathspec.nr; i++) {
                        const char *path = pathspec.items[i].match;
index bb84ba0e4694a6ef2cda7898ec9c61fa80bf74ae..2fb8c5dc0b6fdc97beb82f4dc3802a8f0dad8211 100644 (file)
@@ -368,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        }
        if (rev.prune_data.nr) {
                /* builtin_diff_b_f() */
        }
        if (rev.prune_data.nr) {
                /* builtin_diff_b_f() */
-               GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);
+               GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
                if (!path)
                        path = rev.prune_data.items[0].match;
                paths += rev.prune_data.nr;
                if (!path)
                        path = rev.prune_data.items[0].match;
                paths += rev.prune_data.nr;
diff --git a/dir.c b/dir.c
index 79465e7f4caca6ec014ed5052dcc14cd038430f2..50ec2f547800ecb929c694bd6ff059cbd38055da 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -108,7 +108,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
        int n;
        size_t max = 0;
 
        int n;
        size_t max = 0;
 
-       GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
+       GUARD_PATHSPEC(pathspec,
+                      PATHSPEC_FROMTOP |
+                      PATHSPEC_MAXDEPTH |
+                      PATHSPEC_LITERAL);
 
        for (n = 0; n < pathspec->nr; n++) {
                size_t i = 0, len = 0;
 
        for (n = 0; n < pathspec->nr; n++) {
                size_t i = 0, len = 0;
@@ -232,7 +235,10 @@ int match_pathspec_depth(const struct pathspec *ps,
 {
        int i, retval = 0;
 
 {
        int i, retval = 0;
 
-       GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
+       GUARD_PATHSPEC(ps,
+                      PATHSPEC_FROMTOP |
+                      PATHSPEC_MAXDEPTH |
+                      PATHSPEC_LITERAL);
 
        if (!ps->nr) {
                if (!ps->recursive ||
 
        if (!ps->nr) {
                if (!ps->recursive ||
@@ -1288,7 +1294,10 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
         * Check out create_simplify()
         */
        if (pathspec)
         * Check out create_simplify()
         */
        if (pathspec)
-               GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
+               GUARD_PATHSPEC(pathspec,
+                              PATHSPEC_FROMTOP |
+                              PATHSPEC_MAXDEPTH |
+                              PATHSPEC_LITERAL);
 
        if (has_symlink_leading_path(path, len))
                return dir->nr;
 
        if (has_symlink_leading_path(path, len))
                return dir->nr;
index b2e3a8778c24c13cea34f092cb7fdb00bcd7533d..6a16938cb65936fd1df816b149408daa57945c55 100644 (file)
@@ -70,6 +70,7 @@ static struct pathspec_magic {
        const char *name;
 } pathspec_magic[] = {
        { PATHSPEC_FROMTOP, '/', "top" },
        const char *name;
 } pathspec_magic[] = {
        { PATHSPEC_FROMTOP, '/', "top" },
+       { PATHSPEC_LITERAL,   0, "literal" },
 };
 
 /*
 };
 
 /*
@@ -92,13 +93,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
                                const char *elt)
 {
        static int literal_global = -1;
                                const char *elt)
 {
        static int literal_global = -1;
-       unsigned magic = 0, short_magic = 0;
+       unsigned magic = 0, short_magic = 0, global_magic = 0;
        const char *copyfrom = elt, *long_magic_end = NULL;
        char *match;
        int i, pathspec_prefix = -1;
 
        if (literal_global < 0)
                literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
        const char *copyfrom = elt, *long_magic_end = NULL;
        char *match;
        int i, pathspec_prefix = -1;
 
        if (literal_global < 0)
                literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
+       if (literal_global)
+               global_magic |= PATHSPEC_LITERAL;
 
        if (elt[0] != ':') {
                ; /* nothing to do */
 
        if (elt[0] != ':') {
                ; /* nothing to do */
@@ -164,6 +167,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 
        magic |= short_magic;
        *p_short_magic = short_magic;
 
        magic |= short_magic;
        *p_short_magic = short_magic;
+       magic |= global_magic;
 
        if (pathspec_prefix >= 0 &&
            (prefixlen || (prefix && *prefix)))
 
        if (pathspec_prefix >= 0 &&
            (prefixlen || (prefix && *prefix)))
@@ -236,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
                                     elt, ce_len, ce->name);
                }
 
                                     elt, ce_len, ce->name);
                }
 
-       if (literal_global)
+       if (magic & PATHSPEC_LITERAL)
                item->nowildcard_len = item->len;
        else {
                item->nowildcard_len = simple_length(item->match);
                item->nowildcard_len = item->len;
        else {
                item->nowildcard_len = simple_length(item->match);
@@ -402,7 +406,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 {
        struct pathspec ps;
        parse_pathspec(&ps,
 {
        struct pathspec ps;
        parse_pathspec(&ps,
-                      PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
+                      PATHSPEC_ALL_MAGIC &
+                      ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
                       PATHSPEC_PREFER_CWD,
                       prefix, pathspec);
        return ps._raw;
                       PATHSPEC_PREFER_CWD,
                       prefix, pathspec);
        return ps._raw;
index 7ef9896edb84df10488437afe4d87dfd1c626d17..987d70c55a2e68662609b0ed3b7507dda2170913 100644 (file)
@@ -4,9 +4,11 @@
 /* Pathspec magic */
 #define PATHSPEC_FROMTOP       (1<<0)
 #define PATHSPEC_MAXDEPTH      (1<<1)
 /* Pathspec magic */
 #define PATHSPEC_FROMTOP       (1<<0)
 #define PATHSPEC_MAXDEPTH      (1<<1)
+#define PATHSPEC_LITERAL       (1<<2)
 #define PATHSPEC_ALL_MAGIC       \
        (PATHSPEC_FROMTOP       | \
 #define PATHSPEC_ALL_MAGIC       \
        (PATHSPEC_FROMTOP       | \
-        PATHSPEC_MAXDEPTH)
+        PATHSPEC_MAXDEPTH      | \
+        PATHSPEC_LITERAL)
 
 #define PATHSPEC_ONESTAR 1     /* the pathspec pattern sastisfies GFNM_ONESTAR */
 
 
 #define PATHSPEC_ONESTAR 1     /* the pathspec pattern sastisfies GFNM_ONESTAR */
 
index 39ef61994f6a4b4bea1731002f7637232e7dd349..49c148e17efab0bc512ca09ec4a37a448f8ec1a6 100755 (executable)
@@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' '
        test_cmp expect actual
 '
 
        test_cmp expect actual
 '
 
+test_expect_success 'no-glob option matches literally (vanilla)' '
+       echo vanilla >expect &&
+       git log --format=%s -- ":(literal)foo" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'no-glob option matches literally (star)' '
        echo star >expect &&
        git --literal-pathspecs log --format=%s -- "f*" >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'no-glob option matches literally (star)' '
        echo star >expect &&
        git --literal-pathspecs log --format=%s -- "f*" >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'no-glob option matches literally (star)' '
+       echo star >expect &&
+       git log --format=%s -- ":(literal)f*" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'no-glob option matches literally (bracket)' '
        echo bracket >expect &&
        git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'no-glob option matches literally (bracket)' '
        echo bracket >expect &&
        git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'no-glob option matches literally (bracket)' '
+       echo bracket >expect &&
+       git log --format=%s -- ":(literal)f[o][o]" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'no-glob environment variable works' '
        echo star >expect &&
        GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
 test_expect_success 'no-glob environment variable works' '
        echo star >expect &&
        GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
index 21a50d8ed3bc6fcfd92e4e00a23a80a20f869f9f..ccf9d7c8fd41c00f13136ef99d24180b36a098c1 100644 (file)
@@ -202,7 +202,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
         * path. Magic that matches more than one path is not
         * supported.
         */
         * path. Magic that matches more than one path is not
         * supported.
         */
-       GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);
+       GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
 #if 0
        /*
         * We should reject wildcards as well. Unfortunately we
 #if 0
        /*
         * We should reject wildcards as well. Unfortunately we
index 37b157ed6e2c90d3ae24e39e944237a7c75d8bf2..676bd7f3c850dcc9b75553986ddeb1fe152da3c3 100644 (file)
@@ -636,7 +636,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
        enum interesting never_interesting = ps->has_wildcard ?
                entry_not_interesting : all_entries_not_interesting;
 
        enum interesting never_interesting = ps->has_wildcard ?
                entry_not_interesting : all_entries_not_interesting;
 
-       GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
+       GUARD_PATHSPEC(ps,
+                      PATHSPEC_FROMTOP |
+                      PATHSPEC_MAXDEPTH |
+                      PATHSPEC_LITERAL);
 
        if (!ps->nr) {
                if (!ps->recursive ||
 
        if (!ps->nr) {
                if (!ps->recursive ||