X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-add.c;h=7083820f7b2745708e40f624935a0ad231351e24;hb=c7e3a75121877ecc8ea60c2d3873a1c6c504ed68;hp=d225988e53ce8e6fab177b7679a807bb57b4d13a;hpb=0d78153952e70c21e94dc6b7eefcb2ac5337a902;p=git.git diff --git a/builtin-add.c b/builtin-add.c index d225988e5..7083820f7 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -8,6 +8,7 @@ #include "cache.h" #include "builtin.h" #include "dir.h" +#include "cache-tree.h" static const char builtin_add_usage[] = "git-add [-n] [-v] ..."; @@ -44,50 +45,89 @@ static int common_prefix(const char **pathspec) return prefix; } -static int match(const char **pathspec, const char *name, int namelen, int prefix) +static int match_one(const char *match, const char *name, int namelen) { + int matchlen; + + /* If the match was just the prefix, we matched */ + matchlen = strlen(match); + if (!matchlen) + return 1; + + /* + * If we don't match the matchstring exactly, + * we need to match by fnmatch + */ + if (strncmp(match, name, matchlen)) + return !fnmatch(match, name, 0); + + /* + * If we did match the string exactly, we still + * need to make sure that it happened on a path + * component boundary (ie either the last character + * of the match was '/', or the next character of + * the name was '/' or the terminating NUL. + */ + return match[matchlen-1] == '/' || + name[matchlen] == '/' || + !name[matchlen]; +} + +static int match(const char **pathspec, const char *name, int namelen, int prefix, char *seen) +{ + int retval; const char *match; name += prefix; namelen -= prefix; - while ((match = *pathspec++) != NULL) { - int matchlen; - + for (retval = 0; (match = *pathspec++) != NULL; seen++) { + if (retval & *seen) + continue; match += prefix; - matchlen = strlen(match); - if (!matchlen) - return 1; - if (!strncmp(match, name, matchlen)) { - if (match[matchlen-1] == '/') - return 1; - switch (name[matchlen]) { - case '/': case '\0': - return 1; - } + if (match_one(match, name, namelen)) { + retval = 1; + *seen = 1; } - if (!fnmatch(match, name, 0)) - return 1; } - return 0; + return retval; } static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) { - int i; + char *seen; + int i, specs; struct dir_entry **src, **dst; + for (specs = 0; pathspec[specs]; specs++) + /* nothing */; + seen = xmalloc(specs); + memset(seen, 0, specs); + src = dst = dir->entries; i = dir->nr; while (--i >= 0) { struct dir_entry *entry = *src++; - if (!match(pathspec, entry->name, entry->len, prefix)) { + if (!match(pathspec, entry->name, entry->len, prefix, seen)) { free(entry); continue; } *dst++ = entry; } dir->nr = dst - dir->entries; + + for (i = 0; i < specs; i++) { + struct stat st; + const char *match; + if (seen[i]) + continue; + + /* Existing file? We must have ignored it */ + match = pathspec[i]; + if (!lstat(match, &st)) + continue; + die("pathspec '%s' did not match any files", match); + } } static void fill_directory(struct dir_struct *dir, const char **pathspec) @@ -158,6 +198,7 @@ static int add_file_to_index(const char *path, int verbose) die("unable to add %s to index",path); if (verbose) printf("add '%s'\n", path); + cache_tree_invalidate_path(active_cache_tree, path); return 0; }