pathspec: support :(literal) syntax for noglob pathspec
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Jul 14, 2013 at 15:36 UTC
5c6933d201fab183a9779dca0fe43bf2f1eca098
9 files changed
+64
-15
Documentation/glossary-content.txt
+16
-4
@@ -322,10 +322,22 @@ and a close parentheses `)`, and the remainder is the pattern to match
322
against the path.
323
+
324
The "magic signature" consists of an ASCII symbol that is not
325
-alphanumeric. Currently only the slash `/` is recognized as a
326
-"magic signature": it makes the pattern match from the root of
327
-the working tree, even when you are running the command from
328
-inside a subdirectory.
325
+alphanumeric.
326
++
327
+--
328
+top `/`;;
329
+ The magic word `top` (mnemonic: `/`) makes the pattern match
330
+ from the root of the working tree, even when you are running
331
+ the command from inside a subdirectory.
332
+
333
+literal;;
334
+ Wildcards in the pattern such as `*` or `?` are treated
335
+ as literal characters.
336
+--
337
++
338
+Currently only the slash `/` is recognized as the "magic signature",
339
+but it is envisioned that we will support more types of magic in later
340
+versions of Git.
341
+
342
A pathspec with only a colon means "there is no pathspec". This form
343
should not be combined with other pathspec.
builtin/add.c
+1
-1
@@ -541,7 +541,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
541
/*
542
* file_exists() assumes exact match
543
*/
544
- GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);
544
+ GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
545
546
for (i = 0; i < pathspec.nr; i++) {
547
const char *path = pathspec.items[i].match;
builtin/diff.c
+1
-1
@@ -368,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
368
}
369
if (rev.prune_data.nr) {
370
/* builtin_diff_b_f() */
371
- GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);
371
+ GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
372
if (!path)
373
path = rev.prune_data.items[0].match;
374
paths += rev.prune_data.nr;
dir.c
+12
-3
@@ -108,7 +108,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
108
int n;
109
size_t max = 0;
110
111
- GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
111
+ GUARD_PATHSPEC(pathspec,
112
+ PATHSPEC_FROMTOP |
113
+ PATHSPEC_MAXDEPTH |
114
+ PATHSPEC_LITERAL);
115
116
for (n = 0; n < pathspec->nr; n++) {
117
size_t i = 0, len = 0;
@@ -232,7 +235,10 @@ int match_pathspec_depth(const struct pathspec *ps,
235
{
236
int i, retval = 0;
237
235
- GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
238
+ GUARD_PATHSPEC(ps,
239
+ PATHSPEC_FROMTOP |
240
+ PATHSPEC_MAXDEPTH |
241
+ PATHSPEC_LITERAL);
242
243
if (!ps->nr) {
244
if (!ps->recursive ||
@@ -1288,7 +1294,10 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
1294
* Check out create_simplify()
1295
*/
1296
if (pathspec)
1291
- GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
1297
+ GUARD_PATHSPEC(pathspec,
1298
+ PATHSPEC_FROMTOP |
1299
+ PATHSPEC_MAXDEPTH |
1300
+ PATHSPEC_LITERAL);
1301
1302
if (has_symlink_leading_path(path, len))
1303
return dir->nr;
pathspec.c
+8
-3
@@ -70,6 +70,7 @@ static struct pathspec_magic {
70
const char *name;
71
} pathspec_magic[] = {
72
{ PATHSPEC_FROMTOP, '/', "top" },
73
+ { PATHSPEC_LITERAL, 0, "literal" },
74
};
75
76
/*
@@ -92,13 +93,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
93
const char *elt)
94
{
95
static int literal_global = -1;
95
- unsigned magic = 0, short_magic = 0;
96
+ unsigned magic = 0, short_magic = 0, global_magic = 0;
97
const char *copyfrom = elt, *long_magic_end = NULL;
98
char *match;
99
int i, pathspec_prefix = -1;
100
101
if (literal_global < 0)
102
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
103
+ if (literal_global)
104
+ global_magic |= PATHSPEC_LITERAL;
105
106
if (elt[0] != ':') {
107
; /* nothing to do */
@@ -164,6 +167,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
167
168
magic |= short_magic;
169
*p_short_magic = short_magic;
170
+ magic |= global_magic;
171
172
if (pathspec_prefix >= 0 &&
173
(prefixlen || (prefix && *prefix)))
@@ -236,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
240
elt, ce_len, ce->name);
241
}
242
239
- if (literal_global)
243
+ if (magic & PATHSPEC_LITERAL)
244
item->nowildcard_len = item->len;
245
else {
246
item->nowildcard_len = simple_length(item->match);
@@ -402,7 +406,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
406
{
407
struct pathspec ps;
408
parse_pathspec(&ps,
405
- PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
409
+ PATHSPEC_ALL_MAGIC &
410
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
411
PATHSPEC_PREFER_CWD,
412
prefix, pathspec);
413
return ps._raw;
pathspec.h
+3
-1
@@ -4,9 +4,11 @@
4
/* Pathspec magic */
5
#define PATHSPEC_FROMTOP (1<<0)
6
#define PATHSPEC_MAXDEPTH (1<<1)
7
+#define PATHSPEC_LITERAL (1<<2)
8
#define PATHSPEC_ALL_MAGIC \
9
(PATHSPEC_FROMTOP | \
9
- PATHSPEC_MAXDEPTH)
10
+ PATHSPEC_MAXDEPTH | \
11
+ PATHSPEC_LITERAL)
12
13
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
14
t/t6130-pathspec-noglob.sh
+18
@@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' '
47
test_cmp expect actual
48
'
49
50
+test_expect_success 'no-glob option matches literally (vanilla)' '
51
+ echo vanilla >expect &&
52
+ git log --format=%s -- ":(literal)foo" >actual &&
53
+ test_cmp expect actual
54
+'
55
+
56
test_expect_success 'no-glob option matches literally (star)' '
57
echo star >expect &&
58
git --literal-pathspecs log --format=%s -- "f*" >actual &&
59
test_cmp expect actual
60
'
61
62
+test_expect_success 'no-glob option matches literally (star)' '
63
+ echo star >expect &&
64
+ git log --format=%s -- ":(literal)f*" >actual &&
65
+ test_cmp expect actual
66
+'
67
+
68
test_expect_success 'no-glob option matches literally (bracket)' '
69
echo bracket >expect &&
70
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
71
test_cmp expect actual
72
'
73
74
+test_expect_success 'no-glob option matches literally (bracket)' '
75
+ echo bracket >expect &&
76
+ git log --format=%s -- ":(literal)f[o][o]" >actual &&
77
+ test_cmp expect actual
78
+'
79
+
80
test_expect_success 'no-glob environment variable works' '
81
echo star >expect &&
82
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
tree-diff.c
+1
-1
@@ -202,7 +202,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
202
* path. Magic that matches more than one path is not
203
* supported.
204
*/
205
- GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);
205
+ GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
206
#if 0
207
/*
208
* We should reject wildcards as well. Unfortunately we
tree-walk.c
+4
-1
@@ -636,7 +636,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
636
enum interesting never_interesting = ps->has_wildcard ?
637
entry_not_interesting : all_entries_not_interesting;
638
639
- GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
639
+ GUARD_PATHSPEC(ps,
640
+ PATHSPEC_FROMTOP |
641
+ PATHSPEC_MAXDEPTH |
642
+ PATHSPEC_LITERAL);
643
644
if (!ps->nr) {
645
if (!ps->recursive ||