Skip to content

Commit 5c6933d

Browse files
pcloudsgitster
authored andcommitted
pathspec: support :(literal) syntax for noglob pathspec
Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 341003e commit 5c6933d

File tree

9 files changed

+64
-15
lines changed

9 files changed

+64
-15
lines changed

Documentation/glossary-content.txt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,22 @@ and a close parentheses `)`, and the remainder is the pattern to match
322322
against the path.
323323
+
324324
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.
329341
+
330342
A pathspec with only a colon means "there is no pathspec". This form
331343
should not be combined with other pathspec.

builtin/add.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
541541
/*
542542
* file_exists() assumes exact match
543543
*/
544-
GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);
544+
GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
545545

546546
for (i = 0; i < pathspec.nr; i++) {
547547
const char *path = pathspec.items[i].match;

builtin/diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
368368
}
369369
if (rev.prune_data.nr) {
370370
/* builtin_diff_b_f() */
371-
GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);
371+
GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
372372
if (!path)
373373
path = rev.prune_data.items[0].match;
374374
paths += rev.prune_data.nr;

dir.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
108108
int n;
109109
size_t max = 0;
110110

111-
GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
111+
GUARD_PATHSPEC(pathspec,
112+
PATHSPEC_FROMTOP |
113+
PATHSPEC_MAXDEPTH |
114+
PATHSPEC_LITERAL);
112115

113116
for (n = 0; n < pathspec->nr; n++) {
114117
size_t i = 0, len = 0;
@@ -232,7 +235,10 @@ int match_pathspec_depth(const struct pathspec *ps,
232235
{
233236
int i, retval = 0;
234237

235-
GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
238+
GUARD_PATHSPEC(ps,
239+
PATHSPEC_FROMTOP |
240+
PATHSPEC_MAXDEPTH |
241+
PATHSPEC_LITERAL);
236242

237243
if (!ps->nr) {
238244
if (!ps->recursive ||
@@ -1288,7 +1294,10 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
12881294
* Check out create_simplify()
12891295
*/
12901296
if (pathspec)
1291-
GUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
1297+
GUARD_PATHSPEC(pathspec,
1298+
PATHSPEC_FROMTOP |
1299+
PATHSPEC_MAXDEPTH |
1300+
PATHSPEC_LITERAL);
12921301

12931302
if (has_symlink_leading_path(path, len))
12941303
return dir->nr;

pathspec.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static struct pathspec_magic {
7070
const char *name;
7171
} pathspec_magic[] = {
7272
{ PATHSPEC_FROMTOP, '/', "top" },
73+
{ PATHSPEC_LITERAL, 0, "literal" },
7374
};
7475

7576
/*
@@ -92,13 +93,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
9293
const char *elt)
9394
{
9495
static int literal_global = -1;
95-
unsigned magic = 0, short_magic = 0;
96+
unsigned magic = 0, short_magic = 0, global_magic = 0;
9697
const char *copyfrom = elt, *long_magic_end = NULL;
9798
char *match;
9899
int i, pathspec_prefix = -1;
99100

100101
if (literal_global < 0)
101102
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
103+
if (literal_global)
104+
global_magic |= PATHSPEC_LITERAL;
102105

103106
if (elt[0] != ':') {
104107
; /* nothing to do */
@@ -164,6 +167,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
164167

165168
magic |= short_magic;
166169
*p_short_magic = short_magic;
170+
magic |= global_magic;
167171

168172
if (pathspec_prefix >= 0 &&
169173
(prefixlen || (prefix && *prefix)))
@@ -236,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
236240
elt, ce_len, ce->name);
237241
}
238242

239-
if (literal_global)
243+
if (magic & PATHSPEC_LITERAL)
240244
item->nowildcard_len = item->len;
241245
else {
242246
item->nowildcard_len = simple_length(item->match);
@@ -402,7 +406,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
402406
{
403407
struct pathspec ps;
404408
parse_pathspec(&ps,
405-
PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
409+
PATHSPEC_ALL_MAGIC &
410+
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
406411
PATHSPEC_PREFER_CWD,
407412
prefix, pathspec);
408413
return ps._raw;

pathspec.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
/* Pathspec magic */
55
#define PATHSPEC_FROMTOP (1<<0)
66
#define PATHSPEC_MAXDEPTH (1<<1)
7+
#define PATHSPEC_LITERAL (1<<2)
78
#define PATHSPEC_ALL_MAGIC \
89
(PATHSPEC_FROMTOP | \
9-
PATHSPEC_MAXDEPTH)
10+
PATHSPEC_MAXDEPTH | \
11+
PATHSPEC_LITERAL)
1012

1113
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
1214

t/t6130-pathspec-noglob.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' '
4747
test_cmp expect actual
4848
'
4949

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+
5056
test_expect_success 'no-glob option matches literally (star)' '
5157
echo star >expect &&
5258
git --literal-pathspecs log --format=%s -- "f*" >actual &&
5359
test_cmp expect actual
5460
'
5561

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+
5668
test_expect_success 'no-glob option matches literally (bracket)' '
5769
echo bracket >expect &&
5870
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
5971
test_cmp expect actual
6072
'
6173

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+
6280
test_expect_success 'no-glob environment variable works' '
6381
echo star >expect &&
6482
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&

tree-diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
202202
* path. Magic that matches more than one path is not
203203
* supported.
204204
*/
205-
GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);
205+
GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
206206
#if 0
207207
/*
208208
* We should reject wildcards as well. Unfortunately we

tree-walk.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
636636
enum interesting never_interesting = ps->has_wildcard ?
637637
entry_not_interesting : all_entries_not_interesting;
638638

639-
GUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);
639+
GUARD_PATHSPEC(ps,
640+
PATHSPEC_FROMTOP |
641+
PATHSPEC_MAXDEPTH |
642+
PATHSPEC_LITERAL);
640643

641644
if (!ps->nr) {
642645
if (!ps->recursive ||

0 commit comments

Comments
 (0)