From: Junio C Hamano Date: Sun, 6 Jan 2013 07:42:07 +0000 (-0800) Subject: Merge branch 'jk/pathspec-literal' X-Git-Tag: v1.8.2-rc0~178 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/971e829cd84cf95203cec44d22d0e009f98ddbf5?hp=-c 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 --- 971e829cd84cf95203cec44d22d0e009f98ddbf5 diff --combined Documentation/git.txt index 7a3f03b5ce,8d869db682..05c0b942be --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -43,15 -43,9 +43,15 @@@ unreleased) version of git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.8.0.2/git.html[documentation for release 1.8.0.2] +* link:v1.8.1/git.html[documentation for release 1.8.1] * release notes for + link:RelNotes/1.8.1.txt[1.8.1]. + +* link:v1.8.0.3/git.html[documentation for release 1.8.0.3] + +* release notes for + link:RelNotes/1.8.0.3.txt[1.8.0.3], link:RelNotes/1.8.0.2.txt[1.8.0.2], link:RelNotes/1.8.0.1.txt[1.8.0.1], link:RelNotes/1.8.0.txt[1.8.0]. @@@ -428,6 -422,11 +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 -795,16 +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]] ------------------------ diff --combined cache.h index e1df1e40dd,95608d9dc5..c257953fa7 --- a/cache.h +++ b/cache.h @@@ -362,6 -362,7 +362,7 @@@ static inline enum object_type object_t #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 @@@ -473,8 -474,6 +474,8 @@@ extern int index_name_is_other(const st extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); +#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */ + struct pathspec { const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ int nr; @@@ -484,8 -483,7 +485,8 @@@ struct pathspec_item { const char *match; int len; - unsigned int use_wildcard:1; + int nowildcard_len; + int flags; } *items; }; @@@ -493,6 -491,8 +494,8 @@@ extern int init_pathspec(struct pathspe 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); @@@ -717,11 -717,10 +720,11 @@@ static inline int is_absolute_path(cons } int is_directory(const char *); const char *real_path(const char *path); +const char *real_path_if_valid(const char *path); const char *absolute_path(const char *path); const char *relative_path(const char *abs, const char *base); int normalize_path_copy(char *dst, const char *src); -int longest_ancestor_length(const char *path, const char *prefix_list); +int longest_ancestor_length(const char *path, struct string_list *prefixes); char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); int offset_1st_component(const char *path); @@@ -1003,19 -1002,14 +1006,19 @@@ struct ref unsigned char old_sha1[20]; unsigned char new_sha1[20]; char *symref; - unsigned int force:1, + unsigned int + force:1, + requires_force:1, merge:1, nonfastforward:1, + not_forwardable:1, + update:1, deletion:1; enum { REF_STATUS_NONE = 0, REF_STATUS_OK, REF_STATUS_REJECT_NONFASTFORWARD, + REF_STATUS_REJECT_ALREADY_EXISTS, REF_STATUS_REJECT_NODELETE, REF_STATUS_UPTODATE, REF_STATUS_REMOTE_REJECT, @@@ -1145,9 -1139,6 +1148,9 @@@ extern int check_repository_format_vers extern int git_env_bool(const char *, int); extern int git_config_system(void); extern int config_error_nonbool(const char *); +#ifdef __GNUC__ +#define config_error_nonbool(s) (config_error_nonbool(s), -1) +#endif extern const char *get_log_output_encoding(void); extern const char *get_commit_output_encoding(void); @@@ -1167,7 -1158,6 +1170,7 @@@ extern int author_ident_sufficiently_gi extern const char *git_commit_encoding; extern const char *git_log_output_encoding; extern const char *git_mailmap_file; +extern const char *git_mailmap_blob; /* IO helper functions */ extern void maybe_flush_or_die(FILE *, const char *); diff --combined dir.c index 9afd388604,03ff36bc6e..095ea7ebab --- a/dir.c +++ b/dir.c @@@ -34,32 -34,11 +34,33 @@@ int fnmatch_icase(const char *pattern, return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0)); } +inline int git_fnmatch(const char *pattern, const char *string, + int flags, int prefix) +{ + int fnm_flags = 0; + if (flags & GFNM_PATHNAME) + fnm_flags |= FNM_PATHNAME; + if (prefix > 0) { + if (strncmp(pattern, string, prefix)) + return FNM_NOMATCH; + pattern += prefix; + string += prefix; + } + if (flags & GFNM_ONESTAR) { + int pattern_len = strlen(++pattern); + int string_len = strlen(string); + return string_len < pattern_len || + strcmp(pattern, + string + string_len - pattern_len); + } + return fnmatch(pattern, string, fnm_flags); +} + 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 -48,7 +70,7 @@@ 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 -118,7 +140,7 @@@ int within_depth(const char *name, int 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 -128,7 +150,7 @@@ 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 -140,7 +162,7 @@@ 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 -150,16 +172,16 @@@ } } - /* * 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; @@@ -252,10 -234,7 +256,10 @@@ static int match_pathspec_item(const st return MATCHED_RECURSIVELY; } - if (item->use_wildcard && !fnmatch(match, name, 0)) + if (item->nowildcard_len < item->len && + !git_fnmatch(match, name, + item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0, + item->nowildcard_len - prefix)) return MATCHED_FNMATCH; return 0; @@@ -1454,14 -1433,10 +1458,18 @@@ int init_pathspec(struct pathspec *path item->match = path; item->len = strlen(path); - item->nowildcard_len = simple_length(path); - item->use_wildcard = !limit_pathspec_to_literal() && - !no_wildcard(path); - if (item->use_wildcard) - pathspec->has_wildcard = 1; + 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; ++ } + } } qsort(pathspec->items, pathspec->nr, @@@ -1475,3 -1450,11 +1483,11 @@@ void free_pathspec(struct pathspec *pat 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; + }