summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/glossary-content.txt20
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/diff.c2
-rw-r--r--dir.c15
-rw-r--r--pathspec.c11
-rw-r--r--pathspec.h4
-rwxr-xr-xt/t6130-pathspec-noglob.sh18
-rw-r--r--tree-diff.c2
-rw-r--r--tree-walk.c5
9 files changed, 64 insertions, 15 deletions
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt
index dba5062b37..ca9f20f25f 100644
--- a/Documentation/glossary-content.txt
+++ b/Documentation/glossary-content.txt
@@ -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
-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.
diff --git a/builtin/add.c b/builtin/add.c
index 0b80fa8956..663ddd122c 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -541,7 +541,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 bb84ba0e46..2fb8c5dc0b 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -368,7 +368,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 79465e7f4c..50ec2f5478 100644
--- 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;
- 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;
@@ -232,7 +235,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 ||
@@ -1288,7 +1294,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 b2e3a8778c..6a16938cb6 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 */
@@ -164,6 +167,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)))
@@ -236,7 +240,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);
@@ -402,7 +406,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 7ef9896edb..987d70c55a 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 39ef61994f..49c148e17e 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 21a50d8ed3..ccf9d7c8fd 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 37b157ed6e..676bd7f3c8 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 ||