{"thread":{"id":"41238","subject":"Minor bug, git ls-files -o aborts because of broken submodules","startedAt":"2016-01-22T09:17:29Z","lastAt":"2016-01-25T13:13:21Z","messageCount":9,"participants":["Duy Nguyen","Jeff King","Stefan Beller","Andreas Krey"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"276537","messageId":"CACsJy8BpCc6sNKUs3TsMnA_8dk+uFvZy1T_UmfQMxcm2bpg2uw@mail.gmail.com","threadId":"41238","inReplyTo":null,"subject":"Minor bug, git ls-files -o aborts because of broken submodules","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-22T09:17:29Z","receivedAt":"2016-01-22T09:17:29Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"$ git init abc\n$ cd abc\n$ mkdir def\n$ echo 'gitdir: blah blah' >def/.git\n$ git ls-files -o\nfatal: Not a git repository: def/blah blah\n\nIf some directory looks like a submodule but turns out not, that's not\na fatal error. The stack trace is something like this. I suspect\ndo_submodule_path should use the gently version..\n\n#1  0x0000000000588a78 in die\n#2  0x0000000000558ded in read_gitfile_gently\n#3  0x000000000051e2f6 in do_submodule_path\n#4  0x000000000051e484 in git_pathdup_submodule\n#5  0x00000000005340ac in resolve_gitlink_ref_recursive\n#6  0x00000000005342cf in resolve_gitlink_ref\n#7  0x00000000004dd20d in treat_directory\n#8  0x00000000004dd760 in treat_one_path\n#9  0x00000000004dd971 in treat_path\n#10 0x00000000004de038 in read_directory_recursive\n-- \nDuy\n"},{"id":"276575","messageId":"20160122211803.GA17071@sigill.intra.peff.net","threadId":"41238","inReplyTo":"CACsJy8BpCc6sNKUs3TsMnA_8dk+uFvZy1T_UmfQMxcm2bpg2uw@mail.gmail.com","subject":"Re: Minor bug, git ls-files -o aborts because of broken submodules","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T21:18:03Z","receivedAt":"2016-01-22T21:18:03Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 22, 2016 at 04:17:29PM +0700, Duy Nguyen wrote:\n\n> $ git init abc\n> $ cd abc\n> $ mkdir def\n> $ echo 'gitdir: blah blah' >def/.git\n> $ git ls-files -o\n> fatal: Not a git repository: def/blah blah\n> \n> If some directory looks like a submodule but turns out not, that's not\n> a fatal error. The stack trace is something like this. I suspect\n> do_submodule_path should use the gently version..\n> \n> #1  0x0000000000588a78 in die\n> #2  0x0000000000558ded in read_gitfile_gently\n> #3  0x000000000051e2f6 in do_submodule_path\n> #4  0x000000000051e484 in git_pathdup_submodule\n> #5  0x00000000005340ac in resolve_gitlink_ref_recursive\n> #6  0x00000000005342cf in resolve_gitlink_ref\n> #7  0x00000000004dd20d in treat_directory\n> #8  0x00000000004dd760 in treat_one_path\n> #9  0x00000000004dd971 in treat_path\n> #10 0x00000000004de038 in read_directory_recursive\n\nI think we'd have to change the semantics going up the stack, as\ndo_submodule_path has no way to report failure.\n\nBut I think this is another case of\n\n  http://thread.gmane.org/gmane.comp.version-control.git/265560/focus=281253\n\nThere the question was about performance (lots of these clog up the\nlinear ref_cache list), but I think the root cause is the same: going\ntoo far into ref resolution without realizing we don't have a real\nsubmodule.\n\nAndreas posted some patches, but they didn't make it to the list. Here\nare my replies, which did:\n\n  http://article.gmane.org/gmane.comp.version-control.git/282028\n\n  http://article.gmane.org/gmane.comp.version-control.git/282029\n\n  http://thread.gmane.org/gmane.comp.version-control.git/282030\n\nHowever, from going over them, I think there was a problem in the series;\nwe really do need to know the sha1 in some of these cases. So I think\nmaybe the simplest thing would be to catch this case in\nresolve_gitlink_ref(), before we go deeper. Let me see if I can come up\nwith something.\n\n-Peff\n"},{"id":"276577","messageId":"20160122222650.GA14772@sigill.intra.peff.net","threadId":"41238","inReplyTo":"20160122211803.GA17071@sigill.intra.peff.net","subject":"Re: Minor bug, git ls-files -o aborts because of broken submodules","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T22:26:50Z","receivedAt":"2016-01-22T22:26:50Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 22, 2016 at 04:18:03PM -0500, Jeff King wrote:\n\n> But I think this is another case of\n> \n>   http://thread.gmane.org/gmane.comp.version-control.git/265560/focus=281253\n> \n> There the question was about performance (lots of these clog up the\n> linear ref_cache list), but I think the root cause is the same: going\n> too far into ref resolution without realizing we don't have a real\n> submodule.\n> \n> Andreas posted some patches, but they didn't make it to the list. Here\n> are my replies, which did:\n> \n>   http://article.gmane.org/gmane.comp.version-control.git/282028\n> \n>   http://article.gmane.org/gmane.comp.version-control.git/282029\n> \n>   http://thread.gmane.org/gmane.comp.version-control.git/282030\n> \n> However, from going over them, I think there was a problem in the series;\n> we really do need to know the sha1 in some of these cases. So I think\n> maybe the simplest thing would be to catch this case in\n> resolve_gitlink_ref(), before we go deeper. Let me see if I can come up\n> with something.\n\nHere it is. I think this is the right fix, based on the previous attempt\nby Andreas and my comments. Sorry for stealing your topic, but I hope\nthe perf numbers in the second patch will brighten your day. :)\n\n  [1/2]: clean: make is_git_repository a public function\n  [2/2]: resolve_gitlink_ref: ignore non-repository paths\n\n-Peff\n"},{"id":"276578","messageId":"20160122222733.GA15560@sigill.intra.peff.net","threadId":"41238","inReplyTo":"20160122222650.GA14772@sigill.intra.peff.net","subject":"[PATCH 1/2] clean: make is_git_repository a public function","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T22:27:33Z","receivedAt":"2016-01-22T22:27:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have always had is_git_directory(), for looking at a\nspecific directory to see if it contains a git repo. In\n0179ca7 (clean: improve performance when removing lots of\ndirectories, 2015-06-15), we added is_git_repository() which\nchecks for a non-bare repository by looking at its \".git\"\nentry.\n\nHowever, the fix in 0179ca7 needs to be applied other\nplaces, too. Let's make this new helper globally available.\nWe need to give it a better name, though, to avoid confusion\nwith is_git_directory(). This patch does that, documents\nboth functions with a comment to reduce confusion, and\nremoves the clean-specific references in the comments.\n\nBased-on-a-patch-by: Andreas Krey <a.krey@gmx.de>\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/clean.c | 26 +-------------------------\n cache.h         | 20 +++++++++++++++++++-\n setup.c         | 17 +++++++++++++++++\n 3 files changed, 37 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex d7acb94..919157b 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n-/*\n- * Return 1 if the given path is the root of a git repository or\n- * submodule else 0. Will not return 1 for bare repositories with the\n- * exception of creating a bare repository in \"foo/.git\" and calling\n- * is_git_repository(\"foo\").\n- */\n-static int is_git_repository(struct strbuf *path)\n-{\n-\tint ret = 0;\n-\tint gitfile_error;\n-\tsize_t orig_path_len = path->len;\n-\tassert(orig_path_len != 0);\n-\tstrbuf_complete(path, '/');\n-\tstrbuf_addstr(path, \".git\");\n-\tif (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))\n-\t\tret = 1;\n-\tif (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||\n-\t    gitfile_error == READ_GITFILE_ERR_READ_FAILED)\n-\t\tret = 1;  /* This could be a real .git file, take the\n-\t\t\t   * safe option and avoid cleaning */\n-\tstrbuf_setlen(path, orig_path_len);\n-\treturn ret;\n-}\n-\n static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,\n \t\tint dry_run, int quiet, int *dir_gone)\n {\n@@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,\n \n \t*dir_gone = 1;\n \n-\tif ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {\n+\tif ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) {\n \t\tif (!quiet) {\n \t\t\tquote_path_relative(path->buf, prefix, &quoted);\n \t\t\tprintf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),\ndiff --git a/cache.h b/cache.h\nindex dfc459c..553b04b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -458,7 +458,6 @@ extern char *git_work_tree_cfg;\n extern int is_inside_work_tree(void);\n extern const char *get_git_dir(void);\n extern const char *get_git_common_dir(void);\n-extern int is_git_directory(const char *path);\n extern char *get_object_directory(void);\n extern char *get_index_file(void);\n extern char *get_graft_file(void);\n@@ -469,6 +468,25 @@ extern const char *get_git_namespace(void);\n extern const char *strip_namespace(const char *namespaced_ref);\n extern const char *get_git_work_tree(void);\n \n+/*\n+ * Return true if the given path is a git directory; note that this _just_\n+ * looks at the directory itself. If you want to know whether \"foo/.git\"\n+ * is a repository, you must feed that path, not just \"foo\".\n+ */\n+extern int is_git_directory(const char *path);\n+\n+/*\n+ * Return 1 if the given path is the root of a git repository or\n+ * submodule, else 0. Will not return 1 for bare repositories with the\n+ * exception of creating a bare repository in \"foo/.git\" and calling\n+ * is_git_repository(\"foo\").\n+ *\n+ * If we run into read errors, we err on the side of saying \"yes, it is\",\n+ * as we usually consider sub-repos precious, and would prefer to err on the\n+ * side of not disrupting or deleting them.\n+ */\n+extern int is_nonbare_repository_dir(struct strbuf *path);\n+\n #define READ_GITFILE_ERR_STAT_FAILED 1\n #define READ_GITFILE_ERR_NOT_A_FILE 2\n #define READ_GITFILE_ERR_OPEN_FAILED 3\ndiff --git a/setup.c b/setup.c\nindex d343725..2c4b22c 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -312,6 +312,23 @@ done:\n \treturn ret;\n }\n \n+int is_nonbare_repository_dir(struct strbuf *path)\n+{\n+\tint ret = 0;\n+\tint gitfile_error;\n+\tsize_t orig_path_len = path->len;\n+\tassert(orig_path_len != 0);\n+\tstrbuf_complete(path, '/');\n+\tstrbuf_addstr(path, \".git\");\n+\tif (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))\n+\t\tret = 1;\n+\tif (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||\n+\t    gitfile_error == READ_GITFILE_ERR_READ_FAILED)\n+\t\tret = 1;\n+\tstrbuf_setlen(path, orig_path_len);\n+\treturn ret;\n+}\n+\n int is_inside_git_dir(void)\n {\n \tif (inside_git_dir < 0)\n-- \n2.7.0.384.gae54cb4\n"},{"id":"276579","messageId":"20160122222930.GB15560@sigill.intra.peff.net","threadId":"41238","inReplyTo":"20160122222650.GA14772@sigill.intra.peff.net","subject":"[PATCH 2/2] resolve_gitlink_ref: ignore non-repository paths","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T22:29:30Z","receivedAt":"2016-01-22T22:29:30Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"When we want to look up a submodule ref, we use\nget_ref_cache(path) to find or auto-create its ref cache.\nBut if we feed a path that isn't actually a git repository,\nwe blindly create the ref cache, and then may die deeper in\nthe code when we try to access it. This is a problem because\nmany callers speculatively feed us a path that looks vaguely\nlike a repository, and expect us to tell them when it is\nnot.\n\nThis patch teaches resolve_gitlink_ref to reject\nnon-repository paths without creating a ref_cache. This\navoids the die(), and also performs better if you have a\nlarge number of these faux-submodule directories (because\nthe ref_cache lookup is linear, under the assumption that\nthere won't be a large number of submodules).\n\nTo accomplish this, we also break get_ref_cache into two\npieces: the lookup and auto-creation (the latter is lumped\ninto create_ref_cache). This lets us first cheaply ask our\ncache \"is it a submodule we know about?\" If so, we can avoid\nrepeating our filesystem lookup. So lookups of real\nsubmodules are not penalized; they examine the submodule's\n.git directory only once.\n\nThe test in t3000 demonstrates a case where this improves\ncorrectness (we used to just die). The new perf case in\np7300 shows off the speed improvement in an admittedly\npathological repository:\n\nTest                  HEAD^               HEAD\n----------------------------------------------------------------\n7300.4: ls-files -o   66.97(66.15+0.87)   0.33(0.08+0.24) -99.5%\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n refs/files-backend.c       | 46 ++++++++++++++++++++++++++++++++--------------\n t/perf/p7300-clean.sh      |  4 ++++\n t/t3000-ls-files-others.sh |  7 +++++++\n 3 files changed, 43 insertions(+), 14 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex c648b5e..3a27f27 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -933,6 +933,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)\n \t}\n }\n \n+/*\n+ * Create a new submodule ref cache and add it to the internal\n+ * set of caches.\n+ */\n static struct ref_cache *create_ref_cache(const char *submodule)\n {\n \tint len;\n@@ -942,16 +946,12 @@ static struct ref_cache *create_ref_cache(const char *submodule)\n \tlen = strlen(submodule) + 1;\n \trefs = xcalloc(1, sizeof(struct ref_cache) + len);\n \tmemcpy(refs->name, submodule, len);\n+\trefs->next = submodule_ref_caches;\n+\tsubmodule_ref_caches = refs;\n \treturn refs;\n }\n \n-/*\n- * Return a pointer to a ref_cache for the specified submodule. For\n- * the main repository, use submodule==NULL. The returned structure\n- * will be allocated and initialized but not necessarily populated; it\n- * should not be freed.\n- */\n-static struct ref_cache *get_ref_cache(const char *submodule)\n+static struct ref_cache *lookup_ref_cache(const char *submodule)\n {\n \tstruct ref_cache *refs;\n \n@@ -961,10 +961,20 @@ static struct ref_cache *get_ref_cache(const char *submodule)\n \tfor (refs = submodule_ref_caches; refs; refs = refs->next)\n \t\tif (!strcmp(submodule, refs->name))\n \t\t\treturn refs;\n+\treturn NULL;\n+}\n \n-\trefs = create_ref_cache(submodule);\n-\trefs->next = submodule_ref_caches;\n-\tsubmodule_ref_caches = refs;\n+/*\n+ * Return a pointer to a ref_cache for the specified submodule. For\n+ * the main repository, use submodule==NULL. The returned structure\n+ * will be allocated and initialized but not necessarily populated; it\n+ * should not be freed.\n+ */\n+static struct ref_cache *get_ref_cache(const char *submodule)\n+{\n+\tstruct ref_cache *refs = lookup_ref_cache(submodule);\n+\tif (!refs)\n+\t\trefs = create_ref_cache(submodule);\n \treturn refs;\n }\n \n@@ -1336,16 +1346,24 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,\n int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n {\n \tint len = strlen(path), retval;\n-\tchar *submodule;\n+\tstruct strbuf submodule = STRBUF_INIT;\n \tstruct ref_cache *refs;\n \n \twhile (len && path[len-1] == '/')\n \t\tlen--;\n \tif (!len)\n \t\treturn -1;\n-\tsubmodule = xstrndup(path, len);\n-\trefs = get_ref_cache(submodule);\n-\tfree(submodule);\n+\n+\tstrbuf_add(&submodule, path, len);\n+\trefs = lookup_ref_cache(submodule.buf);\n+\tif (!refs) {\n+\t\tif (!is_nonbare_repository_dir(&submodule)) {\n+\t\t\tstrbuf_release(&submodule);\n+\t\t\treturn -1;\n+\t\t}\n+\t\trefs = create_ref_cache(submodule.buf);\n+\t}\n+\tstrbuf_release(&submodule);\n \n \tretval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n \treturn retval;\ndiff --git a/t/perf/p7300-clean.sh b/t/perf/p7300-clean.sh\nindex ec94cdd..7c1888a 100755\n--- a/t/perf/p7300-clean.sh\n+++ b/t/perf/p7300-clean.sh\n@@ -28,4 +28,8 @@ test_perf 'clean many untracked sub dirs, ignore nested git' '\n \tgit clean -n -q -f -f -d 100000_sub_dirs/\n '\n \n+test_perf 'ls-files -o' '\n+\tgit ls-files -o\n+'\n+\n test_done\ndiff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh\nindex 88be904..c525656 100755\n--- a/t/t3000-ls-files-others.sh\n+++ b/t/t3000-ls-files-others.sh\n@@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' '\n \ttest_cmp expected3 output\n '\n \n+test_expect_success 'ls-files --others handles non-submodule .git' '\n+\tmkdir not-a-submodule &&\n+\techo foo >not-a-submodule/.git &&\n+\tgit ls-files -o >output &&\n+\ttest_cmp expected1 output\n+'\n+\n test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '\n \tgit init super &&\n \tgit init sub &&\n-- \n2.7.0.384.gae54cb4\n"},{"id":"276581","messageId":"20160122223154.GA15635@sigill.intra.peff.net","threadId":"41238","inReplyTo":"20160122222930.GB15560@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] resolve_gitlink_ref: ignore non-repository paths","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T22:31:54Z","receivedAt":"2016-01-22T22:31:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 22, 2016 at 05:29:30PM -0500, Jeff King wrote:\n\n> diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh\n> index 88be904..c525656 100755\n> --- a/t/t3000-ls-files-others.sh\n> +++ b/t/t3000-ls-files-others.sh\n> @@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' '\n>  \ttest_cmp expected3 output\n>  '\n>  \n> +test_expect_success 'ls-files --others handles non-submodule .git' '\n> +\tmkdir not-a-submodule &&\n> +\techo foo >not-a-submodule/.git &&\n> +\tgit ls-files -o >output &&\n> +\ttest_cmp expected1 output\n> +'\n\nBTW, I scratched my head about why I was able to use \"expected1\" here\nwithout having to add \"not-a-submodule\" to it. But the answer is that\nthe directory itself does not get mentioned (it is not a file!), and we\nseem to always exclude \".git\" paths entirely.\n\nI'm not sure if that's the best thing in every case (what if you have\nprecious content in a \".git\" file?), but this does behave exactly as a\nvalid \".git\" would with an empty HEAD ref. So I think it's a reasonable\nbehavior in practice.\n\n-Peff\n"},{"id":"276584","messageId":"CAGZ79kYU_=w0VWFRNGamP_nnnjyF6AcOj+A8r8GfhyrJMQzi9w@mail.gmail.com","threadId":"41238","inReplyTo":"20160122223154.GA15635@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] resolve_gitlink_ref: ignore non-repository paths","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-01-22T22:36:54Z","receivedAt":"2016-01-22T22:36:54Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Impressive performance improvements. :)\n\nOn Fri, Jan 22, 2016 at 2:31 PM, Jeff King <peff@peff.net> wrote:\n\n\n> BTW, what if you have\n> precious content in a \".git\" file?\n\nI'd kindly ask to use a different version control in that case.\n\nQ: What can you use Git for?\nA: Everything including version control, backup, deploying software,\n    except when there is a file named .git with precious content.\n\n;)\n"},{"id":"276586","messageId":"20160122224056.GA15965@sigill.intra.peff.net","threadId":"41238","inReplyTo":"CAGZ79kYU_=w0VWFRNGamP_nnnjyF6AcOj+A8r8GfhyrJMQzi9w@mail.gmail.com","subject":"Re: [PATCH 2/2] resolve_gitlink_ref: ignore non-repository paths","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-22T22:40:56Z","receivedAt":"2016-01-22T22:40:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 22, 2016 at 02:36:54PM -0800, Stefan Beller wrote:\n\n> Impressive performance improvements. :)\n\n\"Accidentally quadratic\" bugs are some of my favorites, because it's\nusually easy to show off the results. Of course, the repo in p7300 is\npretty ridiculous, and most people won't see any speedup. I'll be\ncurious to hear about Andreas's case, as it is a real-world one which\nmay see some improvement.\n\n> > BTW, what if you have\n> > precious content in a \".git\" file?\n> \n> I'd kindly ask to use a different version control in that case.\n> \n> Q: What can you use Git for?\n> A: Everything including version control, backup, deploying software,\n>     except when there is a file named .git with precious content.\n> \n> ;)\n\nYeah, I think that is my attitude as well. Just because your \".git\" file\nis not actually a real gitfile does not make it a good idea. We do not\nlist it in \"ls-files -o\", but it is not like you could commit it,\neither; we explicitly prevent it from being added to the index.\n\n-Peff\n"},{"id":"276712","messageId":"20160125131321.GB18574@inner.h.apk.li","threadId":"41238","inReplyTo":"20160122222650.GA14772@sigill.intra.peff.net","subject":"Re: Minor bug, git ls-files -o aborts because of broken submodules","fromName":"Andreas Krey","fromEmail":"a.krey@gmx.de","sentAt":"2016-01-25T13:13:21Z","receivedAt":"2016-01-25T13:13:21Z","isPatch":false,"sender":{"key":"a.krey@gmx.de","avatar":"https://avatars.githubusercontent.com/u/37810?v=4"},"body":"On Fri, 22 Jan 2016 17:26:50 +0000, Jeff King wrote:\n...\n> Here it is. I think this is the right fix, based on the previous attempt\n> by Andreas and my comments. Sorry for stealing your topic,\n\nThis seems to keep happening with things I try to patch. :-)\n\n> but I hope\n> the perf numbers in the second patch will brighten your day. :)\n\nThe patches are 'quadratically' improving my case as well,\nmany thanks for completing this. (I was just mustering\nthe steam for another round of work on this.)\n\nAndreas\n\n-- \n\"Totally trivial. Famous last words.\"\nFrom: Linus Torvalds <torvalds@*.org>\nDate: Fri, 22 Jan 2010 07:29:21 -0800\n"}]}