Skip to content

Commit 2f6c976

Browse files
committed
magic pathspec: futureproof shorthand form
The earlier design was to take whatever non-alnum that the short format parser happens to support, leaving the rest as part of the pattern, so a version of git that knows '*' magic and a version that does not would have behaved differently when given ":*Makefile". The former would have applied the '*' magic to the pattern "Makefile", while the latter would used no magic to the pattern "*Makefile". Instead, just reserve all non-alnum ASCII letters that are neither glob nor regexp special as potential magic signature, and when we see a magic that is not supported, die with an error message, just like the longhand codepath does. With this, ":%#!*Makefile" will always mean "%#!" magic applied to the pattern "*Makefile", no matter what version of git is used (it is a different matter if the version of git supports all of these three magic matching rules). Also make ':' without anything else to mean "there is no pathspec". This would allow differences between "git log" and "git log ." run from the top level of the working tree (the latter simplifies no-op commits away from the history) to be expressed from a subdirectory by saying "git log :". Helped-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8a42c98 commit 2f6c976

File tree

3 files changed

+18
-8
lines changed

3 files changed

+18
-8
lines changed

ctype.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@ enum {
1010
A = GIT_ALPHA,
1111
D = GIT_DIGIT,
1212
G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
13-
R = GIT_REGEX_SPECIAL /* $, (, ), +, ., ^, {, | */
13+
R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */
14+
P = GIT_PATHSPEC_MAGIC /* other non-alnum, except for ] and } */
1415
};
1516

1617
unsigned char sane_ctype[256] = {
1718
0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
1819
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
19-
S, 0, 0, 0, R, 0, 0, 0, R, R, G, R, 0, 0, R, 0, /* 32.. 47 */
20-
D, D, D, D, D, D, D, D, D, D, 0, 0, 0, 0, 0, G, /* 48.. 63 */
21-
0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
22-
A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, 0, /* 80.. 95 */
23-
0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
24-
A, A, A, A, A, A, A, A, A, A, A, R, R, 0, 0, 0, /* 112..127 */
20+
S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
21+
D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
22+
P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
23+
A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, P, /* 80.. 95 */
24+
P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
25+
A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0, /* 112..127 */
2526
/* Nothing in the 128.. range */
2627
};

git-compat-util.h

+2
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ extern unsigned char sane_ctype[256];
462462
#define GIT_ALPHA 0x04
463463
#define GIT_GLOB_SPECIAL 0x08
464464
#define GIT_REGEX_SPECIAL 0x10
465+
#define GIT_PATHSPEC_MAGIC 0x20
465466
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
466467
#define isascii(x) (((x) & ~0x7f) == 0)
467468
#define isspace(x) sane_istest(x,GIT_SPACE)
@@ -472,6 +473,7 @@ extern unsigned char sane_ctype[256];
472473
#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
473474
#define tolower(x) sane_case((unsigned char)(x), 0x20)
474475
#define toupper(x) sane_case((unsigned char)(x), 0)
476+
#define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC)
475477

476478
static inline int sane_case(int x, int high)
477479
{

setup.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,26 @@ const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
197197
}
198198
if (*copyfrom == ')')
199199
copyfrom++;
200+
} else if (!elt[1]) {
201+
/* Just ':' -- no element! */
202+
return NULL;
200203
} else {
201204
/* shorthand */
202205
for (copyfrom = elt + 1;
203206
*copyfrom && *copyfrom != ':';
204207
copyfrom++) {
205208
char ch = *copyfrom;
209+
210+
if (!is_pathspec_magic(ch))
211+
break;
206212
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
207213
if (pathspec_magic[i].mnemonic == ch) {
208214
magic |= pathspec_magic[i].bit;
209215
break;
210216
}
211217
if (ARRAY_SIZE(pathspec_magic) <= i)
212-
break;
218+
die("Unimplemented pathspec magic '%c' in '%s'",
219+
ch, elt);
213220
}
214221
if (*copyfrom == ':')
215222
copyfrom++;

0 commit comments

Comments
 (0)