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>
This commit is contained in:

committed by
Junio C Hamano

parent
341003e715
commit
5c6933d201
@ -322,10 +322,22 @@ and a close parentheses `)`, and the remainder is the pattern to match
|
|||||||
against the path.
|
against the path.
|
||||||
+
|
+
|
||||||
The "magic signature" consists of an ASCII symbol that is not
|
The "magic signature" consists of an ASCII symbol that is not
|
||||||
alphanumeric. Currently only the slash `/` is recognized as a
|
alphanumeric.
|
||||||
"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.
|
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
|
A pathspec with only a colon means "there is no pathspec". This form
|
||||||
should not be combined with other pathspec.
|
should not be combined with other pathspec.
|
||||||
|
@ -541,7 +541,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||||||
/*
|
/*
|
||||||
* file_exists() assumes exact match
|
* file_exists() assumes exact match
|
||||||
*/
|
*/
|
||||||
GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);
|
GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
|
||||||
|
|
||||||
for (i = 0; i < pathspec.nr; i++) {
|
for (i = 0; i < pathspec.nr; i++) {
|
||||||
const char *path = pathspec.items[i].match;
|
const char *path = pathspec.items[i].match;
|
||||||
|
@ -368,7 +368,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
if (rev.prune_data.nr) {
|
if (rev.prune_data.nr) {
|
||||||
/* builtin_diff_b_f() */
|
/* builtin_diff_b_f() */
|
||||||
GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);
|
GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
|
||||||
if (!path)
|
if (!path)
|
||||||
path = rev.prune_data.items[0].match;
|
path = rev.prune_data.items[0].match;
|
||||||
paths += rev.prune_data.nr;
|
paths += rev.prune_data.nr;
|
||||||
|
15
dir.c
15
dir.c
@ -108,7 +108,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
|
|||||||
int n;
|
int n;
|
||||||
size_t max = 0;
|
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++) {
|
for (n = 0; n < pathspec->nr; n++) {
|
||||||
size_t i = 0, len = 0;
|
size_t i = 0, len = 0;
|
||||||
@ -232,7 +235,10 @@ int match_pathspec_depth(const struct pathspec *ps,
|
|||||||
{
|
{
|
||||||
int i, retval = 0;
|
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->nr) {
|
||||||
if (!ps->recursive ||
|
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()
|
* Check out create_simplify()
|
||||||
*/
|
*/
|
||||||
if (pathspec)
|
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))
|
if (has_symlink_leading_path(path, len))
|
||||||
return dir->nr;
|
return dir->nr;
|
||||||
|
11
pathspec.c
11
pathspec.c
@ -70,6 +70,7 @@ static struct pathspec_magic {
|
|||||||
const char *name;
|
const char *name;
|
||||||
} pathspec_magic[] = {
|
} pathspec_magic[] = {
|
||||||
{ PATHSPEC_FROMTOP, '/', "top" },
|
{ PATHSPEC_FROMTOP, '/', "top" },
|
||||||
|
{ PATHSPEC_LITERAL, 0, "literal" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -92,13 +93,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
const char *elt)
|
const char *elt)
|
||||||
{
|
{
|
||||||
static int literal_global = -1;
|
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;
|
const char *copyfrom = elt, *long_magic_end = NULL;
|
||||||
char *match;
|
char *match;
|
||||||
int i, pathspec_prefix = -1;
|
int i, pathspec_prefix = -1;
|
||||||
|
|
||||||
if (literal_global < 0)
|
if (literal_global < 0)
|
||||||
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
||||||
|
if (literal_global)
|
||||||
|
global_magic |= PATHSPEC_LITERAL;
|
||||||
|
|
||||||
if (elt[0] != ':') {
|
if (elt[0] != ':') {
|
||||||
; /* nothing to do */
|
; /* nothing to do */
|
||||||
@ -164,6 +167,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
|
|
||||||
magic |= short_magic;
|
magic |= short_magic;
|
||||||
*p_short_magic = short_magic;
|
*p_short_magic = short_magic;
|
||||||
|
magic |= global_magic;
|
||||||
|
|
||||||
if (pathspec_prefix >= 0 &&
|
if (pathspec_prefix >= 0 &&
|
||||||
(prefixlen || (prefix && *prefix)))
|
(prefixlen || (prefix && *prefix)))
|
||||||
@ -236,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
elt, ce_len, ce->name);
|
elt, ce_len, ce->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (literal_global)
|
if (magic & PATHSPEC_LITERAL)
|
||||||
item->nowildcard_len = item->len;
|
item->nowildcard_len = item->len;
|
||||||
else {
|
else {
|
||||||
item->nowildcard_len = simple_length(item->match);
|
item->nowildcard_len = simple_length(item->match);
|
||||||
@ -402,7 +406,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
|
|||||||
{
|
{
|
||||||
struct pathspec ps;
|
struct pathspec ps;
|
||||||
parse_pathspec(&ps,
|
parse_pathspec(&ps,
|
||||||
PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
|
PATHSPEC_ALL_MAGIC &
|
||||||
|
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
|
||||||
PATHSPEC_PREFER_CWD,
|
PATHSPEC_PREFER_CWD,
|
||||||
prefix, pathspec);
|
prefix, pathspec);
|
||||||
return ps._raw;
|
return ps._raw;
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
/* Pathspec magic */
|
/* Pathspec magic */
|
||||||
#define PATHSPEC_FROMTOP (1<<0)
|
#define PATHSPEC_FROMTOP (1<<0)
|
||||||
#define PATHSPEC_MAXDEPTH (1<<1)
|
#define PATHSPEC_MAXDEPTH (1<<1)
|
||||||
|
#define PATHSPEC_LITERAL (1<<2)
|
||||||
#define PATHSPEC_ALL_MAGIC \
|
#define PATHSPEC_ALL_MAGIC \
|
||||||
(PATHSPEC_FROMTOP | \
|
(PATHSPEC_FROMTOP | \
|
||||||
PATHSPEC_MAXDEPTH)
|
PATHSPEC_MAXDEPTH | \
|
||||||
|
PATHSPEC_LITERAL)
|
||||||
|
|
||||||
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
|
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
|
||||||
|
|
||||||
|
@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' '
|
|||||||
test_cmp expect actual
|
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)' '
|
test_expect_success 'no-glob option matches literally (star)' '
|
||||||
echo star >expect &&
|
echo star >expect &&
|
||||||
git --literal-pathspecs log --format=%s -- "f*" >actual &&
|
git --literal-pathspecs log --format=%s -- "f*" >actual &&
|
||||||
test_cmp expect 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)' '
|
test_expect_success 'no-glob option matches literally (bracket)' '
|
||||||
echo bracket >expect &&
|
echo bracket >expect &&
|
||||||
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
|
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
|
||||||
test_cmp expect 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' '
|
test_expect_success 'no-glob environment variable works' '
|
||||||
echo star >expect &&
|
echo star >expect &&
|
||||||
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
|
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
|
||||||
|
@ -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
|
* path. Magic that matches more than one path is not
|
||||||
* supported.
|
* supported.
|
||||||
*/
|
*/
|
||||||
GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);
|
GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
|
||||||
#if 0
|
#if 0
|
||||||
/*
|
/*
|
||||||
* We should reject wildcards as well. Unfortunately we
|
* We should reject wildcards as well. Unfortunately we
|
||||||
|
@ -636,7 +636,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
|
|||||||
enum interesting never_interesting = ps->has_wildcard ?
|
enum interesting never_interesting = ps->has_wildcard ?
|
||||||
entry_not_interesting : all_entries_not_interesting;
|
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->nr) {
|
||||||
if (!ps->recursive ||
|
if (!ps->recursive ||
|
||||||
|
Reference in New Issue
Block a user