Merge branch 'jk/pathspec-literal'
Allow scripts to feed literal paths to commands that take pathspecs, by disabling wildcard globbing. * jk/pathspec-literal: add global --literal-pathspecs option Conflicts: dir.c
This commit is contained in:
commit
971e829cd8
@ -428,6 +428,11 @@ help ...`.
|
||||
Do not use replacement refs to replace git objects. See
|
||||
linkgit:git-replace[1] for more information.
|
||||
|
||||
--literal-pathspecs::
|
||||
Treat pathspecs literally, rather than as glob patterns. This is
|
||||
equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
|
||||
variable to `1`.
|
||||
|
||||
|
||||
GIT COMMANDS
|
||||
------------
|
||||
@ -796,6 +801,16 @@ for further details.
|
||||
as a file path and will try to write the trace messages
|
||||
into it.
|
||||
|
||||
GIT_LITERAL_PATHSPECS::
|
||||
Setting this variable to `1` will cause git to treat all
|
||||
pathspecs literally, rather than as glob patterns. For example,
|
||||
running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search
|
||||
for commits that touch the path `*.c`, not any paths that the
|
||||
glob `*.c` matches. You might want this if you are feeding
|
||||
literal paths to git (e.g., paths previously given to you by
|
||||
`git ls-tree`, `--raw` diff output, etc).
|
||||
|
||||
|
||||
Discussion[[Discussion]]
|
||||
------------------------
|
||||
|
||||
|
3
cache.h
3
cache.h
@ -362,6 +362,7 @@ static inline enum object_type object_type(unsigned int mode)
|
||||
#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
|
||||
#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
|
||||
#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
|
||||
#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
|
||||
|
||||
/*
|
||||
* Repository-local GIT_* environment variables
|
||||
@ -493,6 +494,8 @@ extern int init_pathspec(struct pathspec *, const char **);
|
||||
extern void free_pathspec(struct pathspec *);
|
||||
extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
|
||||
|
||||
extern int limit_pathspec_to_literal(void);
|
||||
|
||||
#define HASH_WRITE_OBJECT 1
|
||||
#define HASH_FORMAT_CHECK 2
|
||||
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
|
||||
|
38
dir.c
38
dir.c
@ -60,6 +60,7 @@ static size_t common_prefix_len(const char **pathspec)
|
||||
{
|
||||
const char *n, *first;
|
||||
size_t max = 0;
|
||||
int literal = limit_pathspec_to_literal();
|
||||
|
||||
if (!pathspec)
|
||||
return max;
|
||||
@ -69,7 +70,7 @@ static size_t common_prefix_len(const char **pathspec)
|
||||
size_t i, len = 0;
|
||||
for (i = 0; first == n || i < max; i++) {
|
||||
char c = n[i];
|
||||
if (!c || c != first[i] || is_glob_special(c))
|
||||
if (!c || c != first[i] || (!literal && is_glob_special(c)))
|
||||
break;
|
||||
if (c == '/')
|
||||
len = i + 1;
|
||||
@ -139,6 +140,7 @@ int within_depth(const char *name, int namelen,
|
||||
static int match_one(const char *match, const char *name, int namelen)
|
||||
{
|
||||
int matchlen;
|
||||
int literal = limit_pathspec_to_literal();
|
||||
|
||||
/* If the match was just the prefix, we matched */
|
||||
if (!*match)
|
||||
@ -148,7 +150,7 @@ static int match_one(const char *match, const char *name, int namelen)
|
||||
for (;;) {
|
||||
unsigned char c1 = tolower(*match);
|
||||
unsigned char c2 = tolower(*name);
|
||||
if (c1 == '\0' || is_glob_special(c1))
|
||||
if (c1 == '\0' || (!literal && is_glob_special(c1)))
|
||||
break;
|
||||
if (c1 != c2)
|
||||
return 0;
|
||||
@ -160,7 +162,7 @@ static int match_one(const char *match, const char *name, int namelen)
|
||||
for (;;) {
|
||||
unsigned char c1 = *match;
|
||||
unsigned char c2 = *name;
|
||||
if (c1 == '\0' || is_glob_special(c1))
|
||||
if (c1 == '\0' || (!literal && is_glob_special(c1)))
|
||||
break;
|
||||
if (c1 != c2)
|
||||
return 0;
|
||||
@ -170,14 +172,16 @@ static int match_one(const char *match, const char *name, int namelen)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we don't match the matchstring exactly,
|
||||
* we need to match by fnmatch
|
||||
*/
|
||||
matchlen = strlen(match);
|
||||
if (strncmp_icase(match, name, matchlen))
|
||||
if (strncmp_icase(match, name, matchlen)) {
|
||||
if (literal)
|
||||
return 0;
|
||||
return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;
|
||||
}
|
||||
|
||||
if (namelen == matchlen)
|
||||
return MATCHED_EXACTLY;
|
||||
@ -1454,13 +1458,17 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)
|
||||
|
||||
item->match = path;
|
||||
item->len = strlen(path);
|
||||
item->nowildcard_len = simple_length(path);
|
||||
item->flags = 0;
|
||||
if (item->nowildcard_len < item->len) {
|
||||
pathspec->has_wildcard = 1;
|
||||
if (path[item->nowildcard_len] == '*' &&
|
||||
no_wildcard(path + item->nowildcard_len + 1))
|
||||
item->flags |= PATHSPEC_ONESTAR;
|
||||
if (limit_pathspec_to_literal()) {
|
||||
item->nowildcard_len = item->len;
|
||||
} else {
|
||||
item->nowildcard_len = simple_length(path);
|
||||
if (item->nowildcard_len < item->len) {
|
||||
pathspec->has_wildcard = 1;
|
||||
if (path[item->nowildcard_len] == '*' &&
|
||||
no_wildcard(path + item->nowildcard_len + 1))
|
||||
item->flags |= PATHSPEC_ONESTAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1475,3 +1483,11 @@ void free_pathspec(struct pathspec *pathspec)
|
||||
free(pathspec->items);
|
||||
pathspec->items = NULL;
|
||||
}
|
||||
|
||||
int limit_pathspec_to_literal(void)
|
||||
{
|
||||
static int flag = -1;
|
||||
if (flag < 0)
|
||||
flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
||||
return flag;
|
||||
}
|
||||
|
8
git.c
8
git.c
@ -135,6 +135,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
|
||||
git_config_push_parameter((*argv)[1]);
|
||||
(*argv)++;
|
||||
(*argc)--;
|
||||
} else if (!strcmp(cmd, "--literal-pathspecs")) {
|
||||
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "1", 1);
|
||||
if (envchanged)
|
||||
*envchanged = 1;
|
||||
} else if (!strcmp(cmd, "--no-literal-pathspecs")) {
|
||||
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
|
||||
if (envchanged)
|
||||
*envchanged = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option: %s\n", cmd);
|
||||
usage(git_usage_string);
|
||||
|
62
t/t6130-pathspec-noglob.sh
Executable file
62
t/t6130-pathspec-noglob.sh
Executable file
@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test globbing (and noglob) of pathspec limiting'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'create commits with glob characters' '
|
||||
test_commit unrelated bar &&
|
||||
test_commit vanilla foo &&
|
||||
test_commit star "f*" &&
|
||||
test_commit bracket "f[o][o]"
|
||||
'
|
||||
|
||||
test_expect_success 'vanilla pathspec matches literally' '
|
||||
echo vanilla >expect &&
|
||||
git log --format=%s -- foo >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'star pathspec globs' '
|
||||
cat >expect <<-\EOF &&
|
||||
bracket
|
||||
star
|
||||
vanilla
|
||||
EOF
|
||||
git log --format=%s -- "f*" >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'bracket pathspec globs and matches literal brackets' '
|
||||
cat >expect <<-\EOF &&
|
||||
bracket
|
||||
vanilla
|
||||
EOF
|
||||
git log --format=%s -- "f[o][o]" >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'no-glob option matches literally (vanilla)' '
|
||||
echo vanilla >expect &&
|
||||
git --literal-pathspecs log --format=%s -- 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 (bracket)' '
|
||||
echo bracket >expect &&
|
||||
git --literal-pathspecs log --format=%s -- "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 &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user