From: Junio C Hamano Date: Thu, 15 Oct 2015 22:43:39 +0000 (-0700) Subject: Merge branch 'js/icase-wt-detection' X-Git-Tag: v2.7.0-rc0~108 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/6652939ce8cacb147bce2f0c3503486915ca5a73?ds=inline;hp=-c Merge branch 'js/icase-wt-detection' On a case insensitive filesystems, setting GIT_WORK_TREE variable using a random cases that does not agree with what the filesystem thinks confused Git that it wasn't inside the working tree. * js/icase-wt-detection: setup: fix "inside work tree" detection on case-insensitive filesystems --- 6652939ce8cacb147bce2f0c3503486915ca5a73 diff --combined dir.c index b90484acf8,22402c730e..fba938b701 --- a/dir.c +++ b/dir.c @@@ -882,25 -882,6 +882,25 @@@ int match_pathname(const char *pathname */ if (!patternlen && !namelen) return 1; + /* + * This can happen when we ignore some exclude rules + * on directories in other to see if negative rules + * may match. E.g. + * + * /abc + * !/abc/def/ghi + * + * The pattern of interest is "/abc". On the first + * try, we should match path "abc" with this pattern + * in the "if" statement right above, but the caller + * ignores it. + * + * On the second try with paths within "abc", + * e.g. "abc/xyz", we come here and try to match it + * with "/abc". + */ + if (!patternlen && namelen && *name == '/') + return 1; } return fnmatch_icase_mem(pattern, patternlen, @@@ -908,48 -889,6 +908,48 @@@ WM_PATHNAME) == 0; } +/* + * Return non-zero if pathname is a directory and an ancestor of the + * literal path in a (negative) pattern. This is used to keep + * descending in "foo" and "foo/bar" when the pattern is + * "!foo/bar/.gitignore". "foo/notbar" will not be descended however. + */ +static int match_neg_path(const char *pathname, int pathlen, int *dtype, + const char *base, int baselen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR)); + + if (*dtype == DT_UNKNOWN) + *dtype = get_dtype(NULL, pathname, pathlen); + if (*dtype != DT_DIR) + return 0; + + if (*pattern == '/') { + pattern++; + patternlen--; + prefix--; + } + + if (baselen) { + if (((pathlen < baselen && base[pathlen] == '/') || + pathlen == baselen) && + !strncmp_icase(pathname, base, pathlen)) + return 1; + pathname += baselen + 1; + pathlen -= baselen + 1; + } + + + if (prefix && + ((pathlen < prefix && pattern[pathlen] == '/') && + !strncmp_icase(pathname, pattern, pathlen))) + return 1; + + return 0; +} + /* * Scan the given exclude list in reverse to see whether pathname * should be ignored. The first match (i.e. the last on the list), if @@@ -962,8 -901,7 +962,8 @@@ static struct exclude *last_exclude_mat int *dtype, struct exclude_list *el) { - int i; + struct exclude *exc = NULL; /* undecided */ + int i, matched_negative_path = 0; if (!el->nr) return NULL; /* undefined */ @@@ -984,33 -922,18 +984,33 @@@ if (match_basename(basename, pathlen - (basename - pathname), exclude, prefix, x->patternlen, - x->flags)) - return x; + x->flags)) { + exc = x; + break; + } continue; } assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); if (match_pathname(pathname, pathlen, x->base, x->baselen ? x->baselen - 1 : 0, + exclude, prefix, x->patternlen, x->flags)) { + exc = x; + break; + } + + if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path && + match_neg_path(pathname, pathlen, dtype, x->base, + x->baselen ? x->baselen - 1 : 0, exclude, prefix, x->patternlen, x->flags)) - return x; + matched_negative_path = 1; } - return NULL; /* undecided */ + if (exc && + !(exc->flags & EXC_FLAG_NEGATIVE) && + !(exc->flags & EXC_FLAG_NODIR) && + matched_negative_path) + exc = NULL; + return exc; } /* @@@ -2107,6 -2030,15 +2107,15 @@@ int file_exists(const char *f return lstat(f, &sb) == 0; } + static int cmp_icase(char a, char b) + { + if (a == b) + return 0; + if (ignore_case) + return toupper(a) - toupper(b); + return a - b; + } + /* * Given two normalized paths (a trailing slash is ok), if subdir is * outside dir, return -1. Otherwise return the offset in subdir that @@@ -2118,7 -2050,7 +2127,7 @@@ int dir_inside_of(const char *subdir, c assert(dir && subdir && *dir && *subdir); - while (*dir && *subdir && *dir == *subdir) { + while (*dir && *subdir && !cmp_icase(*dir, *subdir)) { dir++; subdir++; offset++; @@@ -2253,8 -2185,6 +2262,8 @@@ int remove_dir_recursively(struct strbu return remove_dir_recurse(path, flag, NULL); } +static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude") + void setup_standard_excludes(struct dir_struct *dir) { const char *path; @@@ -2269,7 -2199,7 +2278,7 @@@ dir->untracked ? &dir->ss_excludes_file : NULL); /* per repository user preference */ - path = git_path("info/exclude"); + path = git_path_info_exclude(); if (!access_or_warn(path, R_OK, 0)) add_excludes_from_file_1(dir, path, dir->untracked ? &dir->ss_info_exclude : NULL);