{"thread":{"id":"34944","subject":"[PATCH v2 0/4] stop storing trailing slash in dir-hash","startedAt":"2013-09-17T07:06:13Z","lastAt":"2013-09-17T17:11:25Z","messageCount":6,"participants":["Eric Sunshine","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":4},"messages":[{"id":"227725","messageId":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","threadId":"34944","inReplyTo":null,"subject":"[PATCH v2 0/4] stop storing trailing slash in dir-hash","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-17T07:06:13Z","receivedAt":"2013-09-17T07:06:13Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"This series changes name-hash to stop storing the (redundant) trailing\nslash with index_state.dir_hash entries. As an intentional side-effect,\nthe series fixes [1] in a cleaner way (suggested by Junio [2]) than\neither [3] (680be044 in master) or [4].\n\nChanges since v1 [5]:\n\n* Add index_file_exists() as complement of index_dir_exists() introduced\n  in v1 rather than changing the behavior of index_name_exists() to\n  check only for files. To avoid disturbing current or future in-flight\n  topics, index_name_exists() is retained (suggested by Junio [6]) as a\n  thin wrapper dispatching either to index_file_exists() or\n  index_dir_exists().\n\n* Split v1 patch 1 into v2 patches 1 & 2 to ease review. (This is\n  possible now that index_name_exists() retains its original behavior.)\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/232727\n[2]: http://thread.gmane.org/gmane.comp.version-control.git/232727/focus=232813\n[3]: http://thread.gmane.org/gmane.comp.version-control.git/232796\n[4]: http://thread.gmane.org/gmane.comp.version-control.git/232833\n[5]: http://thread.gmane.org/gmane.comp.version-control.git/234743\n[6]: http://article.gmane.org/gmane.comp.version-control.git/234761\n\nEric Sunshine (4):\n  name-hash: refactor polymorphic index_name_exists()\n  employ new explicit \"exists in index?\" API\n  name-hash: stop storing trailing '/' on paths in index_state.dir_hash\n  dir: revert work-around for retired dangerous behavior\n\n cache.h        |  4 ++++\n dir.c          | 28 ++++++++-------------------\n name-hash.c    | 61 ++++++++++++++++++++++++++++++++--------------------------\n read-cache.c   |  4 ++--\n unpack-trees.c |  4 ++--\n 5 files changed, 50 insertions(+), 51 deletions(-)\n\n-- \n1.8.4.535.g7b94f8e\n"},{"id":"227727","messageId":"1379401577-36799-2-git-send-email-sunshine@sunshineco.com","threadId":"34944","inReplyTo":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","subject":"[PATCH v2 1/4] name-hash: refactor polymorphic index_name_exists()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-17T07:06:14Z","receivedAt":"2013-09-17T07:06:14Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"Depending upon the absence or presence of a trailing '/' on the incoming\npathname, index_name_exists() checks either if a file is present in the\nindex or if a directory is represented within the index. Each caller\nexplicitly chooses the mode of operation by adding or removing a\ntrailing '/' before invoking index_name_exists().\n\nSince these two modes of operations are disjoint and have no code in\ncommon (one searches index_state.name_hash; the other dir_hash), they\ncan be represented more naturally as distinct functions: one to search\nfor a file, and one for a directory.\n\nSplitting index searching into two functions relieves callers of the\nartificial burden of having to add or remove a slash to select the mode\nof operation; instead they just call the desired function. A subsequent\npatch will take advantage of this benefit in order to eliminate the\nrequirement that the incoming pathname for a directory search must have\na trailing slash.\n\n(In order to avoid disturbing in-flight topics, index_name_exists() is\nretained as a thin wrapper dispatching either to index_dir_exists() or\nindex_file_exists().)\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\n---\n cache.h     |  4 ++++\n name-hash.c | 54 ++++++++++++++++++++++++++++++------------------------\n 2 files changed, 34 insertions(+), 24 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex a47b9c0..038afe1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -314,6 +314,8 @@ extern void free_name_hash(struct index_state *istate);\n #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)\n #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))\n #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))\n+#define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))\n+#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))\n #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))\n #define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))\n #define resolve_undo_clear() resolve_undo_clear_index(&the_index)\n@@ -463,6 +465,8 @@ extern int write_index(struct index_state *, int newfd);\n extern int discard_index(struct index_state *);\n extern int unmerged_index(const struct index_state *);\n extern int verify_path(const char *path);\n+extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);\n+extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);\n extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);\n extern int index_name_pos(const struct index_state *, const char *name, int namelen);\n #define ADD_CACHE_OK_TO_ADD 1\t\t/* Ok to add */\ndiff --git a/name-hash.c b/name-hash.c\nindex 617c86c..f06b049 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -222,7 +222,29 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen\n \treturn slow_same_name(name, namelen, ce->name, len);\n }\n \n-struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)\n+struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen)\n+{\n+\tstruct cache_entry *ce;\n+\tstruct dir_entry *dir;\n+\n+\tlazy_init_name_hash(istate);\n+\tdir = find_dir_entry(istate, name, namelen);\n+\tif (dir && dir->nr)\n+\t\treturn dir->ce;\n+\n+\t/*\n+\t * It might be a submodule. Unlike plain directories, which are stored\n+\t * in the dir-hash, submodules are stored in the name-hash, so check\n+\t * there, as well.\n+\t */\n+\tce = index_file_exists(istate, name, namelen - 1, 1);\n+\tif (ce && S_ISGITLINK(ce->ce_mode))\n+\t\treturn ce;\n+\n+\treturn NULL;\n+}\n+\n+struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tunsigned int hash = hash_name(name, namelen);\n \tstruct cache_entry *ce;\n@@ -237,32 +259,16 @@ 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 * When looking for a directory (trailing '/'), it might be a\n-\t * submodule or a directory. 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 a separate hash\n-\t * table *with* their closing slash.\n-\t *\n-\t * The side effect of this storage technique is we have need to\n-\t * lookup the directory in a separate hash table, and if not found\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\tstruct dir_entry *dir = find_dir_entry(istate, name, namelen);\n-\t\tif (dir && dir->nr)\n-\t\t\treturn dir->ce;\n-\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 \n+struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)\n+{\n+\tif (namelen > 0 && name[namelen - 1] == '/')\n+\t\treturn index_dir_exists(istate, name, namelen);\n+\treturn index_file_exists(istate, name, namelen, icase);\n+}\n+\n static int free_dir_entry(void *entry, void *unused)\n {\n \tstruct dir_entry *dir = entry;\n-- \n1.8.4.535.g7b94f8e\n"},{"id":"227726","messageId":"1379401577-36799-3-git-send-email-sunshine@sunshineco.com","threadId":"34944","inReplyTo":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","subject":"[PATCH v2 2/4] employ new explicit \"exists in index?\" API","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-17T07:06:15Z","receivedAt":"2013-09-17T07:06:15Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"Each caller of index_name_exists() knows whether it is looking for a\ndirectory or a file, and can avoid the unnecessary indirection of\nindex_name_exists() by instead calling index_dir_exists() or\nindex_file_exists() directly.\n\nInvoking the appropriate search function explicitly will allow a\nsubsequent patch to relieve callers of the artificial burden of having\nto add a trailing '/' to the pathname given to index_dir_exists().\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\n---\n dir.c          | 10 +++++-----\n read-cache.c   |  4 ++--\n unpack-trees.c |  4 ++--\n 3 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex b439ff0..a8401b9 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -860,7 +860,7 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)\n \n static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)\n {\n-\tif (cache_name_exists(pathname, len, ignore_case))\n+\tif (cache_file_exists(pathname, len, ignore_case))\n \t\treturn NULL;\n \n \tALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);\n@@ -885,11 +885,11 @@ enum exist_status {\n /*\n  * Do not use the alphabetically sorted index to look up\n  * the directory name; instead, use the case insensitive\n- * name hash.\n+ * directory hash.\n  */\n static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)\n {\n-\tconst struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);\n+\tconst struct cache_entry *ce = cache_dir_exists(dirname, len + 1);\n \tunsigned char endchar;\n \n \tif (!ce)\n@@ -1071,7 +1071,7 @@ static int get_index_dtype(const char *path, int len)\n \tint pos;\n \tconst struct cache_entry *ce;\n \n-\tce = cache_name_exists(path, len, 0);\n+\tce = cache_file_exists(path, len, 0);\n \tif (ce) {\n \t\tif (!ce_uptodate(ce))\n \t\t\treturn DT_UNKNOWN;\n@@ -1131,7 +1131,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t\t\t\t\t  int dtype, struct dirent *de)\n {\n \tint exclude;\n-\tint has_path_in_index = !!cache_name_exists(path->buf, path->len, ignore_case);\n+\tint has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);\n \n \tif (dtype == DT_UNKNOWN)\n \t\tdtype = get_dtype(de, path->buf, path->len);\ndiff --git a/read-cache.c b/read-cache.c\nindex 885943a..b8d3759 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -643,7 +643,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\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(istate, ce->name, ptr - ce->name, ignore_case);\n+\t\t\t\tfoundce = index_dir_exists(istate, ce->name, ptr - ce->name);\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@@ -652,7 +652,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \t\t}\n \t}\n \n-\talias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);\n+\talias = index_file_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 \t\tfree(ce);\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 1a61e6f..35cb05e 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1357,7 +1357,7 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le\n {\n \tconst struct cache_entry *src;\n \n-\tsrc = index_name_exists(o->src_index, name, len, 1);\n+\tsrc = index_file_exists(o->src_index, name, len, 1);\n \treturn src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n }\n \n@@ -1403,7 +1403,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t * delete this path, which is in a subdirectory that\n \t * is being replaced with a blob.\n \t */\n-\tresult = index_name_exists(&o->result, name, len, 0);\n+\tresult = index_file_exists(&o->result, name, len, 0);\n \tif (result) {\n \t\tif (result->ce_flags & CE_REMOVE)\n \t\t\treturn 0;\n-- \n1.8.4.535.g7b94f8e\n"},{"id":"227728","messageId":"1379401577-36799-4-git-send-email-sunshine@sunshineco.com","threadId":"34944","inReplyTo":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","subject":"[PATCH v2 3/4] name-hash: stop storing trailing '/' on paths in index_state.dir_hash","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-17T07:06:16Z","receivedAt":"2013-09-17T07:06:16Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"When 5102c617 (Add case insensitivity support for directories when using\ngit status, 2010-10-03) added directories to the name-hash there was\nonly a single hash table in which both real cache entries and leading\ndirectory prefixes were registered. To distinguish between the two types\nof entries, directories were stored with a trailing '/'.\n\n2092678c (name-hash.c: fix endless loop with core.ignorecase=true,\n2013-02-28), however, moved directories to a separate hash table\n(index_state.dir_hash) but retained the (now) redundant trailing '/',\nthus callers continue to bear the burden of ensuring the slash's\npresence before searching the index for a directory. Eliminate this\nredundancy by storing paths in the dir-hash without the trailing '/'.\n\nAn important benefit of this change is that it eliminates undocumented\nand dangerous behavior of dir.c:directory_exists_in_index_icase() in\nwhich it assumes not only that it can validly access one character\nbeyond the end of its incoming directory argument, but also that that\ncharacter will unconditionally be a '/'. This perilous behavior was\n\"tolerated\" because the string passed in by its lone caller always had a\n'/' in that position, however, things broke [1] when 2eac2a4c (ls-files\n-k: a directory only can be killed if the index has a non-directory,\n2013-08-15) added a new caller which failed to respect the undocumented\nassumption.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/232727\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\n---\n dir.c        |  2 +-\n name-hash.c  | 11 ++++++-----\n read-cache.c |  2 +-\n 3 files changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex a8401b9..fccd479 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -889,7 +889,7 @@ enum exist_status {\n  */\n static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)\n {\n-\tconst struct cache_entry *ce = cache_dir_exists(dirname, len + 1);\n+\tconst struct cache_entry *ce = cache_dir_exists(dirname, len);\n \tunsigned char endchar;\n \n \tif (!ce)\ndiff --git a/name-hash.c b/name-hash.c\nindex f06b049..e5b6e1a 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -58,9 +58,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\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 * during a git status. Directory components are stored without 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 * reach this point, because they are stored\n \t * in index_state.name_hash (as ordinary cache_entries).\n \t *\n \t * Note that the cache_entry stored with the dir_entry merely\n@@ -78,6 +78,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \t\tnamelen--;\n \tif (namelen <= 0)\n \t\treturn NULL;\n+\tnamelen--;\n \n \t/* lookup existing entry for that directory */\n \tdir = find_dir_entry(istate, ce->name, namelen);\n@@ -97,7 +98,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \t\t}\n \n \t\t/* recursively add missing parent directories */\n-\t\tdir->parent = hash_dir_entry(istate, ce, namelen - 1);\n+\t\tdir->parent = hash_dir_entry(istate, ce, namelen);\n \t}\n \treturn dir;\n }\n@@ -237,7 +238,7 @@ struct cache_entry *index_dir_exists(struct index_state *istate, const char *nam\n \t * in the dir-hash, submodules are stored in the name-hash, so check\n \t * there, as well.\n \t */\n-\tce = index_file_exists(istate, name, namelen - 1, 1);\n+\tce = index_file_exists(istate, name, namelen, 1);\n \tif (ce && S_ISGITLINK(ce->ce_mode))\n \t\treturn ce;\n \n@@ -265,7 +266,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na\n struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)\n {\n \tif (namelen > 0 && name[namelen - 1] == '/')\n-\t\treturn index_dir_exists(istate, name, namelen);\n+\t\treturn index_dir_exists(istate, name, namelen - 1);\n \treturn index_file_exists(istate, name, namelen, icase);\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex b8d3759..e25de32 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -643,7 +643,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\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_dir_exists(istate, ce->name, ptr - ce->name);\n+\t\t\t\tfoundce = index_dir_exists(istate, ce->name, ptr - ce->name - 1);\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-- \n1.8.4.535.g7b94f8e\n"},{"id":"227729","messageId":"1379401577-36799-5-git-send-email-sunshine@sunshineco.com","threadId":"34944","inReplyTo":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","subject":"[PATCH v2 4/4] dir: revert work-around for retired dangerous behavior","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-17T07:06:17Z","receivedAt":"2013-09-17T07:06:17Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"directory_exists_in_index_icase() dangerously assumed that it could\naccess one character beyond the end of its directory argument, and that\nthat character would unconditionally be '/'.  2eac2a4c (ls-files -k: a\ndirectory only can be killed if the index has a non-directory,\n2013-08-15) added a caller which did not respect this undocumented\nassumption, and 680be044 (dir.c::test_one_path(): work around\ndirectory_exists_in_index_icase() breakage, 2013-08-23) added a\nwork-around which temporarily appends a '/' before invoking\ndirectory_exists_in_index_icase().\n\nSince the dangerous behavior of directory_exists_in_index_icase() has\nbeen eliminated, the work-around is now redundant, so retire it (but not\nthe tests added by the same commit).\n\nSigned-off-by: Eric Sunshine <sunshine@sunshineco.com>\n---\n dir.c | 18 +++---------------\n 1 file changed, 3 insertions(+), 15 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex fccd479..23b6de4 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1160,21 +1160,9 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t */\n \tif ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&\n \t    (dtype == DT_DIR) &&\n-\t    !has_path_in_index) {\n-\t\t/*\n-\t\t * NEEDSWORK: directory_exists_in_index_icase()\n-\t\t * assumes that one byte past the given path is\n-\t\t * readable and has '/', which needs to be fixed, but\n-\t\t * until then, work it around in the caller.\n-\t\t */\n-\t\tstrbuf_addch(path, '/');\n-\t\tif (directory_exists_in_index(path->buf, path->len - 1) ==\n-\t\t    index_nonexistent) {\n-\t\t\tstrbuf_setlen(path, path->len - 1);\n-\t\t\treturn path_none;\n-\t\t}\n-\t\tstrbuf_setlen(path, path->len - 1);\n-\t}\n+\t    !has_path_in_index &&\n+\t    (directory_exists_in_index(path->buf, path->len) == index_nonexistent))\n+\t\treturn path_none;\n \n \texclude = is_excluded(dir, path->buf, &dtype);\n \n-- \n1.8.4.535.g7b94f8e\n"},{"id":"227762","messageId":"xmqqk3ifz83m.fsf@gitster.dls.corp.google.com","threadId":"34944","inReplyTo":"1379401577-36799-1-git-send-email-sunshine@sunshineco.com","subject":"Re: [PATCH v2 0/4] stop storing trailing slash in dir-hash","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-09-17T17:11:25Z","receivedAt":"2013-09-17T17:11:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> * Split v1 patch 1 into v2 patches 1 & 2 to ease review. (This is\n>   possible now that index_name_exists() retains its original behavior.)\n\nIt really shows in [PATCH 2/4] that illustrates which callers were\ndepending on the old calling convention; I like it.\n\nThanks.\n"}]}