{"thread":{"id":"25315","subject":"[PATCH v2 0/6] Extensions of core.ignorecase=true support","startedAt":"2010-10-03T04:32:21Z","lastAt":"2010-10-07T05:48:04Z","messageCount":45,"participants":["Joshua Jensen","Johannes Sixt","Ævar Arnfjörð Bjarmason","Robert Buck","Thomas Adam","Sverre Rabbelier","Junio C Hamano","Jonathan Nieder","Erik Faye-Lund","Robin Rosenberg"],"isPatch":true,"patchVersion":2,"patchTotal":6},"messages":[{"id":"152302","messageId":"20101003043221.1960.73178.stgit@SlamDunk","threadId":"25315","inReplyTo":null,"subject":"[PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:21Z","receivedAt":"2010-10-03T04:32:21Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"The second version of this patch series fixes the problematic case\ninsensitive fnmatch call in patch 1 that relied on an apparently GNU-only\nextension.  Instead, the pattern and string are lowercased into\ntemporary buffers, and the standard fnmatch is called without relying\non the GNU extension.\n\nPatches 2-6 received no modifications.\n\nThe original cover for the patch series follows as posted by Johannes Sixt:\n\nThe following patch series extends the core.ignorecase=true support to\nhandle case insensitive comparisons for the .gitignore file, git status,\nand git ls-files.  git add and git fast-import will fold the case of the\nfile being added, matching that of an already added directory entry.  Case\nfolding is also applied to git fast-import for renames, copies, and deletes.\n\nThe most notable benefit, IMO, is that the case of directories in the\nworktree does not matter if, and only if, the directory exists already in\nthe index with some different case variant.  This helps applications on\nWindows that change the case even of directories in unpredictable ways.\nJoshua mentioned Perforce as the primary example.\n\nConcerning the implementation, Joshua explained when he initially submitted\nthe series to the msysgit mailing list:\n\n git status and add both use an update made to name-hash.c where\n directories, specifically names with a trailing slash, can be looked up\n in a case insensitive manner. After trying a myriad of solutions, this\n seemed to be the cleanest. Does anyone see a problem with embedding the\n directory names in the same hash as the file names? I couldn't find one,\n especially since I append a slash to each directory name.\n\n The git add path case folding functionality is a somewhat radical\n departure from what Git does now. It is described in detail in patch 5.\n Does anyone have any concerns?\n\nI support the idea of this patch, and I can confirm that it works: I've\nused this series in production both with core.ignorecase set to true and\nto false, and in the former case, with directories and files with case\ndifferent from the index.\n\nJoshua Jensen (6):\n      Add string comparison functions that respect the ignore_case variable.\n      Case insensitivity support for .gitignore via core.ignorecase\n      Add case insensitivity support for directories when using git status\n      Add case insensitivity support when using git ls-files\n      Support case folding for git add when core.ignorecase=true\n      Support case folding in git fast-import when core.ignorecase=true\n\n\n dir.c         |  152 ++++++++++++++++++++++++++++++++++++++++++++++++++-------\n dir.h         |    4 ++\n fast-import.c |    7 ++-\n name-hash.c   |   72 +++++++++++++++++++++++++++\n read-cache.c  |   23 +++++++++\n 5 files changed, 235 insertions(+), 23 deletions(-)\n"},{"id":"152305","messageId":"20101003043228.1960.88989.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 1/6] Add string comparison functions that respect the ignore_case variable.","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:28Z","receivedAt":"2010-10-03T04:32:28Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"Multiple locations within this patch series alter a case sensitive\nstring comparison call such as strcmp() to be a call to a string\ncomparison call that selects case comparison based on the global\nignore_case variable. Behaviorally, when core.ignorecase=false, the\n*_icase() versions are functionally equivalent to their C runtime\ncounterparts.  When core.ignorecase=true, the *_icase() versions perform\na case insensitive comparison.\n\nLike Linus' earlier ignorecase patch, these may ignore filename\nconventions on certain file systems. By isolating filename comparisons\nto certain functions, support for those filename conventions may be more\neasily met.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n dir.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n dir.h |    4 ++++\n 2 files changed, 66 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex d1e5e5e..ffa410d 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -18,6 +18,68 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, in\n \tint check_only, const struct path_simplify *simplify);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n+/* helper string functions with support for the ignore_case flag */\n+int strcmp_icase(const char *a, const char *b)\n+{\n+\treturn ignore_case ? strcasecmp(a, b) : strcmp(a, b);\n+}\n+\n+int strncmp_icase(const char *a, const char *b, size_t count)\n+{\n+\treturn ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);\n+}\n+\n+int fnmatch_casefold(const char *pattern, const char *string, int flags)\n+{\n+\tchar lowerPatternBuf[MAX_PATH];\n+\tchar lowerStringBuf[MAX_PATH];\n+\tchar* lowerPattern;\n+\tchar* lowerString;\n+\tsize_t patternLen;\n+\tsize_t stringLen;\n+\tchar* out;\n+\tint ret;\n+\n+\t/*\n+\t * Use the provided stack buffer, if possible.  If the string is too\n+\t * large, allocate buffer space.\n+\t */\n+\tpatternLen = strlen(pattern);\n+\tif (patternLen + 1 > sizeof(lowerPatternBuf))\n+\t\tlowerPattern = xmalloc(patternLen + 1);\n+\telse\n+\t\tlowerPattern = lowerPatternBuf;\n+\n+\tstringLen = strlen(string);\n+\tif (stringLen + 1 > sizeof(lowerStringBuf))\n+\t\tlowerString = xmalloc(stringLen + 1);\n+\telse\n+\t\tlowerString = lowerStringBuf;\n+\n+\t/* Make the pattern and string lowercase to pass to fnmatch. */\n+\tfor (out = lowerPattern; *pattern; ++out, ++pattern)\n+\t\t*out = tolower(*pattern);\n+\t*out = 0;\n+\n+\tfor (out = lowerString; *string; ++out, ++string)\n+\t\t*out = tolower(*string);\n+\t*out = 0;\n+\n+\tret = fnmatch(lowerPattern, lowerString, flags);\n+\n+\t/* Free the pattern or string if it was allocated. */\n+\tif (lowerPattern != lowerPatternBuf)\n+\t\tfree(lowerPattern);\n+\tif (lowerString != lowerStringBuf)\n+\t\tfree(lowerString);\n+\treturn ret;\n+}\n+\n+int fnmatch_icase(const char *pattern, const char *string, int flags)\n+{\n+\treturn ignore_case ? fnmatch_casefold(pattern, string, flags) : fnmatch(pattern, string, flags);\n+}\n+\n static int common_prefix(const char **pathspec)\n {\n \tconst char *path, *slash, *next;\ndiff --git a/dir.h b/dir.h\nindex 278d84c..b3e2104 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -101,4 +101,8 @@ extern int remove_dir_recursively(struct strbuf *path, int flag);\n /* tries to remove the path with empty directories along it, ignores ENOENT */\n extern int remove_path(const char *path);\n \n+extern int strcmp_icase(const char *a, const char *b);\n+extern int strncmp_icase(const char *a, const char *b, size_t count);\n+extern int fnmatch_icase(const char *pattern, const char *string, int flags);\n+\n #endif\n"},{"id":"152303","messageId":"20101003043234.1960.12596.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 2/6] Case insensitivity support for .gitignore via core.ignorecase","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:34Z","receivedAt":"2010-10-03T04:32:34Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"This is especially beneficial when using Windows and Perforce and the\ngit-p4 bridge. Internally, Perforce preserves a given file's full path\nincluding its case at the time it was added to the Perforce repository.\nWhen syncing a file down via Perforce, missing directories are created,\nif necessary, using the case as stored with the filename. Unfortunately,\ntwo files in the same directory can have differing cases for their\nrespective paths, such as /diRa/file1.c and /DirA/file2.c. Depending on\nsync order, DirA/ may get created instead of diRa/.\n\nIt is possible to handle directory names in a case insensitive manner\nwithout this patch, but it is highly inconvenient, requiring each\ncharacter to be specified like so: [Bb][Uu][Ii][Ll][Dd]. With this patch, the\ngitignore exclusions honor the core.ignorecase=true configuration\nsetting and make the process less error prone. The above is specified\nlike so: Build\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n dir.c |   12 ++++++------\n 1 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex ffa410d..63d7b41 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -436,14 +436,14 @@ int excluded_from_list(const char *pathname,\n \t\t\tif (x->flags & EXC_FLAG_NODIR) {\n \t\t\t\t/* match basename */\n \t\t\t\tif (x->flags & EXC_FLAG_NOWILDCARD) {\n-\t\t\t\t\tif (!strcmp(exclude, basename))\n+\t\t\t\t\tif (!strcmp_icase(exclude, basename))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else if (x->flags & EXC_FLAG_ENDSWITH) {\n \t\t\t\t\tif (x->patternlen - 1 <= pathlen &&\n-\t\t\t\t\t    !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))\n+\t\t\t\t\t    !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else {\n-\t\t\t\t\tif (fnmatch(exclude, basename, 0) == 0)\n+\t\t\t\t\tif (fnmatch_icase(exclude, basename, 0) == 0)\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t}\n \t\t\t}\n@@ -458,14 +458,14 @@ int excluded_from_list(const char *pathname,\n \n \t\t\t\tif (pathlen < baselen ||\n \t\t\t\t    (baselen && pathname[baselen-1] != '/') ||\n-\t\t\t\t    strncmp(pathname, x->base, baselen))\n+\t\t\t\t    strncmp_icase(pathname, x->base, baselen))\n \t\t\t\t    continue;\n \n \t\t\t\tif (x->flags & EXC_FLAG_NOWILDCARD) {\n-\t\t\t\t\tif (!strcmp(exclude, pathname + baselen))\n+\t\t\t\t\tif (!strcmp_icase(exclude, pathname + baselen))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else {\n-\t\t\t\t\tif (fnmatch(exclude, pathname+baselen,\n+\t\t\t\t\tif (fnmatch_icase(exclude, pathname+baselen,\n \t\t\t\t\t\t    FNM_PATHNAME) == 0)\n \t\t\t\t\t    return to_exclude;\n \t\t\t\t}\n"},{"id":"152306","messageId":"20101003043239.1960.60657.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 3/6] Add case insensitivity support for directories when using git status","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:39Z","receivedAt":"2010-10-03T04:32:39Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"When using a case preserving but case insensitive file system, directory\ncase can differ but still refer to the same physical directory.  git\nstatus reports the directory with the alternate case as an Untracked\nfile.  (That is, when mydir/filea.txt is added to the repository and\nthen the directory on disk is renamed from mydir/ to MyDir/, git status\nshows MyDir/ as being untracked.)\n\nSupport has been added in name-hash.c for hashing directories with a\nterminating slash into the name hash. When index_name_exists() is called\nwith a directory (a name with a terminating slash), the name is not\nfound via the normal cache_name_compare() call, but it is found in the\nslow_same_name() function.\n\nAdditionally, in dir.c, directory_exists_in_index_icase() allows newly\nadded directories deeper in the directory chain to be identified.\n\nUltimately, it would be better if the file list was read in case\ninsensitive alphabetical order from disk, but this change seems to\nsuffice for now.\n\nThe end result is the directory is looked up in a case insensitive\nmanner and does not show in the Untracked files list.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n dir.c       |   40 ++++++++++++++++++++++++++++++++-\n name-hash.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 110 insertions(+), 2 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 63d7b41..86768fb 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -531,6 +531,39 @@ enum exist_status {\n };\n \n /*\n+ * Do not use the alphabetically stored index to look up\n+ * the directory name; instead, use the case insensitive\n+ * name hash.\n+ */\n+static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)\n+{\n+\tstruct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);\n+\tunsigned char endchar;\n+\n+\tif (!ce)\n+\t\treturn index_nonexistent;\n+\tendchar = ce->name[len];\n+\n+\t/*\n+\t * The cache_entry structure returned will contain this dirname\n+\t * and possibly additional path components.\n+\t */\n+\tif (endchar == '/')\n+\t\treturn index_directory;\n+\n+\t/*\n+\t * If there are no additional path components, then this cache_entry\n+\t * represents a submodule.  Submodules, despite being directories,\n+\t * are stored in the cache without a closing slash.\n+\t */\n+\tif (!endchar && S_ISGITLINK(ce->ce_mode))\n+\t\treturn index_gitdir;\n+\n+\t/* This should never be hit, but it exists just in case. */\n+\treturn index_nonexistent;\n+}\n+\n+/*\n  * The index sorts alphabetically by entry name, which\n  * means that a gitlink sorts as '\\0' at the end, while\n  * a directory (which is defined not as an entry, but as\n@@ -539,7 +572,12 @@ enum exist_status {\n  */\n static enum exist_status directory_exists_in_index(const char *dirname, int len)\n {\n-\tint pos = cache_name_pos(dirname, len);\n+\tint pos;\n+\n+\tif (ignore_case)\n+\t\treturn directory_exists_in_index_icase(dirname, len);\n+\n+\tpos = cache_name_pos(dirname, len);\n \tif (pos < 0)\n \t\tpos = -pos-1;\n \twhile (pos < active_nr) {\ndiff --git a/name-hash.c b/name-hash.c\nindex 0031d78..c6b6a3f 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -32,6 +32,42 @@ static unsigned int hash_name(const char *name, int namelen)\n \treturn hash;\n }\n \n+static void hash_index_entry_directories(struct index_state *istate, struct cache_entry *ce)\n+{\n+\t/*\n+\t * Throw each directory component in the hash for quick lookup\n+\t * during a git status. Directory components are stored with their\n+\t * closing slash.  Despite submodules being a directory, they never\n+\t * reach this point, because they are stored without a closing slash\n+\t * in the cache.\n+\t *\n+\t * Note that the cache_entry stored with the directory does not\n+\t * represent the directory itself.  It is a pointer to an existing\n+\t * filename, and its only purpose is to represent existence of the\n+\t * directory in the cache.  It is very possible multiple directory\n+\t * hash entries may point to the same cache_entry.\n+\t */\n+\tunsigned int hash;\n+\tvoid **pos;\n+\n+\tconst char *ptr = ce->name;\n+\twhile (*ptr) {\n+\t\twhile (*ptr && *ptr != '/')\n+\t\t\t++ptr;\n+\t\tif (*ptr == '/') {\n+\t\t\t++ptr;\n+\t\t\thash = hash_name(ce->name, ptr - ce->name);\n+\t\t\tif (!lookup_hash(hash, &istate->name_hash)) {\n+\t\t\t\tpos = insert_hash(hash, ce, &istate->name_hash);\n+\t\t\t\tif (pos) {\n+\t\t\t\t\tce->next = *pos;\n+\t\t\t\t\t*pos = ce;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n {\n \tvoid **pos;\n@@ -47,6 +83,9 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \t\tce->next = *pos;\n \t\t*pos = ce;\n \t}\n+\n+\tif (ignore_case)\n+\t\thash_index_entry_directories(istate, ce);\n }\n \n static void lazy_init_name_hash(struct index_state *istate)\n@@ -97,7 +136,21 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen\n \tif (len == namelen && !cache_name_compare(name, namelen, ce->name, len))\n \t\treturn 1;\n \n-\treturn icase && slow_same_name(name, namelen, ce->name, len);\n+\tif (!icase)\n+\t\treturn 0;\n+\n+\t/*\n+\t * If the entry we're comparing is a filename (no trailing slash), then compare\n+\t * the lengths exactly.\n+\t */\n+\tif (name[namelen - 1] != '/')\n+\t\treturn slow_same_name(name, namelen, ce->name, len);\n+\n+\t/*\n+\t * For a directory, we point to an arbitrary cache_entry filename.  Just\n+\t * make sure the directory portion matches.\n+\t */\n+\treturn slow_same_name(name, namelen, ce->name, namelen < len ? namelen : len);\n }\n \n struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)\n@@ -115,5 +168,22 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na\n \t\t}\n \t\tce = ce->next;\n \t}\n+\n+\t/*\n+\t * Might be a submodule.  Despite submodules being directories,\n+\t * they are stored in the name hash without a closing slash.\n+\t * When ignore_case is 1, directories are stored in the name hash\n+\t * with their closing slash.\n+\t *\n+\t * The side effect of this storage technique is we have need to\n+\t * remove the slash from name and perform the lookup again without\n+\t * the slash.  If a match is made, S_ISGITLINK(ce->mode) will be\n+\t * true.\n+\t */\n+\tif (icase && name[namelen - 1] == '/') {\n+\t\tce = index_name_exists(istate, name, namelen - 1, icase);\n+\t\tif (ce && S_ISGITLINK(ce->ce_mode))\n+\t\t\treturn ce;\n+\t}\n \treturn NULL;\n }\n"},{"id":"152304","messageId":"20101003043245.1960.24041.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 4/6] Add case insensitivity support when using git ls-files","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:45Z","receivedAt":"2010-10-03T04:32:45Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"When mydir/filea.txt is added, mydir/ is renamed to MyDir/, and\nMyDir/fileb.txt is added, running git ls-files mydir only shows\nmydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt.\nRunning git ls-files mYdIR shows nothing.\n\nWith this patch running git ls-files for mydir, MyDir, and mYdIR shows\nmydir/filea.txt and MyDir/fileb.txt.\n\nWildcards are not handled case insensitively in this patch. Example:\nMyDir/aBc/file.txt is added. git ls-files MyDir/a* works fine, but git\nls-files mydir/a* does not.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n dir.c |   38 ++++++++++++++++++++++++++------------\n 1 files changed, 26 insertions(+), 12 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 86768fb..6e2505d 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -153,16 +153,30 @@ static int match_one(const char *match, const char *name, int namelen)\n \tif (!*match)\n \t\treturn MATCHED_RECURSIVELY;\n \n-\tfor (;;) {\n-\t\tunsigned char c1 = *match;\n-\t\tunsigned char c2 = *name;\n-\t\tif (c1 == '\\0' || is_glob_special(c1))\n-\t\t\tbreak;\n-\t\tif (c1 != c2)\n-\t\t\treturn 0;\n-\t\tmatch++;\n-\t\tname++;\n-\t\tnamelen--;\n+\tif (ignore_case) {\n+\t\tfor (;;) {\n+\t\t\tunsigned char c1 = tolower(*match);\n+\t\t\tunsigned char c2 = tolower(*name);\n+\t\t\tif (c1 == '\\0' || is_glob_special(c1))\n+\t\t\t\tbreak;\n+\t\t\tif (c1 != c2)\n+\t\t\t\treturn 0;\n+\t\t\tmatch++;\n+\t\t\tname++;\n+\t\t\tnamelen--;\n+\t\t}\n+\t} else {\n+\t\tfor (;;) {\n+\t\t\tunsigned char c1 = *match;\n+\t\t\tunsigned char c2 = *name;\n+\t\t\tif (c1 == '\\0' || is_glob_special(c1))\n+\t\t\t\tbreak;\n+\t\t\tif (c1 != c2)\n+\t\t\t\treturn 0;\n+\t\t\tmatch++;\n+\t\t\tname++;\n+\t\t\tnamelen--;\n+\t\t}\n \t}\n \n \n@@ -171,8 +185,8 @@ static int match_one(const char *match, const char *name, int namelen)\n \t * we need to match by fnmatch\n \t */\n \tmatchlen = strlen(match);\n-\tif (strncmp(match, name, matchlen))\n-\t\treturn !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;\n+\tif (strncmp_icase(match, name, matchlen))\n+\t\treturn !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;\n \n \tif (namelen == matchlen)\n \t\treturn MATCHED_EXACTLY;\n"},{"id":"152307","messageId":"20101003043251.1960.1774.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 5/6] Support case folding for git add when core.ignorecase=true","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:51Z","receivedAt":"2010-10-03T04:32:51Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"When MyDir/ABC/filea.txt is added to Git, the disk directory MyDir/ABC/\nis renamed to mydir/aBc/, and then mydir/aBc/fileb.txt is added, the\nindex will contain MyDir/ABC/filea.txt and mydir/aBc/fileb.txt. Although\nthe earlier portions of this patch series account for those differences\nin case, this patch makes the pathing consistent by folding the case of\nnewly added files against the first file added with that path.\n\nIn read-cache.c's add_to_index(), the index_name_exists() support used\nfor git status's case insensitive directory lookups is used to find the\nproper directory case according to what the user already checked in.\nThat is, MyDir/ABC/'s case is used to alter the stored path for\nfileb.txt to MyDir/ABC/fileb.txt (instead of mydir/aBc/fileb.txt).\n\nThis is especially important when cloning a repository to a case\nsensitive file system. MyDir/ABC/ and mydir/aBc/ exist in the same\ndirectory on a Windows machine, but on Linux, the files exist in two\nseparate directories. The update to add_to_index(), in effect, treats a\nWindows file system as case sensitive by making path case consistent.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n read-cache.c |   23 +++++++++++++++++++++++\n 1 files changed, 23 insertions(+), 0 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex 1f42473..379862c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -608,6 +608,29 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \t\tce->ce_mode = ce_mode_from_stat(ent, st_mode);\n \t}\n \n+\t/* When core.ignorecase=true, determine if a directory of the same name but differing\n+\t * case already exists within the Git repository.  If it does, ensure the directory\n+\t * case of the file being added to the repository matches (is folded into) the existing\n+\t * entry's directory case.\n+\t */\n+\tif (ignore_case) {\n+\t\tconst char *startPtr = ce->name;\n+\t\tconst char *ptr = startPtr;\n+\t\twhile (*ptr) {\n+\t\t\twhile (*ptr && *ptr != '/')\n+\t\t\t\t++ptr;\n+\t\t\tif (*ptr == '/') {\n+\t\t\t\tstruct cache_entry *foundce;\n+\t\t\t\t++ptr;\n+\t\t\t\tfoundce = index_name_exists(&the_index, ce->name, ptr - ce->name, ignore_case);\n+\t\t\t\tif (foundce) {\n+\t\t\t\t\tmemcpy((void*)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);\n+\t\t\t\t\tstartPtr = ptr;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n \talias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);\n \tif (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {\n \t\t/* Nothing changed, really */\n"},{"id":"152308","messageId":"20101003043257.1960.60639.stgit@SlamDunk","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"[PATCH v2 6/6] Support case folding in git fast-import when core.ignorecase=true","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T04:32:57Z","receivedAt":"2010-10-03T04:32:57Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"When core.ignorecase=true, imported file paths will be folded to match\nexisting directory case.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n fast-import.c |    7 ++++---\n 1 files changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2317b0f..e214048 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -156,6 +156,7 @@ Format of STDIN stream:\n #include \"csum-file.h\"\n #include \"quote.h\"\n #include \"exec_cmd.h\"\n+#include \"dir.h\"\n \n #define PACK_ID_BITS 16\n #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)\n@@ -1461,7 +1462,7 @@ static int tree_content_set(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (!slash1) {\n \t\t\t\tif (!S_ISDIR(mode)\n \t\t\t\t\t\t&& e->versions[1].mode == mode\n@@ -1527,7 +1528,7 @@ static int tree_content_remove(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (slash1 && !S_ISDIR(e->versions[1].mode))\n \t\t\t\t/*\n \t\t\t\t * If p names a file in some subdirectory, and a\n@@ -1585,7 +1586,7 @@ static int tree_content_get(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (!slash1) {\n \t\t\t\tmemcpy(leaf, e, sizeof(*leaf));\n \t\t\t\tif (e->tree && is_null_sha1(e->versions[1].sha1))\n"},{"id":"152327","messageId":"201010031017.35112.j6t@kdbg.org","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-10-03T08:17:34Z","receivedAt":"2010-10-03T08:17:34Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thank you for the resend.\n\nOn Sonntag, 3. Oktober 2010, Joshua Jensen wrote:\n>  git status and add both use an update made to name-hash.c where\n>  directories, specifically names with a trailing slash, can be looked up\n>  in a case insensitive manner. After trying a myriad of solutions, this\n>  seemed to be the cleanest. Does anyone see a problem with embedding the\n>  directory names in the same hash as the file names? I couldn't find one,\n>  especially since I append a slash to each directory name.\n>\n>  The git add path case folding functionality is a somewhat radical\n>  departure from what Git does now. It is described in detail in patch 5.\n>  Does anyone have any concerns?\n\nSince I'm not an expert in the area that is touched by this series, I'd like \nto draw the list's attention to the questions in these two paragraphs.\n\nJunio, IIRC, the series appeared in next for some time before the 1.7.3 \nrelease. Does this imply that you reviewed the series and deemed the \nimplementation sound?\n\n-- Hannes\n"},{"id":"152328","messageId":"AANLkTikU7D5dWAc-04cVUnjPPrC7rjaqjPe_j3rEvn0u@mail.gmail.com","threadId":"25315","inReplyTo":"20101003043228.1960.88989.stgit@SlamDunk","subject":"Re: [PATCH v2 1/6] Add string comparison functions that respect the ignore_case variable.","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T08:30:49Z","receivedAt":"2010-10-03T08:30:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sun, Oct 3, 2010 at 04:32, Joshua Jensen <jjensen@workspacewhiz.com> wrote:\n\n> diff --git a/dir.c b/dir.c\n> index d1e5e5e..ffa410d 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -18,6 +18,68 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, in\n>        int check_only, const struct path_simplify *simplify);\n>  static int get_dtype(struct dirent *de, const char *path, int len);\n>\n> +/* helper string functions with support for the ignore_case flag */\n> +int strcmp_icase(const char *a, const char *b)\n> +{\n> +       return ignore_case ? strcasecmp(a, b) : strcmp(a, b);\n> +}\n> +\n> +int strncmp_icase(const char *a, const char *b, size_t count)\n> +{\n> +       return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);\n> +}\n> +\n> +int fnmatch_casefold(const char *pattern, const char *string, int flags)\n> +{\n> +       char lowerPatternBuf[MAX_PATH];\n> +       char lowerStringBuf[MAX_PATH];\n> +       char* lowerPattern;\n> +       char* lowerString;\n> +       size_t patternLen;\n> +       size_t stringLen;\n> +       char* out;\n> +       int ret;\n> +\n> +       /*\n> +        * Use the provided stack buffer, if possible.  If the string is too\n> +        * large, allocate buffer space.\n> +        */\n> +       patternLen = strlen(pattern);\n> +       if (patternLen + 1 > sizeof(lowerPatternBuf))\n> +               lowerPattern = xmalloc(patternLen + 1);\n> +       else\n> +               lowerPattern = lowerPatternBuf;\n> +\n> +       stringLen = strlen(string);\n> +       if (stringLen + 1 > sizeof(lowerStringBuf))\n> +               lowerString = xmalloc(stringLen + 1);\n> +       else\n> +               lowerString = lowerStringBuf;\n> +\n> +       /* Make the pattern and string lowercase to pass to fnmatch. */\n> +       for (out = lowerPattern; *pattern; ++out, ++pattern)\n> +               *out = tolower(*pattern);\n> +       *out = 0;\n> +\n> +       for (out = lowerString; *string; ++out, ++string)\n> +               *out = tolower(*string);\n> +       *out = 0;\n> +\n> +       ret = fnmatch(lowerPattern, lowerString, flags);\n> +\n> +       /* Free the pattern or string if it was allocated. */\n> +       if (lowerPattern != lowerPatternBuf)\n> +               free(lowerPattern);\n> +       if (lowerString != lowerStringBuf)\n> +               free(lowerString);\n> +       return ret;\n> +}\n> +\n> +int fnmatch_icase(const char *pattern, const char *string, int flags)\n> +{\n> +       return ignore_case ? fnmatch_casefold(pattern, string, flags) : fnmatch(pattern, string, flags);\n> +}\n\n\nI liked v1 of this patch better, although it obviously had portability\nissues. But I think it would be better to handle this with:\n\n    #ifndef FNM_CASEFOLD\n    int fnmatch_casefold(const char *pattern, const char *string, int flags)\n    {\n        ...\n    }\n    #endf\n\n    int fnmatch_icase(const char *pattern, const char *string, int flags)\n    {\n    #ifndef FNM_CASEFOLD\n           return ignore_case ? fnmatch_casefold(pattern, string,\nflags) : fnmatch(pattern, string, flags);\n    #else\n            return fnmatch(pattern, string, flags | (ignore_case ?\nFNM_CASEFOLD : 0));\n    #endif\n    }\n\nOr simply use fnmatch(..., FNM_CASEFOLD) everywhere and include\ncompat/fnmatch/* on platforms like Solaris that don't have the GNU\nextension.\n\nThat would allow the GNU libc, FreeBSD libc and others that implement\nthe GNU extension to do case folding for us, and we wouldn't have to\nmaintain our own fnmatch_casefold.\n"},{"id":"152329","messageId":"4CA847D5.4000903@workspacewhiz.com","threadId":"25315","inReplyTo":"AANLkTikU7D5dWAc-04cVUnjPPrC7rjaqjPe_j3rEvn0u@mail.gmail.com","subject":"Re: [PATCH v2 1/6] Add string comparison functions that respect the ignore_case variable.","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-03T09:07:33Z","receivedAt":"2010-10-03T09:07:33Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Ævar Arnfjörð Bjarmason\nDate: 10/3/2010 2:30 AM\n> On Sun, Oct 3, 2010 at 04:32, Joshua Jensen<jjensen@workspacewhiz.com>  wrote\n>> +int fnmatch_casefold(const char *pattern, const char *string, int flags)\n>> +{\n>> +       char lowerPatternBuf[MAX_PATH];\n>> +       char lowerStringBuf[MAX_PATH];\n>> +       char* lowerPattern;\n>> +       char* lowerString;\n>> +       size_t patternLen;\n>> +       size_t stringLen;\n>> +       char* out;\n>> +       int ret;\n>> +\n>> +       /*\n>> +        * Use the provided stack buffer, if possible.  If the string is too\n>> +        * large, allocate buffer space.\n>> +        */\n>> +       patternLen = strlen(pattern);\n>> +       if (patternLen + 1>  sizeof(lowerPatternBuf))\n>> +               lowerPattern = xmalloc(patternLen + 1);\n>> +       else\n>> +               lowerPattern = lowerPatternBuf;\n>> +\n>> +       stringLen = strlen(string);\n>> +       if (stringLen + 1>  sizeof(lowerStringBuf))\n>> +               lowerString = xmalloc(stringLen + 1);\n>> +       else\n>> +               lowerString = lowerStringBuf;\n>> +\n>> +       /* Make the pattern and string lowercase to pass to fnmatch. */\n>> +       for (out = lowerPattern; *pattern; ++out, ++pattern)\n>> +               *out = tolower(*pattern);\n>> +       *out = 0;\n>> +\n>> +       for (out = lowerString; *string; ++out, ++string)\n>> +               *out = tolower(*string);\n>> +       *out = 0;\n>> +\n>> +       ret = fnmatch(lowerPattern, lowerString, flags);\n>> +\n>> +       /* Free the pattern or string if it was allocated. */\n>> +       if (lowerPattern != lowerPatternBuf)\n>> +               free(lowerPattern);\n>> +       if (lowerString != lowerStringBuf)\n>> +               free(lowerString);\n>> +       return ret;\n>> +}\n>> +\n>> +int fnmatch_icase(const char *pattern, const char *string, int flags)\n>> +{\n>> +       return ignore_case ? fnmatch_casefold(pattern, string, flags) : fnmatch(pattern, string, flags);\n>> +}\n>\n> I liked v1 of this patch better, although it obviously had portability\n> issues. But I think it would be better to handle this with:\n>\n>      #ifndef FNM_CASEFOLD\n>      int fnmatch_casefold(const char *pattern, const char *string, int flags)\n>      {\n>          ...\n>      }\n>      #endf\n>\n>      int fnmatch_icase(const char *pattern, const char *string, int flags)\n>      {\n>      #ifndef FNM_CASEFOLD\n>             return ignore_case ? fnmatch_casefold(pattern, string,\n> flags) : fnmatch(pattern, string, flags);\n>      #else\n>              return fnmatch(pattern, string, flags | (ignore_case ?\n> FNM_CASEFOLD : 0));\n>      #endif\n>      }\n>\n> Or simply use fnmatch(..., FNM_CASEFOLD) everywhere and include\n> compat/fnmatch/* on platforms like Solaris that don't have the GNU\n> extension.\nThe real problem with compat/fnmatch is determining which random \nplatforms need that support and updating the makefile accordingly.  \nFurther, the compat/fnmatch/* code would need to be rejigged somewhat, \nso there is no possible conflict (now or in the future) with the \nprovided symbols.  We discussed this as a potential problem developers \nwould need to be aware of if the system fnmatch.h (or whatever it is \ncalled) gets #included.\n\nAnyway, what you describe above creates two code paths.  I would imagine \nthat would be harder to debug; that is, on some platforms, it uses \nfnmatch_casefold and on others, it hands it off to fnmatch(..., \nFNM_CASEFOLD).\n\nIn any case, I'd like to find a solution to get this series working for \neveryone.  I've been out of commission for a month (deploying Git to 80+ \nprogrammers at an organization, by the way), but I'm back now and can \nwork this until it is complete.\n\nJosh\n"},{"id":"152335","messageId":"1286099806-25774-1-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 0/8] ab/icase-directory: jj/icase-directory with Makefile + configure checks","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:38Z","receivedAt":"2010-10-03T09:56:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sun, Oct 3, 2010 at 09:07, Joshua Jensen <jjensen@workspacewhiz.com> wrote:\n>  ----- Original Message -----\n> From: Ævar Arnfjörð Bjarmason\n> Date: 10/3/2010 2:30 AM\n>>\n>> On Sun, Oct 3, 2010 at 04:32, Joshua Jensen<jjensen@workspacewhiz.com>\n>>  wrote\n>>>\n>>> +int fnmatch_casefold(const char *pattern, const char *string, int flags)\n>>> +{\n>>> +       char lowerPatternBuf[MAX_PATH];\n>>> +       char lowerStringBuf[MAX_PATH];\n>>> +       char* lowerPattern;\n>>> +       char* lowerString;\n>>> +       size_t patternLen;\n>>> +       size_t stringLen;\n>>> +       char* out;\n>>> +       int ret;\n>>> +\n>>> +       /*\n>>> +        * Use the provided stack buffer, if possible.  If the string is\n>>> too\n>>> +        * large, allocate buffer space.\n>>> +        */\n>>> +       patternLen = strlen(pattern);\n>>> +       if (patternLen + 1>  sizeof(lowerPatternBuf))\n>>> +               lowerPattern = xmalloc(patternLen + 1);\n>>> +       else\n>>> +               lowerPattern = lowerPatternBuf;\n>>> +\n>>> +       stringLen = strlen(string);\n>>> +       if (stringLen + 1>  sizeof(lowerStringBuf))\n>>> +               lowerString = xmalloc(stringLen + 1);\n>>> +       else\n>>> +               lowerString = lowerStringBuf;\n>>> +\n>>> +       /* Make the pattern and string lowercase to pass to fnmatch. */\n>>> +       for (out = lowerPattern; *pattern; ++out, ++pattern)\n>>> +               *out = tolower(*pattern);\n>>> +       *out = 0;\n>>> +\n>>> +       for (out = lowerString; *string; ++out, ++string)\n>>> +               *out = tolower(*string);\n>>> +       *out = 0;\n>>> +\n>>> +       ret = fnmatch(lowerPattern, lowerString, flags);\n>>> +\n>>> +       /* Free the pattern or string if it was allocated. */\n>>> +       if (lowerPattern != lowerPatternBuf)\n>>> +               free(lowerPattern);\n>>> +       if (lowerString != lowerStringBuf)\n>>> +               free(lowerString);\n>>> +       return ret;\n>>> +}\n>>> +\n>>> +int fnmatch_icase(const char *pattern, const char *string, int flags)\n>>> +{\n>>> +       return ignore_case ? fnmatch_casefold(pattern, string, flags) :\n>>> fnmatch(pattern, string, flags);\n>>> +}\n>>\n>> I liked v1 of this patch better, although it obviously had portability\n>> issues. But I think it would be better to handle this with:\n>>\n>>     #ifndef FNM_CASEFOLD\n>>     int fnmatch_casefold(const char *pattern, const char *string, int\n>> flags)\n>>     {\n>>         ...\n>>     }\n>>     #endf\n>>\n>>     int fnmatch_icase(const char *pattern, const char *string, int flags)\n>>     {\n>>     #ifndef FNM_CASEFOLD\n>>            return ignore_case ? fnmatch_casefold(pattern, string,\n>> flags) : fnmatch(pattern, string, flags);\n>>     #else\n>>             return fnmatch(pattern, string, flags | (ignore_case ?\n>> FNM_CASEFOLD : 0));\n>>     #endif\n>>     }\n>>\n>> Or simply use fnmatch(..., FNM_CASEFOLD) everywhere and include\n>> compat/fnmatch/* on platforms like Solaris that don't have the GNU\n>> extension.\n\nI offered before to help with making this portable, so I've gone ahead\nand done it. This series is like your v1, but it has two of my patches\nat the front to add Makefile & configure checks & fallbacks for\nfnmatch if the function either doesn't exist, or it doesn't support\nthe FNM_CASEFOLD flag.\n\n> The real problem with compat/fnmatch is determining which random platforms\n> need that support and updating the makefile accordingly.\n\nWe already do this for a bunch of NO_WHATEVER= flags. Adding one more\nisn't going to be too hard to maintain.\n\n> Further, the compat/fnmatch/* code would need to be rejigged\n> somewhat, so there is no possible conflict (now or in the future)\n> with the provided symbols.  We discussed this as a potential problem\n> developers would need to be aware of if the system fnmatch.h (or\n> whatever it is called) gets #included.\n\nSince we do -Icompat/fnmatch it's going to be our fnmatch.h that's\npicked up, so we aren't going to get a symbol conflict I should think.\n\n> Anyway, what you describe above creates two code paths.  I would imagine\n> that would be harder to debug; that is, on some platforms, it uses\n> fnmatch_casefold and on others, it hands it off to fnmatch(...,\n> FNM_CASEFOLD).\n\nMy ad-hoc example pseudocode created two codepaths, but this version\ndoesn't.\n\n> In any case, I'd like to find a solution to get this series working for\n> everyone.  I've been out of commission for a month (deploying Git to 80+\n> programmers at an organization, by the way), but I'm back now and can work\n> this until it is complete.\n\nThis is all from your v1:\n\nJoshua Jensen (6):\n  Add string comparison functions that respect the ignore_case\n    variable.\n  Case insensitivity support for .gitignore via core.ignorecase\n  Add case insensitivity support for directories when using git status\n  Add case insensitivity support when using git ls-files\n  Support case folding for git add when core.ignorecase=true\n  Support case folding in git fast-import when core.ignorecase=true\n\nThese two are new:\n\nÆvar Arnfjörð Bjarmason (2):\n  Makefile & configure: add a NO_FNMATCH flag\n\nThis one is a good idea in general. We shouldn't be duplicating setup\ncode in both the Windows and MinGW portions of the Makefile, and if we\never get another odd system that doesn't have fnmatch() this will make\nthings just work there.\n\nNeeds testing from someone with Windows.\n\n  Makefile & configure: add a NO_FNMATCH_CASEFOLD flag\n\nThe code needed to make Joshua's code portable. On Solaris this\nreturns with the configure script:\n\n    $ make configure && ./configure | grep -i -e fnmatch && grep -i -e fnmatch config.mak.autogen\n        GEN configure\n    checking for fnmatch... yes\n    checking for library containing fnmatch... none required\n    checking whether the fnmatch function supports the FNMATCH_CASEFOLD GNU extension... no\n    NO_FNMATCH=\n    NO_FNMATCH_CASEFOLD=YesPlease\n\nAnd on Linux:\n\n    $ make configure && ./configure | grep -i -e fnmatch && grep -i -e fnmatch config.mak.autogen\n        GEN configure\n    checking for fnmatch... yes\n    checking for library containing fnmatch... none required\n    checking whether the fnmatch function supports the FNMATCH_CASEFOLD GNU extension... yes\n    NO_FNMATCH=\n    NO_FNMATCH_CASEFOLD=\n\n Makefile      |   27 ++++++++++++---\n config.mak.in |    2 +\n configure.ac  |   28 +++++++++++++++\n dir.c         |  106 ++++++++++++++++++++++++++++++++++++++++++++++----------\n dir.h         |    4 ++\n fast-import.c |    7 ++--\n name-hash.c   |   72 ++++++++++++++++++++++++++++++++++++++-\n read-cache.c  |   23 ++++++++++++\n 8 files changed, 241 insertions(+), 28 deletions(-)\n\n-- \n1.7.3.159.g610493\n"},{"id":"152334","messageId":"1286099806-25774-2-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 1/8] Makefile & configure: add a NO_FNMATCH flag","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:39Z","receivedAt":"2010-10-03T09:56:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Windows and MinGW both lack fnmatch() in their C library and needed\ncompat/fnmatch, but they had duplicate code for adding the compat\nfunction, and there was no Makefile flag or configure check for\nfnmatch.\n\nChange the Makefile it so that it's now possible to compile the compat\nfunction with a NO_FNMATCH=YesPlease flag, and add a configure probe\nfor it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile      |   18 +++++++++++++-----\n config.mak.in |    1 +\n configure.ac  |    6 ++++++\n 3 files changed, 20 insertions(+), 5 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8a56b9a..f7c4383 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -70,6 +70,8 @@ all::\n #\n # Define NO_STRTOK_R if you don't have strtok_r in the C library.\n #\n+# Define NO_FNMATCH if you don't have fnmatch in the C library.\n+#\n # Define NO_LIBGEN_H if you don't have libgen.h.\n #\n # Define NEEDS_LIBGEN if your libgen needs -lgen when linking\n@@ -1052,6 +1054,7 @@ ifeq ($(uname_S),Windows)\n \tNO_STRCASESTR = YesPlease\n \tNO_STRLCPY = YesPlease\n \tNO_STRTOK_R = YesPlease\n+\tNO_FNMATCH = YesPlease\n \tNO_MEMMEM = YesPlease\n \t# NEEDS_LIBICONV = YesPlease\n \tNO_ICONV = YesPlease\n@@ -1081,8 +1084,8 @@ ifeq ($(uname_S),Windows)\n \tAR = compat/vcbuild/scripts/lib.pl\n \tCFLAGS =\n \tBASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE\n-\tCOMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o\n-\tCOMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\\\".exe\\\"\n+\tCOMPAT_OBJS = compat/msvc.o compat/winansi.o compat/win32/pthread.o\n+\tCOMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\\\".exe\\\"\n \tBASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib\n \tEXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib\n \tPTHREAD_LIBS =\n@@ -1107,6 +1110,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_STRCASESTR = YesPlease\n \tNO_STRLCPY = YesPlease\n \tNO_STRTOK_R = YesPlease\n+\tNO_FNMATCH = YesPlease\n \tNO_MEMMEM = YesPlease\n \tNEEDS_LIBICONV = YesPlease\n \tOLD_ICONV = YesPlease\n@@ -1128,10 +1132,9 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_PYTHON = YesPlease\n \tBLK_SHA1 = YesPlease\n \tETAGS_TARGET = ETAGS\n-\tCOMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32\n+\tCOMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32\n \tCOMPAT_CFLAGS += -DSTRIP_EXTENSION=\\\".exe\\\"\n-\tCOMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \\\n-\t\tcompat/win32/pthread.o\n+\tCOMPAT_OBJS += compat/mingw.o compat/winansi.o compat/win32/pthread.o\n \tEXTLIBS += -lws2_32\n \tPTHREAD_LIBS =\n \tX = .exe\n@@ -1342,6 +1345,11 @@ ifdef NO_STRTOK_R\n \tCOMPAT_CFLAGS += -DNO_STRTOK_R\n \tCOMPAT_OBJS += compat/strtok_r.o\n endif\n+ifdef NO_FNMATCH\n+\tCOMPAT_CFLAGS += -Icompat/fnmatch\n+\tCOMPAT_CFLAGS += -DNO_FNMATCH\n+\tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n+endif\n ifdef NO_SETENV\n \tCOMPAT_CFLAGS += -DNO_SETENV\n \tCOMPAT_OBJS += compat/setenv.o\ndiff --git a/config.mak.in b/config.mak.in\nindex a0c34ee..aaa70a8 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -47,6 +47,7 @@ NO_C99_FORMAT=@NO_C99_FORMAT@\n NO_HSTRERROR=@NO_HSTRERROR@\n NO_STRCASESTR=@NO_STRCASESTR@\n NO_STRTOK_R=@NO_STRTOK_R@\n+NO_FNMATCH=@NO_FNMATCH@\n NO_MEMMEM=@NO_MEMMEM@\n NO_STRLCPY=@NO_STRLCPY@\n NO_UINTMAX_T=@NO_UINTMAX_T@\ndiff --git a/configure.ac b/configure.ac\nindex cc55b6d..7715f6c 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -818,6 +818,12 @@ GIT_CHECK_FUNC(strtok_r,\n [NO_STRTOK_R=YesPlease])\n AC_SUBST(NO_STRTOK_R)\n #\n+# Define NO_FNMATCH if you don't have fnmatch\n+GIT_CHECK_FUNC(fnmatch,\n+[NO_FNMATCH=],\n+[NO_FNMATCH=YesPlease])\n+AC_SUBST(NO_FNMATCH)\n+#\n # Define NO_MEMMEM if you don't have memmem.\n GIT_CHECK_FUNC(memmem,\n [NO_MEMMEM=],\n-- \n1.7.3.159.g610493\n"},{"id":"152337","messageId":"1286099806-25774-3-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 2/8] Makefile & configure: add a NO_FNMATCH_CASEFOLD flag","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:40Z","receivedAt":"2010-10-03T09:56:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On some platforms (like Solaris) there is a fnmatch, but it doesn't\nsupport the GNU FNM_CASEFOLD extension that's used by the\njj/icase-directory series' fnmatch_icase wrapper.\n\nChange the Makefile so that it's now possible to set\nNO_FNMATCH_CASEFOLD=YesPlease on those systems, and add a configure\nprobe for it.\n\nUnlike the NO_REGEX check we don't add AC_INCLUDES_DEFAULT to our\nheaders. This is because on a GNU system the definition of\nFNM_CASEFOLD in fnmatch.h is guarded by:\n\n    #if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE\n\nOne of the headers AC_INCLUDES_DEFAULT includes ends up defining one\nof those, so if we'd use it we'd always get\nNO_FNMATCH_CASEFOLD=YesPlease on GNU systems, even though they have\nFNM_CASEFOLD.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile      |    9 +++++++++\n config.mak.in |    1 +\n configure.ac  |   22 ++++++++++++++++++++++\n 3 files changed, 32 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex f7c4383..5fe0523 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -72,6 +72,9 @@ all::\n #\n # Define NO_FNMATCH if you don't have fnmatch in the C library.\n #\n+# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the\n+# FNM_CASEFOLD GNU extension.\n+#\n # Define NO_LIBGEN_H if you don't have libgen.h.\n #\n # Define NEEDS_LIBGEN if your libgen needs -lgen when linking\n@@ -848,6 +851,7 @@ ifeq ($(uname_S),SunOS)\n \tNO_MKDTEMP = YesPlease\n \tNO_MKSTEMPS = YesPlease\n \tNO_REGEX = YesPlease\n+\tNO_FNMATCH_CASEFOLD = YesPlease\n \tifeq ($(uname_R),5.6)\n \t\tSOCKLEN_T = int\n \t\tNO_HSTRERROR = YesPlease\n@@ -1350,6 +1354,11 @@ ifdef NO_FNMATCH\n \tCOMPAT_CFLAGS += -DNO_FNMATCH\n \tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n endif\n+ifdef NO_FNMATCH_CASEFOLD\n+\tCOMPAT_CFLAGS += -Icompat/fnmatch\n+\tCOMPAT_CFLAGS += -DNO_FNMATCH_CASEFOLD\n+\tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n+endif\n ifdef NO_SETENV\n \tCOMPAT_CFLAGS += -DNO_SETENV\n \tCOMPAT_OBJS += compat/setenv.o\ndiff --git a/config.mak.in b/config.mak.in\nindex aaa70a8..56343ba 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -48,6 +48,7 @@ NO_HSTRERROR=@NO_HSTRERROR@\n NO_STRCASESTR=@NO_STRCASESTR@\n NO_STRTOK_R=@NO_STRTOK_R@\n NO_FNMATCH=@NO_FNMATCH@\n+NO_FNMATCH_CASEFOLD=@NO_FNMATCH_CASEFOLD@\n NO_MEMMEM=@NO_MEMMEM@\n NO_STRLCPY=@NO_STRLCPY@\n NO_UINTMAX_T=@NO_UINTMAX_T@\ndiff --git a/configure.ac b/configure.ac\nindex 7715f6c..6dd9241 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -824,6 +824,28 @@ GIT_CHECK_FUNC(fnmatch,\n [NO_FNMATCH=YesPlease])\n AC_SUBST(NO_FNMATCH)\n #\n+# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the\n+# FNM_CASEFOLD GNU extension.\n+AC_CACHE_CHECK([whether the fnmatch function supports the FNMATCH_CASEFOLD GNU extension],\n+ [ac_cv_c_excellent_fnmatch], [\n+AC_EGREP_CPP(yippeeyeswehaveit,\n+\tAC_LANG_PROGRAM([\n+#include <fnmatch.h>\n+],\n+[#ifdef FNM_CASEFOLD\n+yippeeyeswehaveit\n+#endif\n+]),\n+\t[ac_cv_c_excellent_fnmatch=yes],\n+\t[ac_cv_c_excellent_fnmatch=no])\n+])\n+if test $ac_cv_c_excellent_fnmatch = yes; then\n+\tNO_FNMATCH_CASEFOLD=\n+else\n+\tNO_FNMATCH_CASEFOLD=YesPlease\n+fi\n+AC_SUBST(NO_FNMATCH_CASEFOLD)\n+#\n # Define NO_MEMMEM if you don't have memmem.\n GIT_CHECK_FUNC(memmem,\n [NO_MEMMEM=],\n-- \n1.7.3.159.g610493\n"},{"id":"152333","messageId":"1286099806-25774-4-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 3/8] Add string comparison functions that respect the ignore_case variable.","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:41Z","receivedAt":"2010-10-03T09:56:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nMultiple locations within this patch series alter a case sensitive\nstring comparison call such as strcmp() to be a call to a string\ncomparison call that selects case comparison based on the global\nignore_case variable. Behaviorally, when core.ignorecase=false, the\n*_icase() versions are functionally equivalent to their C runtime\ncounterparts.  When core.ignorecase=true, the *_icase() versions perform\na case insensitive comparison.\n\nLike Linus' earlier ignorecase patch, these may ignore filename\nconventions on certain file systems. By isolating filename comparisons\nto certain functions, support for those filename conventions may be more\neasily met.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |   16 ++++++++++++++++\n dir.h |    4 ++++\n 2 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex d1e5e5e..3432d58 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -18,6 +18,22 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, in\n \tint check_only, const struct path_simplify *simplify);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n+/* helper string functions with support for the ignore_case flag */\n+int strcmp_icase(const char *a, const char *b)\n+{\n+\treturn ignore_case ? strcasecmp(a, b) : strcmp(a, b);\n+}\n+\n+int strncmp_icase(const char *a, const char *b, size_t count)\n+{\n+\treturn ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);\n+}\n+\n+int fnmatch_icase(const char *pattern, const char *string, int flags)\n+{\n+\treturn fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));\n+}\n+\n static int common_prefix(const char **pathspec)\n {\n \tconst char *path, *slash, *next;\ndiff --git a/dir.h b/dir.h\nindex 278d84c..b3e2104 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -101,4 +101,8 @@ extern int remove_dir_recursively(struct strbuf *path, int flag);\n /* tries to remove the path with empty directories along it, ignores ENOENT */\n extern int remove_path(const char *path);\n \n+extern int strcmp_icase(const char *a, const char *b);\n+extern int strncmp_icase(const char *a, const char *b, size_t count);\n+extern int fnmatch_icase(const char *pattern, const char *string, int flags);\n+\n #endif\n-- \n1.7.3.159.g610493\n"},{"id":"152336","messageId":"1286099806-25774-5-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 4/8] Case insensitivity support for .gitignore via core.ignorecase","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:42Z","receivedAt":"2010-10-03T09:56:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nThis is especially beneficial when using Windows and Perforce and the\ngit-p4 bridge. Internally, Perforce preserves a given file's full path\nincluding its case at the time it was added to the Perforce repository.\nWhen syncing a file down via Perforce, missing directories are created,\nif necessary, using the case as stored with the filename. Unfortunately,\ntwo files in the same directory can have differing cases for their\nrespective paths, such as /diRa/file1.c and /DirA/file2.c. Depending on\nsync order, DirA/ may get created instead of diRa/.\n\nIt is possible to handle directory names in a case insensitive manner\nwithout this patch, but it is highly inconvenient, requiring each\ncharacter to be specified like so: [Bb][Uu][Ii][Ll][Dd]. With this patch, the\ngitignore exclusions honor the core.ignorecase=true configuration\nsetting and make the process less error prone. The above is specified\nlike so: Build\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |   12 ++++++------\n 1 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 3432d58..02c2a82 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -390,14 +390,14 @@ int excluded_from_list(const char *pathname,\n \t\t\tif (x->flags & EXC_FLAG_NODIR) {\n \t\t\t\t/* match basename */\n \t\t\t\tif (x->flags & EXC_FLAG_NOWILDCARD) {\n-\t\t\t\t\tif (!strcmp(exclude, basename))\n+\t\t\t\t\tif (!strcmp_icase(exclude, basename))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else if (x->flags & EXC_FLAG_ENDSWITH) {\n \t\t\t\t\tif (x->patternlen - 1 <= pathlen &&\n-\t\t\t\t\t    !strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))\n+\t\t\t\t\t    !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else {\n-\t\t\t\t\tif (fnmatch(exclude, basename, 0) == 0)\n+\t\t\t\t\tif (fnmatch_icase(exclude, basename, 0) == 0)\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t}\n \t\t\t}\n@@ -412,14 +412,14 @@ int excluded_from_list(const char *pathname,\n \n \t\t\t\tif (pathlen < baselen ||\n \t\t\t\t    (baselen && pathname[baselen-1] != '/') ||\n-\t\t\t\t    strncmp(pathname, x->base, baselen))\n+\t\t\t\t    strncmp_icase(pathname, x->base, baselen))\n \t\t\t\t    continue;\n \n \t\t\t\tif (x->flags & EXC_FLAG_NOWILDCARD) {\n-\t\t\t\t\tif (!strcmp(exclude, pathname + baselen))\n+\t\t\t\t\tif (!strcmp_icase(exclude, pathname + baselen))\n \t\t\t\t\t\treturn to_exclude;\n \t\t\t\t} else {\n-\t\t\t\t\tif (fnmatch(exclude, pathname+baselen,\n+\t\t\t\t\tif (fnmatch_icase(exclude, pathname+baselen,\n \t\t\t\t\t\t    FNM_PATHNAME) == 0)\n \t\t\t\t\t    return to_exclude;\n \t\t\t\t}\n-- \n1.7.3.159.g610493\n"},{"id":"152338","messageId":"1286099806-25774-6-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 5/8] Add case insensitivity support for directories when using git status","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:43Z","receivedAt":"2010-10-03T09:56:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nWhen using a case preserving but case insensitive file system, directory\ncase can differ but still refer to the same physical directory.  git\nstatus reports the directory with the alternate case as an Untracked\nfile.  (That is, when mydir/filea.txt is added to the repository and\nthen the directory on disk is renamed from mydir/ to MyDir/, git status\nshows MyDir/ as being untracked.)\n\nSupport has been added in name-hash.c for hashing directories with a\nterminating slash into the name hash. When index_name_exists() is called\nwith a directory (a name with a terminating slash), the name is not\nfound via the normal cache_name_compare() call, but it is found in the\nslow_same_name() function.\n\nAdditionally, in dir.c, directory_exists_in_index_icase() allows newly\nadded directories deeper in the directory chain to be identified.\n\nUltimately, it would be better if the file list was read in case\ninsensitive alphabetical order from disk, but this change seems to\nsuffice for now.\n\nThe end result is the directory is looked up in a case insensitive\nmanner and does not show in the Untracked files list.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c       |   40 ++++++++++++++++++++++++++++++++-\n name-hash.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 110 insertions(+), 2 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 02c2a82..cf8f65c 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -485,6 +485,39 @@ enum exist_status {\n };\n \n /*\n+ * Do not use the alphabetically stored index to look up\n+ * the directory name; instead, use the case insensitive\n+ * name hash.\n+ */\n+static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)\n+{\n+\tstruct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);\n+\tunsigned char endchar;\n+\n+\tif (!ce)\n+\t\treturn index_nonexistent;\n+\tendchar = ce->name[len];\n+\n+\t/*\n+\t * The cache_entry structure returned will contain this dirname\n+\t * and possibly additional path components.\n+\t */\n+\tif (endchar == '/')\n+\t\treturn index_directory;\n+\n+\t/*\n+\t * If there are no additional path components, then this cache_entry\n+\t * represents a submodule.  Submodules, despite being directories,\n+\t * are stored in the cache without a closing slash.\n+\t */\n+\tif (!endchar && S_ISGITLINK(ce->ce_mode))\n+\t\treturn index_gitdir;\n+\n+\t/* This should never be hit, but it exists just in case. */\n+\treturn index_nonexistent;\n+}\n+\n+/*\n  * The index sorts alphabetically by entry name, which\n  * means that a gitlink sorts as '\\0' at the end, while\n  * a directory (which is defined not as an entry, but as\n@@ -493,7 +526,12 @@ enum exist_status {\n  */\n static enum exist_status directory_exists_in_index(const char *dirname, int len)\n {\n-\tint pos = cache_name_pos(dirname, len);\n+\tint pos;\n+\n+\tif (ignore_case)\n+\t\treturn directory_exists_in_index_icase(dirname, len);\n+\n+\tpos = cache_name_pos(dirname, len);\n \tif (pos < 0)\n \t\tpos = -pos-1;\n \twhile (pos < active_nr) {\ndiff --git a/name-hash.c b/name-hash.c\nindex 0031d78..c6b6a3f 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -32,6 +32,42 @@ static unsigned int hash_name(const char *name, int namelen)\n \treturn hash;\n }\n \n+static void hash_index_entry_directories(struct index_state *istate, struct cache_entry *ce)\n+{\n+\t/*\n+\t * Throw each directory component in the hash for quick lookup\n+\t * during a git status. Directory components are stored with their\n+\t * closing slash.  Despite submodules being a directory, they never\n+\t * reach this point, because they are stored without a closing slash\n+\t * in the cache.\n+\t *\n+\t * Note that the cache_entry stored with the directory does not\n+\t * represent the directory itself.  It is a pointer to an existing\n+\t * filename, and its only purpose is to represent existence of the\n+\t * directory in the cache.  It is very possible multiple directory\n+\t * hash entries may point to the same cache_entry.\n+\t */\n+\tunsigned int hash;\n+\tvoid **pos;\n+\n+\tconst char *ptr = ce->name;\n+\twhile (*ptr) {\n+\t\twhile (*ptr && *ptr != '/')\n+\t\t\t++ptr;\n+\t\tif (*ptr == '/') {\n+\t\t\t++ptr;\n+\t\t\thash = hash_name(ce->name, ptr - ce->name);\n+\t\t\tif (!lookup_hash(hash, &istate->name_hash)) {\n+\t\t\t\tpos = insert_hash(hash, ce, &istate->name_hash);\n+\t\t\t\tif (pos) {\n+\t\t\t\t\tce->next = *pos;\n+\t\t\t\t\t*pos = ce;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n {\n \tvoid **pos;\n@@ -47,6 +83,9 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)\n \t\tce->next = *pos;\n \t\t*pos = ce;\n \t}\n+\n+\tif (ignore_case)\n+\t\thash_index_entry_directories(istate, ce);\n }\n \n static void lazy_init_name_hash(struct index_state *istate)\n@@ -97,7 +136,21 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen\n \tif (len == namelen && !cache_name_compare(name, namelen, ce->name, len))\n \t\treturn 1;\n \n-\treturn icase && slow_same_name(name, namelen, ce->name, len);\n+\tif (!icase)\n+\t\treturn 0;\n+\n+\t/*\n+\t * If the entry we're comparing is a filename (no trailing slash), then compare\n+\t * the lengths exactly.\n+\t */\n+\tif (name[namelen - 1] != '/')\n+\t\treturn slow_same_name(name, namelen, ce->name, len);\n+\n+\t/*\n+\t * For a directory, we point to an arbitrary cache_entry filename.  Just\n+\t * make sure the directory portion matches.\n+\t */\n+\treturn slow_same_name(name, namelen, ce->name, namelen < len ? namelen : len);\n }\n \n struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)\n@@ -115,5 +168,22 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na\n \t\t}\n \t\tce = ce->next;\n \t}\n+\n+\t/*\n+\t * Might be a submodule.  Despite submodules being directories,\n+\t * they are stored in the name hash without a closing slash.\n+\t * When ignore_case is 1, directories are stored in the name hash\n+\t * with their closing slash.\n+\t *\n+\t * The side effect of this storage technique is we have need to\n+\t * remove the slash from name and perform the lookup again without\n+\t * the slash.  If a match is made, S_ISGITLINK(ce->mode) will be\n+\t * true.\n+\t */\n+\tif (icase && name[namelen - 1] == '/') {\n+\t\tce = index_name_exists(istate, name, namelen - 1, icase);\n+\t\tif (ce && S_ISGITLINK(ce->ce_mode))\n+\t\t\treturn ce;\n+\t}\n \treturn NULL;\n }\n-- \n1.7.3.159.g610493\n"},{"id":"152339","messageId":"1286099806-25774-7-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:44Z","receivedAt":"2010-10-03T09:56:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nWhen mydir/filea.txt is added, mydir/ is renamed to MyDir/, and\nMyDir/fileb.txt is added, running git ls-files mydir only shows\nmydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt.\nRunning git ls-files mYdIR shows nothing.\n\nWith this patch running git ls-files for mydir, MyDir, and mYdIR shows\nmydir/filea.txt and MyDir/fileb.txt.\n\nWildcards are not handled case insensitively in this patch. Example:\nMyDir/aBc/file.txt is added. git ls-files MyDir/a* works fine, but git\nls-files mydir/a* does not.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n dir.c |   38 ++++++++++++++++++++++++++------------\n 1 files changed, 26 insertions(+), 12 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex cf8f65c..53aa4f3 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -107,16 +107,30 @@ static int match_one(const char *match, const char *name, int namelen)\n \tif (!*match)\n \t\treturn MATCHED_RECURSIVELY;\n \n-\tfor (;;) {\n-\t\tunsigned char c1 = *match;\n-\t\tunsigned char c2 = *name;\n-\t\tif (c1 == '\\0' || is_glob_special(c1))\n-\t\t\tbreak;\n-\t\tif (c1 != c2)\n-\t\t\treturn 0;\n-\t\tmatch++;\n-\t\tname++;\n-\t\tnamelen--;\n+\tif (ignore_case) {\n+\t\tfor (;;) {\n+\t\t\tunsigned char c1 = tolower(*match);\n+\t\t\tunsigned char c2 = tolower(*name);\n+\t\t\tif (c1 == '\\0' || is_glob_special(c1))\n+\t\t\t\tbreak;\n+\t\t\tif (c1 != c2)\n+\t\t\t\treturn 0;\n+\t\t\tmatch++;\n+\t\t\tname++;\n+\t\t\tnamelen--;\n+\t\t}\n+\t} else {\n+\t\tfor (;;) {\n+\t\t\tunsigned char c1 = *match;\n+\t\t\tunsigned char c2 = *name;\n+\t\t\tif (c1 == '\\0' || is_glob_special(c1))\n+\t\t\t\tbreak;\n+\t\t\tif (c1 != c2)\n+\t\t\t\treturn 0;\n+\t\t\tmatch++;\n+\t\t\tname++;\n+\t\t\tnamelen--;\n+\t\t}\n \t}\n \n \n@@ -125,8 +139,8 @@ static int match_one(const char *match, const char *name, int namelen)\n \t * we need to match by fnmatch\n \t */\n \tmatchlen = strlen(match);\n-\tif (strncmp(match, name, matchlen))\n-\t\treturn !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;\n+\tif (strncmp_icase(match, name, matchlen))\n+\t\treturn !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;\n \n \tif (namelen == matchlen)\n \t\treturn MATCHED_EXACTLY;\n-- \n1.7.3.159.g610493\n"},{"id":"152340","messageId":"1286099806-25774-8-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 7/8] Support case folding for git add when core.ignorecase=true","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:45Z","receivedAt":"2010-10-03T09:56:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nWhen MyDir/ABC/filea.txt is added to Git, the disk directory MyDir/ABC/\nis renamed to mydir/aBc/, and then mydir/aBc/fileb.txt is added, the\nindex will contain MyDir/ABC/filea.txt and mydir/aBc/fileb.txt. Although\nthe earlier portions of this patch series account for those differences\nin case, this patch makes the pathing consistent by folding the case of\nnewly added files against the first file added with that path.\n\nIn read-cache.c's add_to_index(), the index_name_exists() support used\nfor git status's case insensitive directory lookups is used to find the\nproper directory case according to what the user already checked in.\nThat is, MyDir/ABC/'s case is used to alter the stored path for\nfileb.txt to MyDir/ABC/fileb.txt (instead of mydir/aBc/fileb.txt).\n\nThis is especially important when cloning a repository to a case\nsensitive file system. MyDir/ABC/ and mydir/aBc/ exist in the same\ndirectory on a Windows machine, but on Linux, the files exist in two\nseparate directories. The update to add_to_index(), in effect, treats a\nWindows file system as case sensitive by making path case consistent.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n read-cache.c |   23 +++++++++++++++++++++++\n 1 files changed, 23 insertions(+), 0 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex 1f42473..379862c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -608,6 +608,29 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \t\tce->ce_mode = ce_mode_from_stat(ent, st_mode);\n \t}\n \n+\t/* When core.ignorecase=true, determine if a directory of the same name but differing\n+\t * case already exists within the Git repository.  If it does, ensure the directory\n+\t * case of the file being added to the repository matches (is folded into) the existing\n+\t * entry's directory case.\n+\t */\n+\tif (ignore_case) {\n+\t\tconst char *startPtr = ce->name;\n+\t\tconst char *ptr = startPtr;\n+\t\twhile (*ptr) {\n+\t\t\twhile (*ptr && *ptr != '/')\n+\t\t\t\t++ptr;\n+\t\t\tif (*ptr == '/') {\n+\t\t\t\tstruct cache_entry *foundce;\n+\t\t\t\t++ptr;\n+\t\t\t\tfoundce = index_name_exists(&the_index, ce->name, ptr - ce->name, ignore_case);\n+\t\t\t\tif (foundce) {\n+\t\t\t\t\tmemcpy((void*)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);\n+\t\t\t\t\tstartPtr = ptr;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n \talias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);\n \tif (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {\n \t\t/* Nothing changed, really */\n-- \n1.7.3.159.g610493\n"},{"id":"152341","messageId":"1286099806-25774-9-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"[PATCH/RFC v3 8/8] Support case folding in git fast-import when core.ignorecase=true","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-03T09:56:46Z","receivedAt":"2010-10-03T09:56:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Joshua Jensen <jjensen@workspacewhiz.com>\n\nWhen core.ignorecase=true, imported file paths will be folded to match\nexisting directory case.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fast-import.c |    7 ++++---\n 1 files changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2317b0f..e214048 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -156,6 +156,7 @@ Format of STDIN stream:\n #include \"csum-file.h\"\n #include \"quote.h\"\n #include \"exec_cmd.h\"\n+#include \"dir.h\"\n \n #define PACK_ID_BITS 16\n #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)\n@@ -1461,7 +1462,7 @@ static int tree_content_set(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (!slash1) {\n \t\t\t\tif (!S_ISDIR(mode)\n \t\t\t\t\t\t&& e->versions[1].mode == mode\n@@ -1527,7 +1528,7 @@ static int tree_content_remove(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (slash1 && !S_ISDIR(e->versions[1].mode))\n \t\t\t\t/*\n \t\t\t\t * If p names a file in some subdirectory, and a\n@@ -1585,7 +1586,7 @@ static int tree_content_get(\n \n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n-\t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n+\t\tif (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {\n \t\t\tif (!slash1) {\n \t\t\t\tmemcpy(leaf, e, sizeof(*leaf));\n \t\t\t\tif (e->tree && is_null_sha1(e->versions[1].sha1))\n-- \n1.7.3.159.g610493\n"},{"id":"152344","messageId":"AANLkTinZzM=HeT_J-tF5F9DBdvts3i+nboPkPy-uc8V5@mail.gmail.com","threadId":"25315","inReplyTo":"20101003043221.1960.73178.stgit@SlamDunk","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Robert Buck","fromEmail":"buck.robert.j@gmail.com","sentAt":"2010-10-03T11:48:08Z","receivedAt":"2010-10-03T11:48:08Z","isPatch":true,"sender":{"key":"buck.robert.j@gmail.com","avatar":"https://gravatar.com/avatar/1686742e8ac2595378aac67f26fd638ddaf494194f9af0cb6082c4a7eca1a366?d=mp&s=160"},"body":"Referring back to my earlier comment to this patch series, which was\nproposed on August 17, while I tend to agree to the changes that help\nlisting- operations, those changes that fold case concern me. Let me\nexplain...\n\nYou may find there is a strong contingent of people that would approve\nof, and would want to use, case insensitivity for gitignore and ls,\nfor example; but by tying the same single property (core.ignorecase)\nto the case folding behaviors some people would avoid the feature all\ntogether, which would be unfortunate, when they otherwise could\nbenefit from at least one part of the new behavior.\n\nThere were several key things that went wrong in early git\ndevelopment, this and the eol support were two casualties. The eol\nsupport, as you recall, deprecated the old property in favor of a\ncouple new superior ones. I would recommend that the same thing be\ndone here, deprecate the old ignorecase property by introducing two\nbetter ones.\n\nSo I could we please separate the behaviors that change intent\n(folding) from the behaviors that merely alter how things are\ndisplayed (listing) by splitting this into two separate properties?\nFor example,\n\ncore.casepreserving=true|false\ncore.caseinsensitive=true|false\n\nThe former property would control folding, the latter property would\napply to listing and pattern matching. Then people could opt out of\nthe folding behaviors (add, import), while continuing to adopt listing\nand pattern matching (status, ls, ignore).\n\nAgain, deprecate core.ignorecase by making it default to {false,false}\nfor the new properties if unspecified, which would also be the default\nif all three of the properties are unspecified. If ignorecase is\nspecified to be true, then default to {false, true}, respectively.\n\nWould this be possible?\n\nOn Sun, Oct 3, 2010 at 12:32 AM, Joshua Jensen\n<jjensen@workspacewhiz.com> wrote:\n> The second version of this patch series fixes the problematic case\n> insensitive fnmatch call in patch 1 that relied on an apparently GNU-only\n> extension.  Instead, the pattern and string are lowercased into\n> temporary buffers, and the standard fnmatch is called without relying\n> on the GNU extension.\n>\n> Patches 2-6 received no modifications.\n>\n> The original cover for the patch series follows as posted by Johannes Sixt:\n>\n> The following patch series extends the core.ignorecase=true support to\n> handle case insensitive comparisons for the .gitignore file, git status,\n> and git ls-files.  git add and git fast-import will fold the case of the\n> file being added, matching that of an already added directory entry.  Case\n> folding is also applied to git fast-import for renames, copies, and deletes.\n>\n> The most notable benefit, IMO, is that the case of directories in the\n> worktree does not matter if, and only if, the directory exists already in\n> the index with some different case variant.  This helps applications on\n> Windows that change the case even of directories in unpredictable ways.\n> Joshua mentioned Perforce as the primary example.\n>\n> Concerning the implementation, Joshua explained when he initially submitted\n> the series to the msysgit mailing list:\n>\n>  git status and add both use an update made to name-hash.c where\n>  directories, specifically names with a trailing slash, can be looked up\n>  in a case insensitive manner. After trying a myriad of solutions, this\n>  seemed to be the cleanest. Does anyone see a problem with embedding the\n>  directory names in the same hash as the file names? I couldn't find one,\n>  especially since I append a slash to each directory name.\n>\n>  The git add path case folding functionality is a somewhat radical\n>  departure from what Git does now. It is described in detail in patch 5.\n>  Does anyone have any concerns?\n>\n> I support the idea of this patch, and I can confirm that it works: I've\n> used this series in production both with core.ignorecase set to true and\n> to false, and in the former case, with directories and files with case\n> different from the index.\n>\n> Joshua Jensen (6):\n>      Add string comparison functions that respect the ignore_case variable.\n>      Case insensitivity support for .gitignore via core.ignorecase\n>      Add case insensitivity support for directories when using git status\n>      Add case insensitivity support when using git ls-files\n>      Support case folding for git add when core.ignorecase=true\n>      Support case folding in git fast-import when core.ignorecase=true\n>\n>\n>  dir.c         |  152 ++++++++++++++++++++++++++++++++++++++++++++++++++-------\n>  dir.h         |    4 ++\n>  fast-import.c |    7 ++-\n>  name-hash.c   |   72 +++++++++++++++++++++++++++\n>  read-cache.c  |   23 +++++++++\n>  5 files changed, 235 insertions(+), 23 deletions(-)\n>\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n"},{"id":"152345","messageId":"AANLkTimH8Lj69qcOCmR3+5HYfgKnr5nyMvQU=9h0=FaB@mail.gmail.com","threadId":"25315","inReplyTo":"1286099806-25774-7-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Thomas Adam","fromEmail":"thomas@xteddy.org","sentAt":"2010-10-03T11:54:22Z","receivedAt":"2010-10-03T11:54:22Z","isPatch":true,"sender":{"key":"thomas@xteddy.org","avatar":"https://gravatar.com/avatar/e7256db4738e501e5d2e84f00bb0bd99503165729573848a03330301fc2adc4a?d=mp&s=160"},"body":"Hi --\n\nOn 3 October 2010 10:56, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> +       if (ignore_case) {\n> +               for (;;) {\n> +                       unsigned char c1 = tolower(*match);\n> +                       unsigned char c2 = tolower(*name);\n> +                       if (c1 == '\\0' || is_glob_special(c1))\n> +                               break;\n> +                       if (c1 != c2)\n> +                               return 0;\n> +                       match++;\n> +                       name++;\n> +                       namelen--;\n> +               }\n> +       } else {\n> +               for (;;) {\n> +                       unsigned char c1 = *match;\n> +                       unsigned char c2 = *name;\n> +                       if (c1 == '\\0' || is_glob_special(c1))\n> +                               break;\n> +                       if (c1 != c2)\n> +                               return 0;\n> +                       match++;\n> +                       name++;\n> +                       namelen--;\n> +               }\n>        }\n\nIt's a real shame about the code duplication here.  Can we not avoid\nit just by doing:\n\nunsigned char c1 = (ignore_case) ? tolower(*match) : *match;\nunisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n\nI appreciate that to some it might look like perl golf, but...\n\n-- Thomas Adam\n"},{"id":"152353","messageId":"AANLkTim=PnESiRa4urT4ADnUAj4BzfQrWKwoc-1XTzDe@mail.gmail.com","threadId":"25315","inReplyTo":"20101003043257.1960.60639.stgit@SlamDunk","subject":"Re: [PATCH v2 6/6] Support case folding in git fast-import when core.ignorecase=true","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-03T13:00:23Z","receivedAt":"2010-10-03T13:00:23Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Oct 3, 2010 at 06:32, Joshua Jensen <jjensen@workspacewhiz.com> wrote:\n> When core.ignorecase=true, imported file paths will be folded to match\n> existing directory case.\n\nI haven't checked if you got all the relevant cases in fast-import.c,\nbut the cases you do address look good.\n\nHow would this handle incremental imports? How does this handle\nsomeone adding a file twice, with the same name but different case?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"152370","messageId":"201010031958.59482.j6t@kdbg.org","threadId":"25315","inReplyTo":"1286099806-25774-3-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 2/8] Makefile & configure: add a NO_FNMATCH_CASEFOLD flag","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-10-03T17:58:59Z","receivedAt":"2010-10-03T17:58:59Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Sonntag, 3. Oktober 2010, Ævar Arnfjörð Bjarmason wrote:\n> @@ -1350,6 +1354,11 @@ ifdef NO_FNMATCH\n>  \tCOMPAT_CFLAGS += -DNO_FNMATCH\n>  \tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n>  endif\n> +ifdef NO_FNMATCH_CASEFOLD\n> +\tCOMPAT_CFLAGS += -Icompat/fnmatch\n> +\tCOMPAT_CFLAGS += -DNO_FNMATCH_CASEFOLD\n> +\tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n> +endif\n\nI think you should protect against defining both NO_FNMATCH and \nNO_FNMATCH_CASEFOLD (your version would link compat/fnmatch/fnmatch.o twice \nin this case):\n\nifdef NO_FNMATCH\n...\nelse\nifdef NO_FNMATCH_CASEFOLD\n...\nendif\nendif\n\nOtherwise, the patch looks fine.\n\n-- Hannes\n"},{"id":"152372","messageId":"201010032012.01678.j6t@kdbg.org","threadId":"25315","inReplyTo":"AANLkTinZzM=HeT_J-tF5F9DBdvts3i+nboPkPy-uc8V5@mail.gmail.com","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-10-03T18:12:01Z","receivedAt":"2010-10-03T18:12:01Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Sonntag, 3. Oktober 2010, Robert Buck wrote:\n> So I could we please separate the behaviors that change intent\n> (folding) from the behaviors that merely alter how things are\n> displayed (listing) by splitting this into two separate properties?\n> For example,\n>\n> core.casepreserving=true|false\n> core.caseinsensitive=true|false\n>\n> The former property would control folding, the latter property would\n> apply to listing and pattern matching. Then people could opt out of\n> the folding behaviors (add, import), while continuing to adopt listing\n> and pattern matching (status, ls, ignore).\n\ncore.ignorecase has a very well-defined meaning: It describes whether the \nworktree lives on a filesystem that is case-insensitive. Perhaps you could \nhelp me understand your case if you gave examples and a use-case? I have a \nslight suspicion that your wish is orthogonal to core.ignorecase.\n\n-- Hannes\n"},{"id":"152373","messageId":"201010032019.09244.j6t@kdbg.org","threadId":"25315","inReplyTo":"AANLkTimH8Lj69qcOCmR3+5HYfgKnr5nyMvQU=9h0=FaB@mail.gmail.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-10-03T18:19:09Z","receivedAt":"2010-10-03T18:19:09Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Sonntag, 3. Oktober 2010, Thomas Adam wrote:\n> Hi --\n>\n> On 3 October 2010 10:56, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> > +       if (ignore_case) {\n> > +               for (;;) {\n> > +                       unsigned char c1 = tolower(*match);\n> > +                       unsigned char c2 = tolower(*name);\n> > +                       if (c1 == '\\0' || is_glob_special(c1))\n> > +                               break;\n> > +                       if (c1 != c2)\n> > +                               return 0;\n> > +                       match++;\n> > +                       name++;\n> > +                       namelen--;\n> > +               }\n> > +       } else {\n> > +               for (;;) {\n> > +                       unsigned char c1 = *match;\n> > +                       unsigned char c2 = *name;\n> > +                       if (c1 == '\\0' || is_glob_special(c1))\n> > +                               break;\n> > +                       if (c1 != c2)\n> > +                               return 0;\n> > +                       match++;\n> > +                       name++;\n> > +                       namelen--;\n> > +               }\n> >        }\n>\n> It's a real shame about the code duplication here.  Can we not avoid\n> it just by doing:\n>\n> unsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n> unisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n>\n> I appreciate that to some it might look like perl golf, but...\n\nIt has been discussed, and IIRC, the concensus was to keep the code \nduplication because this is an inner loop.\n\n-- Hannes\n"},{"id":"152419","messageId":"AANLkTimRa09+nBFTV9OtzKngAb=QrAP550a22S73cW_y@mail.gmail.com","threadId":"25315","inReplyTo":"201010032019.09244.j6t@kdbg.org","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Thomas Adam","fromEmail":"thomas@xteddy.org","sentAt":"2010-10-03T21:59:10Z","receivedAt":"2010-10-03T21:59:10Z","isPatch":true,"sender":{"key":"thomas@xteddy.org","avatar":"https://gravatar.com/avatar/e7256db4738e501e5d2e84f00bb0bd99503165729573848a03330301fc2adc4a?d=mp&s=160"},"body":"Hi --\n\nOn 3 October 2010 19:19, Johannes Sixt <j6t@kdbg.org> wrote:\n> On Sonntag, 3. Oktober 2010, Thomas Adam wrote:\n>> Hi --\n>>\n>> On 3 October 2010 10:56, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> > +       if (ignore_case) {\n>> > +               for (;;) {\n>> > +                       unsigned char c1 = tolower(*match);\n>> > +                       unsigned char c2 = tolower(*name);\n>> > +                       if (c1 == '\\0' || is_glob_special(c1))\n>> > +                               break;\n>> > +                       if (c1 != c2)\n>> > +                               return 0;\n>> > +                       match++;\n>> > +                       name++;\n>> > +                       namelen--;\n>> > +               }\n>> > +       } else {\n>> > +               for (;;) {\n>> > +                       unsigned char c1 = *match;\n>> > +                       unsigned char c2 = *name;\n>> > +                       if (c1 == '\\0' || is_glob_special(c1))\n>> > +                               break;\n>> > +                       if (c1 != c2)\n>> > +                               return 0;\n>> > +                       match++;\n>> > +                       name++;\n>> > +                       namelen--;\n>> > +               }\n>> >        }\n>>\n>> It's a real shame about the code duplication here.  Can we not avoid\n>> it just by doing:\n>>\n>> unsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n>> unisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n>>\n>> I appreciate that to some it might look like perl golf, but...\n>\n> It has been discussed, and IIRC, the concensus was to keep the code\n> duplication because this is an inner loop.\n\nI must have missed the discussion -- but why/how does making it an\ninner-loop somehow prevent it from such an obvious (and readable)\noptimisation, which would have fitted in well in other areas.\n\n-- Thomas Adam\n"},{"id":"152435","messageId":"7vtyl2df5j.fsf@alter.siamese.dyndns.org","threadId":"25315","inReplyTo":"201010031017.35112.j6t@kdbg.org","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-03T23:34:32Z","receivedAt":"2010-10-03T23:34:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Junio, IIRC, the series appeared in next for some time before the 1.7.3 \n> release. Does this imply that you reviewed the series and deemed the \n> implementation sound?\n\nNot really.  I knew that I had an opportunity to rewind whatever crap I\nthrow in 'next' soon, and wanted to see if anybody screams upon stumbling\non breakages ;-)\n"},{"id":"152441","messageId":"1286160491-4026-1-git-send-email-avarab@gmail.com","threadId":"25315","inReplyTo":"201010031958.59482.j6t@kdbg.org","subject":"[PATCH/RFC v4 2/8] Makefile & configure: add a NO_FNMATCH_CASEFOLD flag","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-04T02:48:11Z","receivedAt":"2010-10-04T02:48:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On some platforms (like Solaris) there is a fnmatch, but it doesn't\nsupport the GNU FNM_CASEFOLD extension that's used by the\njj/icase-directory series' fnmatch_icase wrapper.\n\nChange the Makefile so that it's now possible to set\nNO_FNMATCH_CASEFOLD=YesPlease on those systems, and add a configure\nprobe for it.\n\nUnlike the NO_REGEX check we don't add AC_INCLUDES_DEFAULT to our\nheaders. This is because on a GNU system the definition of\nFNM_CASEFOLD in fnmatch.h is guarded by:\n\n    #if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE\n\nOne of the headers AC_INCLUDES_DEFAULT includes ends up defining one\nof those, so if we'd use it we'd always get\nNO_FNMATCH_CASEFOLD=YesPlease on GNU systems, even though they have\nFNM_CASEFOLD.\n\nWhen checking the flags we use:\n\n    ifdef NO_FNMATCH\n    ...\n    else\n    ifdef NO_FNMATCH_CASEFOLD\n    ...\n    endif\n    endif\n\nThe \"else\" so that we don't link against compat/fnmatch/fnmatch.o\ntwice if both NO_FNMATCH and NO_FNMATCH_CASEFOLD are defined.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n\nOn Sun, Oct 3, 2010 at 17:58, Johannes Sixt <j6t@kdbg.org> wrote:\n> I think you should protect against defining both NO_FNMATCH and\n> NO_FNMATCH_CASEFOLD (your version would link compat/fnmatch/fnmatch.o twice\n> in this case):\n\nWell spotted. That's fixed in this version.\n\n Makefile      |   10 ++++++++++\n config.mak.in |    1 +\n configure.ac  |   22 ++++++++++++++++++++++\n 3 files changed, 33 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex f7c4383..7bd0a2b 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -72,6 +72,9 @@ all::\n #\n # Define NO_FNMATCH if you don't have fnmatch in the C library.\n #\n+# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the\n+# FNM_CASEFOLD GNU extension.\n+#\n # Define NO_LIBGEN_H if you don't have libgen.h.\n #\n # Define NEEDS_LIBGEN if your libgen needs -lgen when linking\n@@ -848,6 +851,7 @@ ifeq ($(uname_S),SunOS)\n \tNO_MKDTEMP = YesPlease\n \tNO_MKSTEMPS = YesPlease\n \tNO_REGEX = YesPlease\n+\tNO_FNMATCH_CASEFOLD = YesPlease\n \tifeq ($(uname_R),5.6)\n \t\tSOCKLEN_T = int\n \t\tNO_HSTRERROR = YesPlease\n@@ -1349,6 +1353,12 @@ ifdef NO_FNMATCH\n \tCOMPAT_CFLAGS += -Icompat/fnmatch\n \tCOMPAT_CFLAGS += -DNO_FNMATCH\n \tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n+else\n+ifdef NO_FNMATCH_CASEFOLD\n+\tCOMPAT_CFLAGS += -Icompat/fnmatch\n+\tCOMPAT_CFLAGS += -DNO_FNMATCH_CASEFOLD\n+\tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n+endif\n endif\n ifdef NO_SETENV\n \tCOMPAT_CFLAGS += -DNO_SETENV\ndiff --git a/config.mak.in b/config.mak.in\nindex aaa70a8..56343ba 100644\n--- a/config.mak.in\n+++ b/config.mak.in\n@@ -48,6 +48,7 @@ NO_HSTRERROR=@NO_HSTRERROR@\n NO_STRCASESTR=@NO_STRCASESTR@\n NO_STRTOK_R=@NO_STRTOK_R@\n NO_FNMATCH=@NO_FNMATCH@\n+NO_FNMATCH_CASEFOLD=@NO_FNMATCH_CASEFOLD@\n NO_MEMMEM=@NO_MEMMEM@\n NO_STRLCPY=@NO_STRLCPY@\n NO_UINTMAX_T=@NO_UINTMAX_T@\ndiff --git a/configure.ac b/configure.ac\nindex 7715f6c..6dd9241 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -824,6 +824,28 @@ GIT_CHECK_FUNC(fnmatch,\n [NO_FNMATCH=YesPlease])\n AC_SUBST(NO_FNMATCH)\n #\n+# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the\n+# FNM_CASEFOLD GNU extension.\n+AC_CACHE_CHECK([whether the fnmatch function supports the FNMATCH_CASEFOLD GNU extension],\n+ [ac_cv_c_excellent_fnmatch], [\n+AC_EGREP_CPP(yippeeyeswehaveit,\n+\tAC_LANG_PROGRAM([\n+#include <fnmatch.h>\n+],\n+[#ifdef FNM_CASEFOLD\n+yippeeyeswehaveit\n+#endif\n+]),\n+\t[ac_cv_c_excellent_fnmatch=yes],\n+\t[ac_cv_c_excellent_fnmatch=no])\n+])\n+if test $ac_cv_c_excellent_fnmatch = yes; then\n+\tNO_FNMATCH_CASEFOLD=\n+else\n+\tNO_FNMATCH_CASEFOLD=YesPlease\n+fi\n+AC_SUBST(NO_FNMATCH_CASEFOLD)\n+#\n # Define NO_MEMMEM if you don't have memmem.\n GIT_CHECK_FUNC(memmem,\n [NO_MEMMEM=],\n-- \n1.7.3.159.g610493\n"},{"id":"152485","messageId":"20101004074916.GK24884@burratino","threadId":"25315","inReplyTo":"201010032019.09244.j6t@kdbg.org","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-04T07:49:16Z","receivedAt":"2010-10-04T07:49:16Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Johannes Sixt wrote:\n> On Sonntag, 3. Oktober 2010, Thomas Adam wrote:\n\n>> It's a real shame about the code duplication here.  Can we not avoid\n>> it just by doing:\n>>\n>> unsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n>> unisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n>>\n>> I appreciate that to some it might look like perl golf, but...\n>\n> It has been discussed, and IIRC, the concensus was to keep the code \n> duplication because this is an inner loop.\n\nDid anyone time it?  If it really is not dwarfed by other computation,\nthen how about (warning: ugly!)\n\nstatic inline int step(unsigned char c1, unsigned char c2,\n                       const char **match, const char **name, int *namelen)\n{\n\tif (c1 == '\\0' || is_glob_special(c1))\n\t\treturn 1;\t/* break */\n\tif (c1 != c2)\n\t\treturn 0;\t/* found mismatch! */\n\t(*match)++;\n\t(*name)++;\n\t(*namelen)--;\n\treturn 2;\t/* continue */\n}\n...\n\nint r = 1;\nif (!ignore_case) {\n\twhile ((r = step(*match, *name, &match, &name, &namelen)) == 2)\n\t\t; /* matches so far */\n} else {\n\twhile ((r = step(tolower(*match), tolower(*name),\n\t                 &match, &name, &namelen)) == 2)\n\t\t; /* matches so far */\n}\nif (!r)\t/* found mismatch! */\n\treturn 0;\n"},{"id":"152492","messageId":"AANLkTim=kCH_D23r77FbkSq-8UF38WBPE0CGxRxT8Szf@mail.gmail.com","threadId":"25315","inReplyTo":"20101004074916.GK24884@burratino","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-04T08:02:38Z","receivedAt":"2010-10-04T08:02:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, Oct 4, 2010 at 07:49, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n> Did anyone time it?\n\n> static inline int step(unsigned char c1, unsigned char c2,\n\nIf it hasn't been timed isn't it better to leave it up to the compiler\nwhether it wants to inline that or not?\n"},{"id":"152530","messageId":"AANLkTikgLzczp1Gkmcg2v35oE2bKxBtxY389Z76FJDRz@mail.gmail.com","threadId":"25315","inReplyTo":"20101004074916.GK24884@burratino","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-10-04T14:03:05Z","receivedAt":"2010-10-04T14:03:05Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Mon, Oct 4, 2010 at 9:49 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Johannes Sixt wrote:\n>> On Sonntag, 3. Oktober 2010, Thomas Adam wrote:\n>\n>>> It's a real shame about the code duplication here.  Can we not avoid\n>>> it just by doing:\n>>>\n>>> unsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n>>> unisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n>>>\n>>> I appreciate that to some it might look like perl golf, but...\n>>\n>> It has been discussed, and IIRC, the concensus was to keep the code\n>> duplication because this is an inner loop.\n>\n> Did anyone time it?  If it really is not dwarfed by other computation,\n> then how about (warning: ugly!)\n>\n\nI believe it was timed. I was the one who reacted on this the first\ntime around, and I seem to remember that the performance impact was\nindeed significant. This function is used all the time when updating\nthe index etc IIRC.\n"},{"id":"152536","messageId":"4CA9EBA2.9020401@workspacewhiz.com","threadId":"25315","inReplyTo":"AANLkTikgLzczp1Gkmcg2v35oE2bKxBtxY389Z76FJDRz@mail.gmail.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-04T14:58:42Z","receivedAt":"2010-10-04T14:58:42Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Erik Faye-Lund\nDate: 10/4/2010 8:03 AM\n> On Mon, Oct 4, 2010 at 9:49 AM, Jonathan Nieder<jrnieder@gmail.com>  wrote:\n>> Johannes Sixt wrote:\n>>> On Sonntag, 3. Oktober 2010, Thomas Adam wrote:\n>>>> It's a real shame about the code duplication here.  Can we not avoid\n>>>> it just by doing:\n>>>>\n>>>> unsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n>>>> unisgned char c2 = (ignore_case) ? tolower(*name) : *name;\n>>>>\n>>>> I appreciate that to some it might look like perl golf, but...\n>>> It has been discussed, and IIRC, the concensus was to keep the code\n>>> duplication because this is an inner loop.\n>> Did anyone time it?  If it really is not dwarfed by other computation,\n>> then how about (warning: ugly!)\n>>\n> I believe it was timed. I was the one who reacted on this the first\n> time around, and I seem to remember that the performance impact was\n> indeed significant. This function is used all the time when updating\n> the index etc IIRC.\nIn a good sized repository I have in front of me now, running 'git \nls-files' through this code path results in 705,374 characters being \nprocessed by this body of code.  Given the code listed above, that means \nwe add 1,410,748 additional comparisons that everyone has to suffer \nthrough, even those on a case sensitive file system.  Sure, the code \ncould be optimized to not perform the double comparison, and the \ncompiler may actually perform that optimization.  Still, it is hundreds \nof thousands of additional comparisons and branches that were not there \nbefore.\n\nI'm running on a really, really fast machine, a Xeon X5560.  The \ndifference in time for the above code versus what is in the patch seems \nto average about 0.07 seconds.  Remember, this is an incredibly fast \nmachine, and I imagine it will be worse on machines with slower \nprocessors and less cache.\n\nAs discussed in the original thread (which, I believe, was on the \nmsysGit mailing list), one of Git's features is its speed.  Maintaining \nthat speed in the core.ignorecase=false case is top priority for me, but \nothers with more know how can tell me I'm wrong.\n\nJosh\n"},{"id":"152540","messageId":"201010041802.57398.robin.rosenberg@dewire.com","threadId":"25315","inReplyTo":"1286099806-25774-7-git-send-email-avarab@gmail.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2010-10-04T16:02:56Z","receivedAt":"2010-10-04T16:02:56Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"söndagen den 3 oktober 2010 11.56.44 skrev  Ævar Arnfjörð Bjarmason:\n> From: Joshua Jensen <jjensen@workspacewhiz.com>\n> \n> When mydir/filea.txt is added, mydir/ is renamed to MyDir/, and\n> MyDir/fileb.txt is added, running git ls-files mydir only shows\n> mydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt.\n> Running git ls-files mYdIR shows nothing.\n> \n> With this patch running git ls-files for mydir, MyDir, and mYdIR shows\n> mydir/filea.txt and MyDir/fileb.txt.\n> \n> Wildcards are not handled case insensitively in this patch. Example:\n> MyDir/aBc/file.txt is added. git ls-files MyDir/a* works fine, but git\n> ls-files mydir/a* does not.\n> \n> Signed-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n> Signed-off-by: Johannes Sixt <j6t@kdbg.org>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  dir.c |   38 ++++++++++++++++++++++++++------------\n>  1 files changed, 26 insertions(+), 12 deletions(-)\n> \n> diff --git a/dir.c b/dir.c\n> index cf8f65c..53aa4f3 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -107,16 +107,30 @@ static int match_one(const char *match, const char\n> *name, int namelen) if (!*match)\n>  \t\treturn MATCHED_RECURSIVELY;\n> \n> -\tfor (;;) {\n> -\t\tunsigned char c1 = *match;\n> -\t\tunsigned char c2 = *name;\n> -\t\tif (c1 == '\\0' || is_glob_special(c1))\n> -\t\t\tbreak;\n> -\t\tif (c1 != c2)\n> -\t\t\treturn 0;\n> -\t\tmatch++;\n> -\t\tname++;\n> -\t\tnamelen--;\n> +\tif (ignore_case) {\n> +\t\tfor (;;) {\n> +\t\t\tunsigned char c1 = tolower(*match);\n> +\t\t\tunsigned char c2 = tolower(*name);\n\nIs anyone thinking \"unicode\" around here?\n\n-- robin\n"},{"id":"152541","messageId":"AANLkTin04o5GtYXWgo_Cpw+YNd23kwk7KjvrixjMk8KS@mail.gmail.com","threadId":"25315","inReplyTo":"201010041802.57398.robin.rosenberg@dewire.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-04T16:41:40Z","receivedAt":"2010-10-04T16:41:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, Oct 4, 2010 at 16:02, Robin Rosenberg\n<robin.rosenberg@dewire.com> wrote:\n\n> Is anyone thinking \"unicode\" around here?\n\nThinking yeah, doing the massive work to implement it: no.\n\nIt's much harder when you don't know what encoding the data is in,\nencoding is only by repository convention in Git.\n"},{"id":"152542","messageId":"AANLkTimuJWHRjVNZu-zmUc0jDsK-5QLA+t87sXYnOMhR@mail.gmail.com","threadId":"25315","inReplyTo":"201010041802.57398.robin.rosenberg@dewire.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-10-04T16:48:46Z","receivedAt":"2010-10-04T16:48:46Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Mon, Oct 4, 2010 at 6:02 PM, Robin Rosenberg\n<robin.rosenberg@dewire.com> wrote:\n> söndagen den 3 oktober 2010 11.56.44 skrev  Ævar Arnfjörð Bjarmason:\n>> From: Joshua Jensen <jjensen@workspacewhiz.com>\n>>\n>> When mydir/filea.txt is added, mydir/ is renamed to MyDir/, and\n>> MyDir/fileb.txt is added, running git ls-files mydir only shows\n>> mydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt.\n>> Running git ls-files mYdIR shows nothing.\n>>\n>> With this patch running git ls-files for mydir, MyDir, and mYdIR shows\n>> mydir/filea.txt and MyDir/fileb.txt.\n>>\n>> Wildcards are not handled case insensitively in this patch. Example:\n>> MyDir/aBc/file.txt is added. git ls-files MyDir/a* works fine, but git\n>> ls-files mydir/a* does not.\n>>\n>> Signed-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n>> Signed-off-by: Johannes Sixt <j6t@kdbg.org>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  dir.c |   38 ++++++++++++++++++++++++++------------\n>>  1 files changed, 26 insertions(+), 12 deletions(-)\n>>\n>> diff --git a/dir.c b/dir.c\n>> index cf8f65c..53aa4f3 100644\n>> --- a/dir.c\n>> +++ b/dir.c\n>> @@ -107,16 +107,30 @@ static int match_one(const char *match, const char\n>> *name, int namelen) if (!*match)\n>>               return MATCHED_RECURSIVELY;\n>>\n>> -     for (;;) {\n>> -             unsigned char c1 = *match;\n>> -             unsigned char c2 = *name;\n>> -             if (c1 == '\\0' || is_glob_special(c1))\n>> -                     break;\n>> -             if (c1 != c2)\n>> -                     return 0;\n>> -             match++;\n>> -             name++;\n>> -             namelen--;\n>> +     if (ignore_case) {\n>> +             for (;;) {\n>> +                     unsigned char c1 = tolower(*match);\n>> +                     unsigned char c2 = tolower(*name);\n>\n> Is anyone thinking \"unicode\" around here?\n>\n\nYou're not the first to think about the combination of core.ignorecase\nand unicode, but unfortunately way too few people have.\n\nslow_same_name() (and index_name_exists() by proxy) already does the\nWrong Thing (tm), so the problem is already rooted in the index. The\nconsensus on the msysGit mailing list last time this was brought up\n[1] was simply to ignore the combination of unicode and\ncore.ignorecase, but I'm not sure I'm convinced myself that it's a\ngood idea. We might end up painting our selves further into a corner,\nin the end making it nearly impossible to fix.\n\nOne complicating factor is that Windows' definition of what\ncharacter-pairs compare as identical depends on a table stored\nsomewhere in NTFS[2]. The time your drive was formatted decides what\nthat table looks like, and I haven't been able to retrieve it. This\nmight be going a little too far, as this table is likely to be very\nrarely changed, but I think it's worth noting.\n\n[1]: http://groups.google.com/group/msysgit/browse_thread/thread/675ad16102f6233f/a25cd7bb8dfa2abb#a25cd7bb8dfa2abb\n[2]: http://blogs.msdn.com/b/michkap/archive/2007/10/24/5641619.aspx\n"},{"id":"152543","messageId":"4CAA0598.9080409@workspacewhiz.com","threadId":"25315","inReplyTo":"201010041802.57398.robin.rosenberg@dewire.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-04T16:49:28Z","receivedAt":"2010-10-04T16:49:28Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Robin Rosenberg\nDate: 10/4/2010 10:02 AM\n> söndagen den 3 oktober 2010 11.56.44 skrev  Ævar Arnfjörð Bjarmason:\n>> From: Joshua Jensen<jjensen@workspacewhiz.com>\n>>\n>> When mydir/filea.txt is added, mydir/ is renamed to MyDir/, and\n>> MyDir/fileb.txt is added, running git ls-files mydir only shows\n>> mydir/filea.txt. Running git ls-files MyDir shows MyDir/fileb.txt.\n>> Running git ls-files mYdIR shows nothing.\n>>\n>> With this patch running git ls-files for mydir, MyDir, and mYdIR shows\n>> mydir/filea.txt and MyDir/fileb.txt.\n>> ---\n>>   dir.c |   38 ++++++++++++++++++++++++++------------\n>>   1 files changed, 26 insertions(+), 12 deletions(-)\n>>\n>> diff --git a/dir.c b/dir.c\n>> index cf8f65c..53aa4f3 100644\n>> --- a/dir.c\n>> +++ b/dir.c\n>> @@ -107,16 +107,30 @@ static int match_one(const char *match, const char\n>> +\tif (ignore_case) {\n>> +\t\tfor (;;) {\n>> +\t\t\tunsigned char c1 = tolower(*match);\n>> +\t\t\tunsigned char c2 = tolower(*name);\n> Is anyone thinking \"unicode\" around here?\nOn Windows, Unicode filenames are 16-bit wide characters.  The current \ncode doesn't handle them at all.\n\nI do not know about other file systems and what Git actually handles.  I \nwas under the impression it didn't handle Unicode filenames well in \ngeneral... ?\n\nJosh\n"},{"id":"152545","messageId":"20101004170342.GA5450@burratino","threadId":"25315","inReplyTo":"4CA9EBA2.9020401@workspacewhiz.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-04T17:03:42Z","receivedAt":"2010-10-04T17:03:42Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Joshua Jensen wrote:\n\n> I'm running on a really, really fast machine, a Xeon X5560.  The\n> difference in time for the above code versus what is in the patch\n> seems to average about 0.07 seconds.\n\nThe useful information would be a percentage...\n\n> Remember, this is an\n> incredibly fast machine, and I imagine it will be worse on machines\n> with slower processors and less cache.\n\n... but the subarch and cache size may indeed also be relevant.\n\nHere's a revised version of the ugly speed hack.  Using a separate\nfunction like this is probably a bad idea unless it speeds things up.\n\n/* Returns match length, or -1 for mismatch. */\nstatic inline int match_until_glob_special(const char *match, const char *name,\n\t\t\t\t\t\tint namelen, int ignore_case)\n{\n\tint remaining = namelen;\n\tfor (;;) {\n\t\tunsigned char c1 = (ignore_case) ? tolower(*match) : *match;\n\t\tunsigned char c2 = (ignore_case) ? tolower(*name) : *name;\n\t\tif (c1 == '\\0' || is_glob_special(c1))\n\t\t\treturn namelen - remaining;\n\t\tif (c1 != c2)\n\t\t\treturn -1;\n\t\tmatch++;\n\t\tname++;\n\t\tremaining--;\n\t}\n}\n\n[...]\n\tint matched;\n\n\t/* If the match was just the prefix, we matched */\n\tif (!*match)\n\t\treturn MATCHED_RECURSIVELY;\n\n\t/*\n\t * Note: this funny \"if\" is to ensure each case gets inlined separately.\n\t * Please don't optimize it away unless you've checked the assembler\n\t * to ensure it wasn't helping.\n\t */\n\tif (ignore_case)\n\t\tmatched = match_until_glob_special(match, name, namelen, 1);\n\telse\n\t\tmatched = match_until_glob_special(match, name, namelen, 0);\n\n\tif (matched == -1)\t/* mismatch! */\n\t\treturn 0;\n\n\tmatch += matched;\n\tname += matched;\n\tremaining -= matched;\n"},{"id":"152546","messageId":"20101004170822.GB5450@burratino","threadId":"25315","inReplyTo":"4CAA0598.9080409@workspacewhiz.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-04T17:08:22Z","receivedAt":"2010-10-04T17:08:22Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Joshua Jensen wrote:\n\n> I do not know about other file systems and what Git actually\n> handles.  I was under the impression it didn't handle Unicode\n> filenames well in general... ?\n\nExcept in cases like ignorecase handling, git treats path components\nas arbitrary streams of bytes ('\\0' and path separators are forbidden,\nof course).  It works pretty well if that's what you need.\n"},{"id":"152552","messageId":"AANLkTimiF0UOpvzng95rJcv=+atQ9uh1aHh4YhVjR=gM@mail.gmail.com","threadId":"25315","inReplyTo":"4CAA0598.9080409@workspacewhiz.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-04T17:53:48Z","receivedAt":"2010-10-04T17:53:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, Oct 4, 2010 at 16:49, Joshua Jensen <jjensen@workspacewhiz.com> wrote:\n>> Is anyone thinking \"unicode\" around here?\n>\n> On Windows, Unicode filenames are 16-bit wide characters.  The current code\n> doesn't handle them at all.\n>\n> I do not know about other file systems and what Git actually handles.  I was\n> under the impression it didn't handle Unicode filenames well in general... ?\n\nThe only sane way of doing this sort of thing is to have a defined\n*internal* encoding that gets converted to whatever the native\nencoding is at the input/output points.\n\nSo Git could use Unicode represented by UTF-8, UTF-16 (whatever's\nconvenient) internally, but when you check out files those checked out\nfiles can be in whatever encoding you choose.\n\nSo you could have a UTF-8 repository but check out UTF-8 filenames on\nWindows. I.e. internally we'd have the file:\n\n    æab\n\nRepresented by UTF-8:\n\n    c3 a6 61 62 \\0\n\nBut would check out UTF-16:\n\n    ff fe e6 00 61 00 62 00\n\nThen when you add a new file it'll know it's in UTF-16 and convert it\nto UTF-8 before writing to the repository. All invisible to the user.\n\nPerl handles encoding issues like this, and it's awesome. The only\nthing you have to do is make sure that the system knows the encoding\nof data going into it, and what encoding you want out of it.\n\nBut any implementation of this is far off, and just storing raw byte\nstreams is Good Enough now that almost everyone uses UTF-8 anyway, so\nnobody's seriously worked on this.\n"},{"id":"152573","messageId":"201010042102.31336.j6t@kdbg.org","threadId":"25315","inReplyTo":"201010041802.57398.robin.rosenberg@dewire.com","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-10-04T19:02:31Z","receivedAt":"2010-10-04T19:02:31Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Montag, 4. Oktober 2010, Robin Rosenberg wrote:\n> Is anyone thinking \"unicode\" around here?\n\nMy recommendation these days is that you should not use git if you care about \nUnicode filenames: git is tied to POSIX in this regard, which defines \nfilenames as streams of *bytes*.\n\n-- Hannes\n"},{"id":"152578","messageId":"AANLkTikdiLRDBchYiZedATPS5ct0nSa6CahxuZiTk3x0@mail.gmail.com","threadId":"25315","inReplyTo":"201010042102.31336.j6t@kdbg.org","subject":"Re: [PATCH/RFC v3 6/8] Add case insensitivity support when using git ls-files","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-10-04T19:17:41Z","receivedAt":"2010-10-04T19:17:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, Oct 4, 2010 at 19:02, Johannes Sixt <j6t@kdbg.org> wrote:\n> On Montag, 4. Oktober 2010, Robin Rosenberg wrote:\n>> Is anyone thinking \"unicode\" around here?\n>\n> My recommendation these days is that you should not use git if you care about\n> Unicode filenames: git is tied to POSIX in this regard, which defines\n> filenames as streams of *bytes*.\n\nA SCM is all about giving meaning to streams of bytes. Just because\nPOSIX only says that filenames are \\0-delimited blobs that doesn't\nmean you can't have some annotation elsewhere that says \"hey, these\nblobs are in $encoding\".\n\n<insert another disclaimer here about implementing this being a huge\n task, but I'm just saying...>\n"},{"id":"152806","messageId":"AANLkTi=tHaCki5yWQW_iQ21Y8ee5G2rNBzX8Pf-nZYAp@mail.gmail.com","threadId":"25315","inReplyTo":"201010032012.01678.j6t@kdbg.org","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Robert Buck","fromEmail":"buck.robert.j@gmail.com","sentAt":"2010-10-06T22:04:41Z","receivedAt":"2010-10-06T22:04:41Z","isPatch":true,"sender":{"key":"buck.robert.j@gmail.com","avatar":"https://gravatar.com/avatar/1686742e8ac2595378aac67f26fd638ddaf494194f9af0cb6082c4a7eca1a366?d=mp&s=160"},"body":"Hello Johannes,\n\nHere is the use case I was thinking of.\n\nLet's say I want to have .gitignore be case insensitive with respect\nto matches so I can simplify the file by not having [D][d]ebug sorts\nof messes. But let's say I also want to support files whose names only\ndiffer by case (just like Unix supports). Can your current patch\nseries support this? Does the current patch series break this?\n\nCould you share how this would or would not work, and if not, how you\nmight accomplish this?\n\nThanks,\n\nBob\n\nOn Sun, Oct 3, 2010 at 2:12 PM, Johannes Sixt <j6t@kdbg.org> wrote:\n> On Sonntag, 3. Oktober 2010, Robert Buck wrote:\n>> So I could we please separate the behaviors that change intent\n>> (folding) from the behaviors that merely alter how things are\n>> displayed (listing) by splitting this into two separate properties?\n>> For example,\n>>\n>> core.casepreserving=true|false\n>> core.caseinsensitive=true|false\n>>\n>> The former property would control folding, the latter property would\n>> apply to listing and pattern matching. Then people could opt out of\n>> the folding behaviors (add, import), while continuing to adopt listing\n>> and pattern matching (status, ls, ignore).\n>\n> core.ignorecase has a very well-defined meaning: It describes whether the\n> worktree lives on a filesystem that is case-insensitive. Perhaps you could\n> help me understand your case if you gave examples and a use-case? I have a\n> slight suspicion that your wish is orthogonal to core.ignorecase.\n>\n> -- Hannes\n>\n"},{"id":"152811","messageId":"4CACFC5A.5050706@workspacewhiz.com","threadId":"25315","inReplyTo":"AANLkTi=tHaCki5yWQW_iQ21Y8ee5G2rNBzX8Pf-nZYAp@mail.gmail.com","subject":"Re: [PATCH v2 0/6] Extensions of core.ignorecase=true support","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-06T22:46:50Z","receivedAt":"2010-10-06T22:46:50Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Robert Buck\nDate: 10/6/2010 4:04 PM\n> Let's say I want to have .gitignore be case insensitive with respect\n> to matches so I can simplify the file by not having [D][d]ebug sorts\n> of messes. But let's say I also want to support files whose names only\n> differ by case (just like Unix supports). Can your current patch\n> series support this? Does the current patch series break this?\n>\n> Could you share how this would or would not work, and if not, how you\n> might accomplish this?\nWith this patch series, you are either on a case sensitive file system \n(core.ignorecase = false) or a case insensitive file system \n(core.ignorecase = true).\n\nThere is no specific configuration for .gitignore case insensitivity.  \nIt only pays attention to core.ignorecase.\n\nThis is something that could be added, but I don't fully understand the \nneed.  On case sensitive file systems, the case of the resultant \nfilename is guaranteed.  If you have both a Debug/ and debug/ directory, \nI would expect two entries in the .gitignore.\n\n?\n\nJosh\n"},{"id":"152839","messageId":"7vzkuqy718.fsf@alter.siamese.dyndns.org","threadId":"25315","inReplyTo":"4CA847D5.4000903@workspacewhiz.com","subject":"Re: [PATCH v2 1/6] Add string comparison functions that respect the ignore_case variable.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-07T04:13:23Z","receivedAt":"2010-10-07T04:13:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Joshua Jensen <jjensen@workspacewhiz.com> writes:\n\n> In any case, I'd like to find a solution to get this series working\n> for everyone.  I've been out of commission for a month (deploying Git\n> to 80+ programmers at an organization, by the way), but I'm back now\n> and can work this until it is complete.\n\nThanks; I'll queue Ævar's v3 (with [v4 2/8]) for now.\n"},{"id":"152845","messageId":"4CAD5F14.3010903@workspacewhiz.com","threadId":"25315","inReplyTo":"7vzkuqy718.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 1/6] Add string comparison functions that respect the ignore_case variable.","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-10-07T05:48:04Z","receivedAt":"2010-10-07T05:48:04Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Junio C Hamano\nDate: 10/6/2010 10:13 PM\n> Joshua Jensen<jjensen@workspacewhiz.com>  writes:\n>> In any case, I'd like to find a solution to get this series working\n>> for everyone.  I've been out of commission for a month (deploying Git\n>> to 80+ programmers at an organization, by the way), but I'm back now\n>> and can work this until it is complete.\n> Thanks; I'll queue Ævar's v3 (with [v4 2/8]) for now.\nThat sounds great!\n\nJosh\n"}]}