{"thread":{"id":"23863","subject":"[PATCH 5/7] Add support for case insensitive directory and file lookups to git log","startedAt":"2010-05-21T04:50:28Z","lastAt":"2010-05-26T18:26:02Z","messageCount":9,"participants":["Joshua Jensen"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"142009","messageId":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":null,"subject":"[PATCH 0/7] Various updates to make core.ignorecase=true work better","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:28Z","receivedAt":"2010-05-21T04:50:28Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"This is a follow up patch to one I posted mid last year specifically for \nmaking .gitignore entries be processed in a case insensitive manner. I \nhave used the patch with success since then, but I was unable to make \nthe updates requested by list members. \n\nOver the past month, I have been able to clean up the code and extend \nthe core.ignorecase=true support to better handle git status, ls-files, \nlog, add, and fast-import. \n\ngit status and add both use an update made to name-hash.c where \ndirectories, specifically names with a trailing slash, can be looked up \nin a case insensitive manner. After trying a myriad of solutions, this \nseemed to be the cleanest. Does anyone see a problem with embedding the \ndirectory names in the same hash as the file names? I couldn't find one, \nespecially since I append a slash to each directory name. \n\nThe new directory_exists_in_index_icase() duplicates some of the \nfunctionality in directory_exists_in_index(). I don't understand some of \nthe functionality I just mindlessly cloned. Can anyone clue me in on \nwhat directory_exists_in_index() achieves in the case of S_ISGITLINK()? \n\nUpdating match_one() bought case insensitive matching support for git \nls-files? Are there other side effects I haven't found yet? \n\nThe git add path case folding functionality is a somewhat radical \ndeparture from what Git does now. It is described in detail in patch 6. \nDoes anyone have any concerns? \n\n\nJoshua Jensen (7):\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  Add support for case insensitive directory and file lookups to git\n    log\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 dir.c         |  110 +++++++++++++++++++++++++++++++++++++++++++++++----------\n dir.h         |    5 +++\n fast-import.c |    3 +-\n name-hash.c   |   44 ++++++++++++++++++++++-\n read-cache.c  |   16 ++++++++\n tree-diff.c   |    9 +++--\n 6 files changed, 162 insertions(+), 25 deletions(-)\n"},{"id":"142007","messageId":"1274417435-2344-2-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 1/7] Add string comparison functions that respect the ignore_case variable.","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:29Z","receivedAt":"2010-05-21T04:50:29Z","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 |   35 +++++++++++++++++++++++++++++++++++\n dir.h |    5 +++++\n 2 files changed, 40 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex cb83332..21d2104 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -18,6 +18,41 @@ 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+int memcmp_icase(const char *a, const char *b, size_t count)\n+{\n+\tif (ignore_case) {\n+\t\tint lowera = 0;\n+\t\tint lowerb = 0;\n+\t\twhile (--count) {\n+\t\t\tlowera = tolower(*a++);\n+\t\t\tlowerb = tolower(*b++);\n+\t\t\tif (lowera != lowerb)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\treturn lowera - lowerb;\n+\n+\t\treturn 0;\n+\t} else {\n+\t\treturn memcmp(a, b, count);\n+\t}\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 3bead5f..aced818 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -100,4 +100,9 @@ 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+extern int memcmp_icase(const char *a, const char *b, size_t count);\n+\n #endif\n-- \n1.7.1.1930.gca7dd4\n"},{"id":"142010","messageId":"1274417435-2344-3-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 2/7] Case insensitivity support for .gitignore via core.ignorecase","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:30Z","receivedAt":"2010-05-21T04:50:30Z","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 21d2104..a19b7ab 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -409,14 +409,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@@ -431,14 +431,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.1.1930.gca7dd4\n"},{"id":"142008","messageId":"1274417435-2344-4-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 3/7] Add case insensitivity support for directories when using git status","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:31Z","receivedAt":"2010-05-21T04:50:31Z","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       |   25 ++++++++++++++++++++++++-\n name-hash.c |   44 +++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 67 insertions(+), 2 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex a19b7ab..c861f3e 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -503,6 +503,24 @@ enum exist_status {\n \tindex_gitdir,\n };\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+\tif (!ce)\n+\t\treturn index_nonexistent;\n+\n+\tif (!strncmp_icase(ce->name, dirname, len)) {\n+\t\tunsigned char endchar = ce->name[len];\n+\t\tif (endchar <= '/') {\n+\t\t\tif (endchar == '/')\n+\t\t\t\treturn index_directory;\n+\t\t\tif (!endchar && S_ISGITLINK(ce->ce_mode))\n+\t\t\t\treturn index_gitdir;\n+\t\t}\n+\t}\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@@ -512,7 +530,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..b10b5b1 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -32,6 +32,30 @@ 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/* throw each directory component in the hash for quick lookup during a git status */\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 +71,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 +124,22 @@ 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+\t}\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-- \n1.7.1.1930.gca7dd4\n"},{"id":"142013","messageId":"1274417435-2344-5-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 4/7] Add case insensitivity support when using git ls-files","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:32Z","receivedAt":"2010-05-21T04:50:32Z","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 c861f3e..d67ec68 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -126,16 +126,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@@ -144,8 +158,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.1.1930.gca7dd4\n"},{"id":"142006","messageId":"1274417435-2344-6-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 5/7] Add support for case insensitive directory and file lookups to git log","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:33Z","receivedAt":"2010-05-21T04:50:33Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"This patch also affects any other commands that use tree-diff.c.\n\nSigned-off-by: Joshua Jensen <jjensen@workspacewhiz.com>\n---\n tree-diff.c |    9 +++++----\n 1 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex fe9f52c..5110980 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -5,6 +5,7 @@\n #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"tree.h\"\n+#include \"dir.h\"\n \n static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)\n {\n@@ -114,7 +115,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \n \t\tif (baselen >= matchlen) {\n \t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n+\t\t\tif (strncmp_icase(base, match, matchlen))\n \t\t\t\tcontinue;\n \n \t\t\t/*\n@@ -131,7 +132,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t}\n \n \t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n+\t\tif (strncmp_icase(base, match, baselen))\n \t\t\tcontinue;\n \n \t\tmatch += baselen;\n@@ -147,7 +148,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * Does match sort strictly earlier than path\n \t\t\t * with their common parts?\n \t\t\t */\n-\t\t\tm = strncmp(match, path,\n+\t\t\tm = strncmp_icase(match, path,\n \t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n \t\t\tif (m < 0)\n \t\t\t\tcontinue;\n@@ -183,7 +184,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * we cheated and did not do strncmp(), so we do\n \t\t\t * that here.\n \t\t\t */\n-\t\t\tm = strncmp(match, path, pathlen);\n+\t\t\tm = strncmp_icase(match, path, pathlen);\n \n \t\t/*\n \t\t * If common part matched earlier then it is a hit,\n-- \n1.7.1.1930.gca7dd4\n"},{"id":"142011","messageId":"1274417435-2344-7-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 6/7] Support case folding for git add when core.ignorecase=true","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:34Z","receivedAt":"2010-05-21T04:50:34Z","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 |   16 ++++++++++++++++\n 1 files changed, 16 insertions(+), 0 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex f1f789b..b3954d5 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -608,6 +608,22 @@ 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+\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}\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.1.1930.gca7dd4\n"},{"id":"142012","messageId":"1274417435-2344-8-git-send-email-jjensen@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"[PATCH 7/7] Support case folding in git fast-import when core.ignorecase=true","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-21T04:50:35Z","receivedAt":"2010-05-21T04:50:35Z","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 |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 352e2e3..2279276 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@@ -1459,7 +1460,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-- \n1.7.1.1930.gca7dd4\n"},{"id":"142386","messageId":"4BFD67BA.2050105@workspacewhiz.com","threadId":"23863","inReplyTo":"1274417435-2344-1-git-send-email-jjensen@workspacewhiz.com","subject":"Re: [PATCH 0/7] Various updates to make core.ignorecase=true work better","fromName":"Joshua Jensen","fromEmail":"jjensen@workspacewhiz.com","sentAt":"2010-05-26T18:26:02Z","receivedAt":"2010-05-26T18:26:02Z","isPatch":true,"sender":{"key":"jjensen@workspacewhiz.com","avatar":"https://avatars.githubusercontent.com/u/111687?v=4"},"body":"  ----- Original Message -----\nFrom: Joshua Jensen\nDate: 5/20/2010 10:50 PM\n> Joshua Jensen (7):\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>    Add support for case insensitive directory and file lookups to git\n>      log\n>    Support case folding for git add when core.ignorecase=true\n>    Support case folding in git fast-import when core.ignorecase=true\nWould this patch series be better sent to the msysGit mailing list, \ngiven that it addresses Windows (and Mac OS X, I suppose) case \npreserving but case insensitive file system issues?  I posted here \nfirst, because it builds on some core.ignorecase functionality Linus wrote.\n\nThanks.\n\nJosh\n"}]}