Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/glossary-content.txt | 4 ++++ builtin/add.c | 2 +- builtin/diff.c | 2 +- dir.c | 15 ++++++++++++--- pathspec.c | 11 ++++++++--- pathspec.h | 4 +++- t/t6130-pathspec-noglob.sh | 18 ++++++++++++++++++ tree-diff.c | 2 +- tree-walk.c | 5 ++++- 9 files changed, 52 insertions(+), 11 deletions(-) diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index eb7ba84..8b91aeb 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -323,6 +323,10 @@ 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", diff --git a/builtin/add.c b/builtin/add.c index aa0709e..8bc6b45 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -426,7 +426,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) /* * 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; diff --git a/builtin/diff.c b/builtin/diff.c index 6b4e3f9..b78435f 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -372,7 +372,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } 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; diff --git a/dir.c b/dir.c index 4f5a2c9..8d9ed24 100644 --- a/dir.c +++ b/dir.c @@ -65,7 +65,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec) 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; @@ -189,7 +192,10 @@ int match_pathspec_depth(const struct pathspec *ps, { 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 || @@ -1338,7 +1344,10 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru * 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; diff --git a/pathspec.c b/pathspec.c index 7b3dfc0..e57196d 100644 --- a/pathspec.c +++ b/pathspec.c @@ -70,6 +70,7 @@ static struct pathspec_magic { 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; - 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); + if (literal_global) + global_magic |= PATHSPEC_LITERAL; if (elt[0] != ':') { ; /* nothing to do */ @@ -163,6 +166,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, magic |= short_magic; *p_short_magic = short_magic; + magic |= global_magic; if (pathspec_prefix >= 0 && (prefixlen || (prefix && *prefix))) @@ -235,7 +239,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 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); @@ -395,7 +399,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec) { 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; diff --git a/pathspec.h b/pathspec.h index 8f339a5..d5db7d5 100644 --- a/pathspec.h +++ b/pathspec.h @@ -4,9 +4,11 @@ /* Pathspec magic */ #define PATHSPEC_FROMTOP (1<<0) #define PATHSPEC_MAXDEPTH (1<<1) +#define PATHSPEC_LITERAL (1<<2) #define PATHSPEC_ALL_MAGIC \ (PATHSPEC_FROMTOP | \ - PATHSPEC_MAXDEPTH) + PATHSPEC_MAXDEPTH | \ + PATHSPEC_LITERAL) #define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */ diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh index 39ef619..49c148e 100755 --- a/t/t6130-pathspec-noglob.sh +++ b/t/t6130-pathspec-noglob.sh @@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' ' 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 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 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 && diff --git a/tree-diff.c b/tree-diff.c index 21a50d8..ccf9d7c 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -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. */ - GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP); + GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL); #if 0 /* * We should reject wildcards as well. Unfortunately we diff --git a/tree-walk.c b/tree-walk.c index 37b157e..676bd7f 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -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; - GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH); + GUARD_PATHSPEC(ps, + PATHSPEC_FROMTOP | + PATHSPEC_MAXDEPTH | + PATHSPEC_LITERAL); if (!ps->nr) { if (!ps->recursive || -- 1.8.0.rc0.19.g7bbb31d -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html