This patch allows core.ignorecase=true to work properly with gitignore exclusions.
This is especially beneficial when using Windows and Perforce and the git-p4 bridge. Perforce preserves a given file's full path including case. When syncing a file down, directories are created, if necessary, using the case as stored with the filename. Unfortunately, two files in the same directory can have differing cases for their respective paths, such as /dirA/file1.c and /DirA/file2.c. Depending on sync order, DirA/ may get created instead of dirA/.
Trying to catch all case combinations for a set of gitignore entries is very difficult. Having the exclusions honor the core.ignorecase=true makes the process less error prone. --- dir.c | 49 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 36 insertions(+), 13 deletions(-)
Show changes to dir.c +36 −14
diff --git a/dir.c b/dir.c index 0e6b752..c63e0a0 100644 --- a/dir.c +++ b/dir.c @@ -315,14 +315,25 @@ static int excluded_1(const char *pathname, if (x->flags & EXC_FLAG_NODIR) { /* match basename */ if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp(exclude, basename)) - return to_exclude; + if (ignore_case) { + if (!strcasecmp(exclude, basename)) + return to_exclude; + } else { + if (!strcmp(exclude, basename)) + return to_exclude; + } } else if (x->flags & EXC_FLAG_ENDSWITH) { - if (x->patternlen - 1 <= pathlen && - !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1)) - return to_exclude; + if (ignore_case) { + if (x->patternlen - 1 <= pathlen && + !strcasecmp(exclude + 1, pathname + pathlen - x->patternlen + 1)) + return to_exclude; + } else { + if (x->patternlen - 1 <= pathlen && + !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1)) + return to_exclude; + } } else { - if (fnmatch(exclude, basename, 0) == 0) + if (fnmatch(exclude, basename, ignore_case ? FNM_CASEFOLD : 0) == 0) return to_exclude; } } @@ -335,17 +346,29 @@ static int excluded_1(const char *pathname, if (*exclude == '/') exclude++; - if (pathlen < baselen || - (baselen && pathname[baselen-1] != '/') || - strncmp(pathname, x->base, baselen)) - continue; + if (ignore_case) { + if (pathlen < baselen || + (baselen && pathname[baselen-1] != '/') || + strncasecmp(pathname, x->base, baselen)) + continue; + } else { + if (pathlen < baselen || + (baselen && pathname[baselen-1] != '/') || + strncmp(pathname, x->base, baselen)) + continue; + } if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp(exclude, pathname + baselen)) - return to_exclude; + if (ignore_case) { + if (!strcasecmp(exclude, pathname + baselen)) + return to_exclude; + } else { + if (!strcmp(exclude, pathname + baselen)) + return to_exclude; + } } else { if (fnmatch(exclude, pathname+baselen, - FNM_PATHNAME) == 0) + FNM_PATHNAME | (ignore_case ? FNM_CASEFOLD : 0)) == 0) return to_exclude; } }
-- 1.6.3.2.1299.gee46c.dirty