diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2012-11-24 11:33:50 +0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2012-11-26 11:13:13 -0800 |
commit | 8c6abbcd2720dd80b1c9b6db8104c4dcc7cba6c7 (patch) | |
tree | 9ee9ada92c4cb6bf3f8e5874d20664cf46a3e0b4 /dir.c | |
parent | 5d74762d87859d08fdf4c87ec9387e31e097acba (diff) | |
download | git-8c6abbcd2720dd80b1c9b6db8104c4dcc7cba6c7.tar.gz |
pathspec: apply "*.c" optimization from exclude
When a pattern contains only a single asterisk as wildcard,
e.g. "foo*bar", after literally comparing the leading part "foo" with
the string, we can compare the tail of the string and make sure it
matches "bar", instead of running fnmatch() on "*bar" against the
remainder of the string.
-O2 build on linux-2.6, without the patch:
$ time git rev-list --quiet HEAD -- '*.c'
real 0m40.770s
user 0m40.290s
sys 0m0.256s
With the patch
$ time ~/w/git/git rev-list --quiet HEAD -- '*.c'
real 0m34.288s
user 0m33.997s
sys 0m0.205s
The above command is not supposed to be widely popular. It's chosen
because it exercises pathspec matching a lot. The point is it cuts
down matching time for popular patterns like *.c, which could be used
as pathspec in other places.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 18 |
1 files changed, 16 insertions, 2 deletions
@@ -46,6 +46,13 @@ inline int git_fnmatch(const char *pattern, const char *string, 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); } @@ -246,7 +253,9 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix, } if (item->nowildcard_len < item->len && - !git_fnmatch(match, name, 0, item->nowildcard_len - prefix)) + !git_fnmatch(match, name, + item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0, + item->nowildcard_len - prefix)) return MATCHED_FNMATCH; return 0; @@ -1446,8 +1455,13 @@ int init_pathspec(struct pathspec *pathspec, const char **paths) item->match = path; item->len = strlen(path); item->nowildcard_len = simple_length(path); - if (item->nowildcard_len < item->len) + 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; + } } qsort(pathspec->items, pathspec->nr, |