{"thread":{"id":"45999","subject":"[WIP/RFC 00/23] repository object","startedAt":"2017-05-18T23:22:15Z","lastAt":"2017-05-30T17:12:26Z","messageCount":41,"participants":["Brandon Williams","Jeff Hostetler","Ben Peart","Stefan Beller","Jacob Keller","brian m. carlson","Johannes Schindelin","Jeff King","Junio C Hamano","Duy Nguyen","Ævar Arnfjörð Bjarmason"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"320217","messageId":"20170518232134.163059-1-bmwill@google.com","threadId":"45999","inReplyTo":null,"subject":"[WIP/RFC 00/23] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:11Z","receivedAt":"2017-05-18T23:22:15Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"When I first started working on the git project I found it very difficult to\nunderstand parts of the code base because of the inherently global nature of\nour code.  It also made working on submodules very difficult.  Since we can\nonly open up a single repository per process, you need to launch a child\nprocess in order to process a submodule.  But you also need to be able to\ncommunicate other stateful information to the children processes so that the\nsubmodules know how best to format their output or match against a\npathspec...it ends up feeling like layering on hack after hack.  What I would\nreally like to do, is to have the ability to have a repository object so that I\ncan open a submodule in-process.\n\nBefore this becomes a reality for all commands, much of the library code would\nneed to be refactored in order to work purely on handles instead of global\nstate.  As it turned out, ls-files is a pretty simple command and doesn't have\n*too* many dependencies.  The biggest thing that needed to be changed was\npiping through an index into a couple library routines so that they don't\ninherently rely on 'the_index'.  A few of these changes I've sent out and can\nbe found at 'origin/bw/pathspec-sans-the-index' and\n'origin/bw/dir-c-stops-relying-on-the-index' which this series is based on.\n\nPatches 1-16 are refactorings to prepare either library code or ls-files itself\nto be ready to handle passing around an index struct.  Patches 17-22 introduce\na repository struct and change a couple of things about how submodule caches\nwork (getting submodule information from .gitmodules).  And Patch 23 converts\nls-files to use a repository struct. \n\nThe most interesting part of the series is from 17-23.  And 1-16 could be taken\nas is without the rest of the series.\n\nThis is still very much in a WIP state, though it does pass all tests.  What\nI'm hoping for here is to get a discussion started about the feasibility of a\nchange like this and hopefully to get the ball rolling.  Is this a direction we\nwant to move in?  Is it worth the pain?\n\nThanks for taking the time to look at this and entertain my insane ideas :)\n\nBrandon Williams (23):\n  convert: convert get_cached_convert_stats_ascii to take an index\n  convert: convert crlf_to_git to take an index\n  convert: convert convert_to_git_filter_fd to take an index\n  convert: convert convert_to_git to take an index\n  convert: convert renormalize_buffer to take an index\n  tree: convert read_tree to take an index parameter\n  ls-files: convert overlay_tree_on_cache to take an index\n  ls-files: convert write_eolinfo to take an index\n  ls-files: convert show_killed_files to take an index\n  ls-files: convert show_other_files to take an index\n  ls-files: convert show_ru_info to take an index\n  ls-files: convert ce_excluded to take an index\n  ls-files: convert prune_cache to take an index\n  ls-files: convert show_files to take an index\n  ls-files: factor out debug info into a function\n  ls-files: factor out tag calculation\n  repo: introduce new repository object\n  repo: add index_state to struct repo\n  repo: add per repo config\n  submodule-config: refactor to allow for multiple submodule_cache's\n  repo: add repo_read_gitmodules\n  submodule: add is_submodule_active\n  ls-files: use repository object\n\n Makefile                               |   1 +\n apply.c                                |   2 +-\n builtin/blame.c                        |   2 +-\n builtin/commit.c                       |   3 +-\n builtin/ls-files.c                     | 348 ++++++++++++++++-----------------\n cache.h                                |   4 +-\n combine-diff.c                         |   2 +-\n config.c                               |   2 +-\n convert.c                              |  31 +--\n convert.h                              |  19 +-\n diff.c                                 |   6 +-\n dir.c                                  |   2 +-\n git.c                                  |   2 +-\n ll-merge.c                             |   2 +-\n merge-recursive.c                      |   4 +-\n repo.c                                 | 112 +++++++++++\n repo.h                                 |  22 +++\n sha1_file.c                            |   6 +-\n submodule-config.c                     |  40 +++-\n submodule-config.h                     |  10 +\n submodule.c                            |  51 +++++\n submodule.h                            |   2 +\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++\n tree.c                                 |  28 ++-\n tree.h                                 |   3 +-\n 25 files changed, 513 insertions(+), 230 deletions(-)\n create mode 100644 repo.c\n create mode 100644 repo.h\n\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320218","messageId":"20170518232134.163059-3-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 02/23] convert: convert crlf_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:13Z","receivedAt":"2017-05-18T23:22:23Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1b90d6e6..f5773cfe1 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -217,13 +217,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t}\n }\n \n-static int has_cr_in_index(const char *path)\n+static int has_cr_in_index(const struct index_state *istate, const char *path)\n {\n \tunsigned long sz;\n \tvoid *data;\n \tint has_cr;\n \n-\tdata = read_blob_data_from_cache(path, &sz);\n+\tdata = read_blob_data_from_index(istate, path, &sz);\n \tif (!data)\n \t\treturn 0;\n \thas_cr = memchr(data, '\\r', sz) != NULL;\n@@ -253,7 +253,8 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,\n \n }\n \n-static int crlf_to_git(const char *path, const char *src, size_t len,\n+static int crlf_to_git(const struct index_state *istate,\n+\t\t       const char *path, const char *src, size_t len,\n \t\t       struct strbuf *buf,\n \t\t       enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n@@ -285,7 +286,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \t\t * unless we want to renormalize in a merge or\n \t\t * cherry-pick.\n \t\t */\n-\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path))\n+\t\tif ((checksafe != SAFE_CRLF_RENORMALIZE) &&\n+\t\t    has_cr_in_index(istate, path))\n \t\t\tconvert_crlf_into_lf = 0;\n \t}\n \tif ((checksafe == SAFE_CRLF_WARN ||\n@@ -1193,7 +1195,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1213,7 +1215,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320219","messageId":"20170518232134.163059-4-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 03/23] convert: convert convert_to_git_filter_fd to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:14Z","receivedAt":"2017-05-18T23:22:25Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c   | 5 +++--\n convert.h   | 3 ++-\n sha1_file.c | 2 +-\n 3 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f5773cfe1..d50e7f7aa 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1203,7 +1203,8 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \treturn ret | ident_to_git(path, src, len, dst, ca.ident);\n }\n \n-void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n+void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t      const char *path, int fd, struct strbuf *dst,\n \t\t\t      enum safe_crlf checksafe)\n {\n \tstruct conv_attrs ca;\n@@ -1215,7 +1216,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(&the_index, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \ndiff --git a/convert.h b/convert.h\nindex 667b7dfe0..3a813a797 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -52,7 +52,8 @@ static inline int would_convert_to_git(const char *path)\n \treturn convert_to_git(path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n-extern void convert_to_git_filter_fd(const char *path, int fd,\n+extern void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t\t     const char *path, int fd,\n \t\t\t\t     struct strbuf *dst,\n \t\t\t\t     enum safe_crlf checksafe);\n extern int would_convert_to_git_filter_fd(const char *path);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 59a4ed2ed..ab09241d2 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3580,7 +3580,7 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,\n \tassert(path);\n \tassert(would_convert_to_git_filter_fd(path));\n \n-\tconvert_to_git_filter_fd(path, fd, &sbuf,\n+\tconvert_to_git_filter_fd(&the_index, path, fd, &sbuf,\n \t\t\t\t write_object ? safe_crlf : SAFE_CRLF_FALSE);\n \n \tif (write_object)\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320220","messageId":"20170518232134.163059-2-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 01/23] convert: convert get_cached_convert_stats_ascii to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:12Z","receivedAt":"2017-05-18T23:22:26Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 3 ++-\n convert.c          | 5 +++--\n convert.h          | 5 ++++-\n 3 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 89b3ce8e5..770d8774a 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -63,7 +63,8 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(ce->name);\n+\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n \t\tprintf(\"i/%-5s w/%-5s attr/%-17s\\t\", i_txt, w_txt, a_txt);\ndiff --git a/convert.c b/convert.c\nindex 8d652bf27..b1b90d6e6 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -133,11 +133,12 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n-const char *get_cached_convert_stats_ascii(const char *path)\n+const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t   const char *path)\n {\n \tconst char *ret;\n \tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n+\tvoid *data = read_blob_data_from_index(istate, path, &sz);\n \tret = gather_convert_stats_ascii(data, sz);\n \tfree(data);\n \treturn ret;\ndiff --git a/convert.h b/convert.h\nindex 82871a11d..667b7dfe0 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -4,6 +4,8 @@\n #ifndef CONVERT_H\n #define CONVERT_H\n \n+struct index_state;\n+\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n@@ -33,7 +35,8 @@ enum eol {\n };\n \n extern enum eol core_eol;\n-extern const char *get_cached_convert_stats_ascii(const char *path);\n+extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t\t  const char *path);\n extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320221","messageId":"20170518232134.163059-5-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 04/23] convert: convert convert_to_git to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:15Z","receivedAt":"2017-05-18T23:22:28Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n apply.c         | 2 +-\n builtin/blame.c | 2 +-\n combine-diff.c  | 2 +-\n convert.c       | 7 ++++---\n convert.h       | 8 +++++---\n diff.c          | 6 +++---\n dir.c           | 2 +-\n sha1_file.c     | 4 ++--\n 8 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex e6dbab26a..7813faacf 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -2267,7 +2267,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)\n \tcase S_IFREG:\n \t\tif (strbuf_read_file(buf, path, st->st_size) != st->st_size)\n \t\t\treturn error(_(\"unable to open or read %s\"), path);\n-\t\tconvert_to_git(path, buf->buf, buf->len, buf, 0);\n+\t\tconvert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);\n \t\treturn 0;\n \tdefault:\n \t\treturn -1;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 07506a3e4..8a9c0eb01 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2383,7 +2383,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \t\tif (strbuf_read(&buf, 0, 0) < 0)\n \t\t\tdie_errno(\"failed to read from stdin\");\n \t}\n-\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\tconvert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);\n \torigin->file.ptr = buf.buf;\n \torigin->file.size = buf.len;\n \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 2848034fe..74f723af3 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1053,7 +1053,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\n \n-\t\t\t\tif (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {\n+\t\t\t\tif (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) {\n \t\t\t\t\tfree(result);\n \t\t\t\t\tresult = strbuf_detach(&buf, &len);\n \t\t\t\t\tresult_size = len;\ndiff --git a/convert.c b/convert.c\nindex d50e7f7aa..3d1c7e2b6 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1179,7 +1179,8 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n-int convert_to_git(const char *path, const char *src, size_t len,\n+int convert_to_git(const struct index_state *istate,\n+\t\t   const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\n \tint ret = 0;\n@@ -1195,7 +1196,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(&the_index, path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1266,7 +1267,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 3a813a797..60cb41d6a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -41,15 +41,17 @@ extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\n-extern int convert_to_git(const char *path, const char *src, size_t len,\n+extern int convert_to_git(const struct index_state *istate,\n+\t\t\t  const char *path, const char *src, size_t len,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n extern int renormalize_buffer(const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n-static inline int would_convert_to_git(const char *path)\n+static inline int would_convert_to_git(const struct index_state *istate,\n+\t\t\t\t       const char *path)\n {\n-\treturn convert_to_git(path, NULL, 0, NULL, 0);\n+\treturn convert_to_git(istate, path, NULL, 0, NULL, 0);\n }\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n extern void convert_to_git_filter_fd(const struct index_state *istate,\ndiff --git a/diff.c b/diff.c\nindex 74283d900..ab19453e1 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2755,7 +2755,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \t * Similarly, if we'd have to convert the file contents anyway, that\n \t * makes the optimization not worthwhile.\n \t */\n-\tif (!want_file && would_convert_to_git(name))\n+\tif (!want_file && would_convert_to_git(&the_index, name))\n \t\treturn 0;\n \n \tlen = strlen(name);\n@@ -2877,7 +2877,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t * point if the path requires us to run the content\n \t\t * conversion.\n \t\t */\n-\t\tif (size_only && !would_convert_to_git(s->path))\n+\t\tif (size_only && !would_convert_to_git(&the_index, s->path))\n \t\t\treturn 0;\n \n \t\t/*\n@@ -2904,7 +2904,7 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \t\t/*\n \t\t * Convert from working tree format to canonical git format\n \t\t */\n-\t\tif (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {\n+\t\tif (convert_to_git(&the_index, s->path, s->data, s->size, &buf, crlf_warn)) {\n \t\t\tsize_t size = 0;\n \t\t\tmunmap(s->data, s->size);\n \t\t\ts->should_munmap = 0;\ndiff --git a/dir.c b/dir.c\nindex 3f3167e55..128fc2f8d 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -795,7 +795,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\t\t (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&\n \t\t\t\t !ce_stage(istate->cache[pos]) &&\n \t\t\t\t ce_uptodate(istate->cache[pos]) &&\n-\t\t\t\t !would_convert_to_git(fname))\n+\t\t\t\t !would_convert_to_git(istate, fname))\n \t\t\t\thashcpy(sha1_stat->sha1,\n \t\t\t\t\tistate->cache[pos]->oid.hash);\n \t\t\telse\ndiff --git a/sha1_file.c b/sha1_file.c\nindex ab09241d2..feb227a83 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3546,7 +3546,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,\n \t */\n \tif ((type == OBJ_BLOB) && path) {\n \t\tstruct strbuf nbuf = STRBUF_INIT;\n-\t\tif (convert_to_git(path, buf, size, &nbuf,\n+\t\tif (convert_to_git(&the_index, path, buf, size, &nbuf,\n \t\t\t\t   write_object ? safe_crlf : SAFE_CRLF_FALSE)) {\n \t\t\tbuf = strbuf_detach(&nbuf, &size);\n \t\t\tre_allocated = 1;\n@@ -3668,7 +3668,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(sha1, fd, type, path, flags);\n \telse if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||\n-\t\t (path && would_convert_to_git(path)))\n+\t\t (path && would_convert_to_git(&the_index, path)))\n \t\tret = index_core(sha1, fd, xsize_t(st->st_size), type, path,\n \t\t\t\t flags);\n \telse\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320222","messageId":"20170518232134.163059-11-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 10/23] ls-files: convert show_other_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:21Z","receivedAt":"2017-05-18T23:22:29Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 7cdee2359..3d4e497cc 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -108,13 +108,14 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \twrite_name(ent->name);\n }\n \n-static void show_other_files(struct dir_struct *dir)\n+static void show_other_files(const struct index_state *istate,\n+\t\t\t     const struct dir_struct *dir)\n {\n \tint i;\n \n \tfor (i = 0; i < dir->nr; i++) {\n \t\tstruct dir_entry *ent = dir->entries[i];\n-\t\tif (!cache_name_is_other(ent->name, ent->len))\n+\t\tif (!index_name_is_other(istate, ent->name, ent->len))\n \t\t\tcontinue;\n \t\tshow_dir_entry(tag_other, ent);\n \t}\n@@ -336,7 +337,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n \t\tfill_directory(dir, &the_index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(dir);\n+\t\t\tshow_other_files(&the_index, dir);\n \t\tif (show_killed)\n \t\t\tshow_killed_files(&the_index, dir);\n \t}\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320223","messageId":"20170518232134.163059-12-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 11/23] ls-files: convert show_ru_info to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:22Z","receivedAt":"2017-05-18T23:22:31Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 3d4e497cc..755dfc8d6 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -292,14 +292,14 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \tstrbuf_release(&name);\n }\n \n-static void show_ru_info(void)\n+static void show_ru_info(const struct index_state *istate)\n {\n \tstruct string_list_item *item;\n \n-\tif (!the_index.resolve_undo)\n+\tif (!istate->resolve_undo)\n \t\treturn;\n \n-\tfor_each_string_list_item(item, the_index.resolve_undo) {\n+\tfor_each_string_list_item(item, istate->resolve_undo) {\n \t\tconst char *path = item->string;\n \t\tstruct resolve_undo_info *ui = item->util;\n \t\tint i, len;\n@@ -685,7 +685,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\n-\t\tshow_ru_info();\n+\t\tshow_ru_info(&the_index);\n \n \tif (ps_matched) {\n \t\tint bad;\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320224","messageId":"20170518232134.163059-7-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 06/23] tree: convert read_tree to take an index parameter","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:17Z","receivedAt":"2017-05-18T23:22:33Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c |  2 +-\n tree.c             | 28 ++++++++++++++++++----------\n tree.h             |  3 ++-\n 3 files changed, 21 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 770d8774a..a4ced5a9c 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -460,7 +460,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec))\n+\tif (read_tree(tree, 1, &pathspec, &the_index))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n \tfor (i = 0; i < active_nr; i++) {\ndiff --git a/tree.c b/tree.c\nindex ce345c551..cb5d40320 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"cache-tree.h\"\n #include \"tree.h\"\n@@ -8,7 +9,11 @@\n \n const char *tree_type = \"tree\";\n \n-static int read_one_entry_opt(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, int opt)\n+static int read_one_entry_opt(struct index_state *istate,\n+\t\t\t      const unsigned char *sha1,\n+\t\t\t      const char *base, int baselen,\n+\t\t\t      const char *pathname,\n+\t\t\t      unsigned mode, int stage, int opt)\n {\n \tint len;\n \tunsigned int size;\n@@ -27,14 +32,15 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n \tmemcpy(ce->name, base, baselen);\n \tmemcpy(ce->name + baselen, pathname, len+1);\n \thashcpy(ce->oid.hash, sha1);\n-\treturn add_cache_entry(ce, opt);\n+\treturn add_index_entry(istate, ce, opt);\n }\n \n static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n \t\t\t  const char *pathname, unsigned mode, int stage,\n \t\t\t  void *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n }\n@@ -47,7 +53,8 @@ static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n \t\t\t\tconst char *pathname, unsigned mode, int stage,\n \t\t\t\tvoid *context)\n {\n-\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\tstruct index_state *istate = context;\n+\treturn read_one_entry_opt(istate, sha1, base->buf, base->len, pathname,\n \t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n@@ -144,7 +151,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_namelen, ce_stage(ce2));\n }\n \n-int read_tree(struct tree *tree, int stage, struct pathspec *match)\n+int read_tree(struct tree *tree, int stage, struct pathspec *match,\n+\t      struct index_state *istate)\n {\n \tread_tree_fn_t fn = NULL;\n \tint i, err;\n@@ -164,23 +172,23 @@ int read_tree(struct tree *tree, int stage, struct pathspec *match)\n \t * do it the original slow way, otherwise, append and then\n \t * sort at the end.\n \t */\n-\tfor (i = 0; !fn && i < active_nr; i++) {\n-\t\tconst struct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; !fn && i < istate->cache_nr; i++) {\n+\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\tif (ce_stage(ce) == stage)\n \t\t\tfn = read_one_entry;\n \t}\n \n \tif (!fn)\n \t\tfn = read_one_entry_quick;\n-\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, NULL);\n+\terr = read_tree_recursive(tree, \"\", 0, stage, match, fn, istate);\n \tif (fn == read_one_entry || err)\n \t\treturn err;\n \n \t/*\n \t * Sort the cache entry -- we need to nuke the cache tree, though.\n \t */\n-\tcache_tree_free(&active_cache_tree);\n-\tQSORT(active_cache, active_nr, cmp_cache_name_compare);\n+\tcache_tree_free(&istate->cache_tree);\n+\tQSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);\n \treturn 0;\n }\n \ndiff --git a/tree.h b/tree.h\nindex d24786cba..99f5b7ec1 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -34,6 +34,7 @@ extern int read_tree_recursive(struct tree *tree,\n \t\t\t       int stage, const struct pathspec *pathspec,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n-extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);\n+extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec,\n+\t\t     struct index_state *istate);\n \n #endif /* TREE_H */\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320225","messageId":"20170518232134.163059-15-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 14/23] ls-files: convert show_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:25Z","receivedAt":"2017-05-18T23:22:35Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 8448b04e8..56fd6644f 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -328,7 +328,7 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n \treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n-static void show_files(struct dir_struct *dir)\n+static void show_files(struct index_state *istate, struct dir_struct *dir)\n {\n \tint i;\n \n@@ -336,17 +336,17 @@ static void show_files(struct dir_struct *dir)\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, &the_index, &pathspec);\n+\t\tfill_directory(dir, istate, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(&the_index, dir);\n+\t\t\tshow_other_files(istate, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(&the_index, dir);\n+\t\t\tshow_killed_files(istate, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -357,12 +357,12 @@ static void show_files(struct dir_struct *dir)\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < active_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, &the_index, ce))\n+\t\t\t    !ce_excluded(dir, istate, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n@@ -371,7 +371,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\terr = lstat(ce->name, &st);\n \t\t\tif (show_deleted && err)\n \t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ce_modified(ce, &st, 0))\n+\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n \t\t\t\tshow_ce_entry(tag_modified, ce);\n \t\t}\n \t}\n@@ -685,7 +685,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n \t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n-\tshow_files(&dir);\n+\tshow_files(&the_index, &dir);\n \tif (show_resolve_undo)\n \t\tshow_ru_info(&the_index);\n \n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320226","messageId":"20170518232134.163059-6-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 05/23] convert: convert renormalize_buffer to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:16Z","receivedAt":"2017-05-18T23:22:40Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n convert.c         | 6 ++++--\n convert.h         | 3 ++-\n ll-merge.c        | 2 +-\n merge-recursive.c | 4 ++--\n 4 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 3d1c7e2b6..e4c8e6ad3 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"attr.h\"\n #include \"run-command.h\"\n@@ -1260,14 +1261,15 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc\n \treturn convert_to_working_tree_internal(path, src, len, dst, 0);\n }\n \n-int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)\n+int renormalize_buffer(const struct index_state *istate, const char *path,\n+\t\t       const char *src, size_t len, struct strbuf *dst)\n {\n \tint ret = convert_to_working_tree_internal(path, src, len, dst, 1);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(&the_index, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n+\treturn ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex 60cb41d6a..cecf59d1a 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -46,7 +46,8 @@ extern int convert_to_git(const struct index_state *istate,\n \t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n-extern int renormalize_buffer(const char *path, const char *src, size_t len,\n+extern int renormalize_buffer(const struct index_state *istate,\n+\t\t\t      const char *path, const char *src, size_t len,\n \t\t\t      struct strbuf *dst);\n static inline int would_convert_to_git(const struct index_state *istate,\n \t\t\t\t       const char *path)\ndiff --git a/ll-merge.c b/ll-merge.c\nindex ac0d4a5d7..d7eafb61a 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -339,7 +339,7 @@ static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr\n static void normalize_file(mmfile_t *mm, const char *path)\n {\n \tstruct strbuf strbuf = STRBUF_INIT;\n-\tif (renormalize_buffer(path, mm->ptr, mm->size, &strbuf)) {\n+\tif (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) {\n \t\tfree(mm->ptr);\n \t\tmm->size = strbuf.len;\n \t\tmm->ptr = strbuf_detach(&strbuf, NULL);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 62decd51c..cdf34c524 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1639,8 +1639,8 @@ static int blob_unchanged(struct merge_options *opt,\n \t * performed.  Comparison can be skipped if both files are\n \t * unchanged since their sha1s have already been compared.\n \t */\n-\tif (renormalize_buffer(path, o.buf, o.len, &o) |\n-\t    renormalize_buffer(path, a.buf, a.len, &a))\n+\tif (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |\n+\t    renormalize_buffer(&the_index, path, a.buf, a.len, &a))\n \t\tret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));\n \n error_return:\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320227","messageId":"20170518232134.163059-13-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 12/23] ls-files: convert ce_excluded to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:23Z","receivedAt":"2017-05-18T23:22:41Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 755dfc8d6..de02819c6 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -321,10 +321,11 @@ static void show_ru_info(const struct index_state *istate)\n \t}\n }\n \n-static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)\n+static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n+\t\t       const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, &the_index, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, ce->name, &dtype);\n }\n \n static void show_files(struct dir_struct *dir)\n@@ -345,7 +346,7 @@ static void show_files(struct dir_struct *dir)\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tconst struct cache_entry *ce = active_cache[i];\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n@@ -361,7 +362,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\tstruct stat st;\n \t\t\tint err;\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, ce))\n+\t\t\t    !ce_excluded(dir, &the_index, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320228","messageId":"20170518232134.163059-16-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 15/23] ls-files: factor out debug info into a function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:26Z","receivedAt":"2017-05-18T23:22:43Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 23 ++++++++++++++---------\n 1 file changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 56fd6644f..6603538ec 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -93,6 +93,19 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static void print_debug(const struct cache_entry *ce)\n+{\n+\tif (debug_mode) {\n+\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n+\n+\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n+\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n+\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n+\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n+\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n+\t}\n+}\n+\n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n \tint len = max_prefix_len;\n@@ -278,15 +291,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t}\n \t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n-\t\tif (debug_mode) {\n-\t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-\n-\t\t\tprintf(\"  ctime: %d:%d\\n\", sd->sd_ctime.sec, sd->sd_ctime.nsec);\n-\t\t\tprintf(\"  mtime: %d:%d\\n\", sd->sd_mtime.sec, sd->sd_mtime.nsec);\n-\t\t\tprintf(\"  dev: %d\\tino: %d\\n\", sd->sd_dev, sd->sd_ino);\n-\t\t\tprintf(\"  uid: %d\\tgid: %d\\n\", sd->sd_uid, sd->sd_gid);\n-\t\t\tprintf(\"  size: %d\\tflags: %x\\n\", sd->sd_size, ce->ce_flags);\n-\t\t}\n+\t\tprint_debug(ce);\n \t}\n \n \tstrbuf_release(&name);\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320229","messageId":"20170518232134.163059-9-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 08/23] ls-files: convert write_eolinfo to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:19Z","receivedAt":"2017-05-18T23:22:46Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 13 ++++++-------\n 1 file changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 7d306f418..9313452e3 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -53,17 +53,16 @@ static const char *tag_modified = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n-static void write_eolinfo(const struct cache_entry *ce, const char *path)\n+static void write_eolinfo(const struct index_state *istate,\n+\t\t\t  const struct cache_entry *ce, const char *path)\n {\n-\tif (!show_eol)\n-\t\treturn;\n-\telse {\n+\tif (show_eol) {\n \t\tstruct stat st;\n \t\tconst char *i_txt = \"\";\n \t\tconst char *w_txt = \"\";\n \t\tconst char *a_txt = get_convert_attr_ascii(path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n-\t\t\ti_txt = get_cached_convert_stats_ascii(&the_index,\n+\t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\n \t\tif (!lstat(path, &st) && S_ISREG(st.st_mode))\n \t\t\tw_txt = get_wt_convert_stats_ascii(path);\n@@ -105,7 +104,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \t\treturn;\n \n \tfputs(tag, stdout);\n-\twrite_eolinfo(NULL, ent->name);\n+\twrite_eolinfo(NULL, NULL, ent->name);\n \twrite_name(ent->name);\n }\n \n@@ -275,7 +274,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n \t\t}\n-\t\twrite_eolinfo(ce, ce->name);\n+\t\twrite_eolinfo(&the_index, ce, ce->name);\n \t\twrite_name(ce->name);\n \t\tif (debug_mode) {\n \t\t\tconst struct stat_data *sd = &ce->ce_stat_data;\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320230","messageId":"20170518232134.163059-8-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 07/23] ls-files: convert overlay_tree_on_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:18Z","receivedAt":"2017-05-18T23:22:49Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/commit.c   |  3 ++-\n builtin/ls-files.c | 15 ++++++++-------\n cache.h            |  3 ++-\n 3 files changed, 12 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1d805f5da..38993bd24 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -253,7 +253,8 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \tif (with_tree) {\n \t\tchar *max_prefix = common_prefix(pattern);\n-\t\toverlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree,\n+\t\t\t\t      max_prefix ? max_prefix : prefix);\n \t\tfree(max_prefix);\n \t}\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex a4ced5a9c..7d306f418 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -431,7 +431,8 @@ static int get_common_prefix_len(const char *common_prefix)\n  * that were given from the command line.  We are not\n  * going to write this index out.\n  */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix)\n {\n \tstruct tree *tree;\n \tunsigned char sha1[20];\n@@ -446,8 +447,8 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\tdie(\"bad tree-ish %s\", tree_name);\n \n \t/* Hoist the unmerged entries up to stage #3 to make room */\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n \t\tce->ce_flags |= CE_STAGEMASK;\n@@ -460,11 +461,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n \t\tmemset(&pathspec, 0, sizeof(pathspec));\n-\tif (read_tree(tree, 1, &pathspec, &the_index))\n+\tif (read_tree(tree, 1, &pathspec, istate))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tswitch (ce_stage(ce)) {\n \t\tcase 0:\n \t\t\tlast_stage0 = ce;\n@@ -679,7 +680,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_cache(with_tree, max_prefix);\n+\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n \t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\ndiff --git a/cache.h b/cache.h\nindex e1f0e182a..175e58f01 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -2179,7 +2179,8 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)\n \n /* ls-files */\n-void overlay_tree_on_cache(const char *tree_name, const char *prefix);\n+void overlay_tree_on_index(struct index_state *istate,\n+\t\t\t   const char *tree_name, const char *prefix);\n \n char *alias_lookup(const char *alias);\n int split_cmdline(char *cmdline, const char ***argv);\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320231","messageId":"20170518232134.163059-10-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 09/23] ls-files: convert show_killed_files to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:20Z","receivedAt":"2017-05-18T23:22:52Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 21 +++++++++++----------\n 1 file changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 9313452e3..7cdee2359 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -120,7 +120,8 @@ static void show_other_files(struct dir_struct *dir)\n \t}\n }\n \n-static void show_killed_files(struct dir_struct *dir)\n+static void show_killed_files(const struct index_state *istate,\n+\t\t\t      const struct dir_struct *dir)\n {\n \tint i;\n \tfor (i = 0; i < dir->nr; i++) {\n@@ -134,29 +135,29 @@ static void show_killed_files(struct dir_struct *dir)\n \t\t\t\t/* If ent->name is prefix of an entry in the\n \t\t\t\t * cache, it will be killed.\n \t\t\t\t */\n-\t\t\t\tpos = cache_name_pos(ent->name, ent->len);\n+\t\t\t\tpos = index_name_pos(istate, ent->name, ent->len);\n \t\t\t\tif (0 <= pos)\n \t\t\t\t\tdie(\"BUG: killed-file %.*s not found\",\n \t\t\t\t\t\tent->len, ent->name);\n \t\t\t\tpos = -pos - 1;\n-\t\t\t\twhile (pos < active_nr &&\n-\t\t\t\t       ce_stage(active_cache[pos]))\n+\t\t\t\twhile (pos < istate->cache_nr &&\n+\t\t\t\t       ce_stage(istate->cache[pos]))\n \t\t\t\t\tpos++; /* skip unmerged */\n-\t\t\t\tif (active_nr <= pos)\n+\t\t\t\tif (istate->cache_nr <= pos)\n \t\t\t\t\tbreak;\n \t\t\t\t/* pos points at a name immediately after\n \t\t\t\t * ent->name in the cache.  Does it expect\n \t\t\t\t * ent->name to be a directory?\n \t\t\t\t */\n-\t\t\t\tlen = ce_namelen(active_cache[pos]);\n+\t\t\t\tlen = ce_namelen(istate->cache[pos]);\n \t\t\t\tif ((ent->len < len) &&\n-\t\t\t\t    !strncmp(active_cache[pos]->name,\n+\t\t\t\t    !strncmp(istate->cache[pos]->name,\n \t\t\t\t\t     ent->name, ent->len) &&\n-\t\t\t\t    active_cache[pos]->name[ent->len] == '/')\n+\t\t\t\t    istate->cache[pos]->name[ent->len] == '/')\n \t\t\t\t\tkilled = 1;\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tif (0 <= cache_name_pos(ent->name, sp - ent->name)) {\n+\t\t\tif (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {\n \t\t\t\t/* If any of the leading directories in\n \t\t\t\t * ent->name is registered in the cache,\n \t\t\t\t * ent->name will be killed.\n@@ -337,7 +338,7 @@ static void show_files(struct dir_struct *dir)\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(dir);\n+\t\t\tshow_killed_files(&the_index, dir);\n \t}\n \tif (show_cached || show_stage) {\n \t\tfor (i = 0; i < active_nr; i++) {\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320232","messageId":"20170518232134.163059-17-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 16/23] ls-files: factor out tag calculation","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:27Z","receivedAt":"2017-05-18T23:22:55Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 41 +++++++++++++++++++++++++----------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 6603538ec..456df61e4 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -93,6 +93,30 @@ static void write_name(const char *name)\n \tstrbuf_release(&full_name);\n }\n \n+static const char *get_tag(const struct cache_entry *ce, const char *tag)\n+{\n+\tstatic char alttag[4];\n+\n+\tif (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) {\n+\t\tmemcpy(alttag, tag, 3);\n+\n+\t\tif (isalpha(tag[0])) {\n+\t\t\talttag[0] = tolower(tag[0]);\n+\t\t} else if (tag[0] == '?') {\n+\t\t\talttag[0] = '!';\n+\t\t} else {\n+\t\t\talttag[0] = 'v';\n+\t\t\talttag[1] = tag[0];\n+\t\t\talttag[2] = ' ';\n+\t\t\talttag[3] = 0;\n+\t\t}\n+\n+\t\ttag = alttag;\n+\t}\n+\n+\treturn tag;\n+}\n+\n static void print_debug(const struct cache_entry *ce)\n {\n \tif (debug_mode) {\n@@ -263,22 +287,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t\t  len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n-\t\tif (tag && *tag && show_valid_bit &&\n-\t\t    (ce->ce_flags & CE_VALID)) {\n-\t\t\tstatic char alttag[4];\n-\t\t\tmemcpy(alttag, tag, 3);\n-\t\t\tif (isalpha(tag[0]))\n-\t\t\t\talttag[0] = tolower(tag[0]);\n-\t\t\telse if (tag[0] == '?')\n-\t\t\t\talttag[0] = '!';\n-\t\t\telse {\n-\t\t\t\talttag[0] = 'v';\n-\t\t\t\talttag[1] = tag[0];\n-\t\t\t\talttag[2] = ' ';\n-\t\t\t\talttag[3] = 0;\n-\t\t\t}\n-\t\t\ttag = alttag;\n-\t\t}\n+\t\ttag = get_tag(ce, tag);\n \n \t\tif (!show_stage) {\n \t\t\tfputs(tag, stdout);\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320233","messageId":"20170518232134.163059-21-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 20/23] submodule-config: refactor to allow for multiple submodule_cache's","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:31Z","receivedAt":"2017-05-18T23:22:56Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A repository object will have its own submodule cache so lay the ground\nwork for allowing multiple submodule cache structs.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n submodule-config.c | 40 ++++++++++++++++++++++++++++++++--------\n submodule-config.h | 10 ++++++++++\n 2 files changed, 42 insertions(+), 8 deletions(-)\n\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4f58491dd..666643d52 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -30,7 +30,7 @@ enum lookup_type {\n \tlookup_path\n };\n \n-static struct submodule_cache the_submodule_cache;\n+struct submodule_cache the_submodule_cache;\n static int is_cache_init;\n \n static int config_path_cmp(const struct submodule_entry *a,\n@@ -49,7 +49,12 @@ static int config_name_cmp(const struct submodule_entry *a,\n \t       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);\n }\n \n-static void cache_init(struct submodule_cache *cache)\n+struct submodule_cache *submodule_cache_alloc(void)\n+{\n+\treturn xcalloc(1, sizeof(struct submodule_cache));\n+}\n+\n+void submodule_cache_init(struct submodule_cache *cache)\n {\n \thashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);\n \thashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);\n@@ -64,7 +69,7 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree(entry->config);\n }\n \n-static void cache_free(struct submodule_cache *cache)\n+static void submodule_cache_clear(struct submodule_cache *cache)\n {\n \tstruct hashmap_iter iter;\n \tstruct submodule_entry *entry;\n@@ -82,6 +87,12 @@ static void cache_free(struct submodule_cache *cache)\n \thashmap_free(&cache->for_name, 1);\n }\n \n+void submodule_cache_free(struct submodule_cache *cache)\n+{\n+\tsubmodule_cache_clear(cache);\n+\tfree(cache);\n+}\n+\n static unsigned int hash_sha1_string(const unsigned char *sha1,\n \t\t\t\t     const char *string)\n {\n@@ -493,27 +504,40 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \treturn submodule;\n }\n \n+const struct submodule *\n+submodule_from_cache(struct submodule_cache *cache,\n+\t\t     const unsigned char *treeish_name,\n+\t\t     const char *key)\n+{\n+\treturn config_from(cache, treeish_name, key, lookup_path);\n+}\n+\n static void ensure_cache_init(void)\n {\n \tif (is_cache_init)\n \t\treturn;\n \n-\tcache_init(&the_submodule_cache);\n+\tsubmodule_cache_init(&the_submodule_cache);\n \tis_cache_init = 1;\n }\n \n-int parse_submodule_config_option(const char *var, const char *value)\n+int parse_submodule_config_option_cache(struct submodule_cache *cache, const char *var, const char *value)\n {\n \tstruct parse_config_parameter parameter;\n-\tparameter.cache = &the_submodule_cache;\n+\tparameter.cache = cache;\n \tparameter.treeish_name = NULL;\n \tparameter.gitmodules_sha1 = null_sha1;\n \tparameter.overwrite = 1;\n \n-\tensure_cache_init();\n \treturn parse_config(var, value, &parameter);\n }\n \n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\tensure_cache_init();\n+\treturn parse_submodule_config_option_cache(&the_submodule_cache, var, value);\n+}\n+\n const struct submodule *submodule_from_name(const unsigned char *treeish_name,\n \t\tconst char *name)\n {\n@@ -530,6 +554,6 @@ const struct submodule *submodule_from_path(const unsigned char *treeish_name,\n \n void submodule_free(void)\n {\n-\tcache_free(&the_submodule_cache);\n+\tsubmodule_cache_clear(&the_submodule_cache);\n \tis_cache_init = 0;\n }\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d434ecdb4..ed598aadd 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -22,14 +22,24 @@ struct submodule {\n \tint recommend_shallow;\n };\n \n+struct submodule_cache;\n+\n+extern struct submodule_cache *submodule_cache_alloc(void);\n+extern void submodule_cache_init(struct submodule_cache *cache);\n+extern void submodule_cache_free(struct submodule_cache *cache);\n+\n extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);\n extern int parse_submodule_config_option(const char *var, const char *value);\n+extern int parse_submodule_config_option_cache(struct submodule_cache *cache, const char *var, const char *value);\n extern const struct submodule *submodule_from_name(\n \t\tconst unsigned char *commit_or_tree, const char *name);\n extern const struct submodule *submodule_from_path(\n \t\tconst unsigned char *commit_or_tree, const char *path);\n+extern const struct submodule *submodule_from_cache(struct submodule_cache *cache,\n+\t\t\t\t\t\t    const unsigned char *treeish_name,\n+\t\t\t\t\t\t    const char *key);\n extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,\n \t\t\t\t      unsigned char *gitmodules_sha1,\n \t\t\t\t      struct strbuf *rev);\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320234","messageId":"20170518232134.163059-20-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 19/23] repo: add per repo config","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:30Z","receivedAt":"2017-05-18T23:23:04Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n cache.h  |  1 +\n config.c |  2 +-\n repo.c   | 27 ++++++++++++++++++++++++++-\n repo.h   |  2 ++\n 4 files changed, 30 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 175e58f01..af9ae1173 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -2015,6 +2015,7 @@ struct config_set {\n };\n \n extern void git_configset_init(struct config_set *cs);\n+extern int config_set_callback(const char *key, const char *value, void *cb);\n extern int git_configset_add_file(struct config_set *cs, const char *filename);\n extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);\n extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);\ndiff --git a/config.c b/config.c\nindex b4a3205da..d24baec50 100644\n--- a/config.c\n+++ b/config.c\n@@ -1765,7 +1765,7 @@ void git_configset_clear(struct config_set *cs)\n \tcs->list.items = NULL;\n }\n \n-static int config_set_callback(const char *key, const char *value, void *cb)\n+int config_set_callback(const char *key, const char *value, void *cb)\n {\n \tstruct config_set *cs = cb;\n \tconfigset_add_value(cs, key, value);\ndiff --git a/repo.c b/repo.c\nindex 7e5c03ac5..223adf4c8 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -1,10 +1,16 @@\n #include \"cache.h\"\n #include \"repo.h\"\n \n+char *\n+repo_git_pathdup(const struct repo *repo, const char *file)\n+{\n+\treturn xstrfmt(\"%s/%s\", repo->gitdir, file);\n+}\n+\n int\n repo_read_index(struct repo *repo, const char *index_file)\n {\n-\tchar *index_path = xstrfmt(\"%s/index\", repo->gitdir);\n+\tchar *index_path = repo_git_pathdup(repo, \"index\");\n \tconst char *file = index_file ? index_file : index_path;\n \n \trepo->index = xcalloc(1, sizeof(struct index_state));\n@@ -16,6 +22,18 @@ repo_read_index(struct repo *repo, const char *index_file)\n }\n \n int\n+repo_read_config(struct repo *repo)\n+{\n+\tstruct config_options opts = { 1, repo->gitdir };\n+\n+\trepo->config = xcalloc(1, sizeof(struct config_set));\n+\tgit_configset_init(repo->config);\n+\n+\treturn git_config_with_options(config_set_callback, repo->config,\n+\t\t\t\t       NULL, &opts);\n+}\n+\n+int\n repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n {\n \tint error = 0;\n@@ -40,6 +58,8 @@ repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n \t/* Maybe need a check to verify that a worktree is indeed a worktree? */\n \trepo->worktree = xstrdup_or_null(worktree);\n \n+\trepo_read_config(repo);\n+\n \tfree(abspath);\n \tfree(suspect);\n \n@@ -58,4 +78,9 @@ repo_clear(struct repo *repo)\n \t\tdiscard_index(repo->index);\n \t\tfree(repo->index);\n \t}\n+\n+\tif (repo->config) {\n+\t\tgit_configset_clear(repo->config);\n+\t\tfree(repo->config);\n+\t}\n }\ndiff --git a/repo.h b/repo.h\nindex 15a0bdee9..b4df774c3 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -2,12 +2,14 @@\n #define REPO_H\n \n struct index_state;\n+struct config_set;\n \n struct repo {\n \tchar *gitdir;\n \tchar *worktree;\n \tconst char *submodule_prefix;\n \tstruct index_state *index;\n+\tstruct config_set *config;\n };\n \n extern int repo_read_index(struct repo *repo, const char *index_file);\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320235","messageId":"20170518232134.163059-23-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 22/23] submodule: add is_submodule_active","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:33Z","receivedAt":"2017-05-18T23:23:07Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Add method which checks if a submodule is active given the provided\nrepository object.\n\nNOTE: this is almost a copy-paste of is_submodule_initialized.  I tried\nto convert is_submodule_initialized to take a submodule_cache and\nconfig_set parameters but that turned out to break some other code paths\nwhich I didn't want to change yet.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n submodule.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++\n submodule.h |  2 ++\n 2 files changed, 53 insertions(+)\n\ndiff --git a/submodule.c b/submodule.c\nindex 80851d044..9a9c52292 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -16,6 +16,7 @@\n #include \"quote.h\"\n #include \"remote.h\"\n #include \"worktree.h\"\n+#include \"repo.h\"\n \n static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n@@ -270,6 +271,56 @@ int is_submodule_initialized(const char *path)\n \treturn ret;\n }\n \n+int is_submodule_active(struct repo *repo, const char *path)\n+{\n+\tint ret = 0;\n+\tchar *key = NULL;\n+\tchar *value = NULL;\n+\tconst struct string_list *sl;\n+\tconst struct submodule *module;\n+\n+\tmodule = submodule_from_cache(repo->submodule_cache, null_sha1, path);\n+\n+\t/* early return if there isn't a path->module mapping */\n+\tif (!module)\n+\t\treturn 0;\n+\n+\t/* submodule.<name>.active is set */\n+\tkey = xstrfmt(\"submodule.%s.active\", module->name);\n+\tif (!git_configset_get_bool(repo->config, key, &ret)) {\n+\t\tfree(key);\n+\t\treturn ret;\n+\t}\n+\tfree(key);\n+\n+\t/* submodule.active is set */\n+\tsl = git_configset_get_value_multi(repo->config, \"submodule.active\");\n+\tif (sl) {\n+\t\tstruct pathspec ps;\n+\t\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\t\tconst struct string_list_item *item;\n+\n+\t\tfor_each_string_list_item(item, sl) {\n+\t\t\targv_array_push(&args, item->string);\n+\t\t}\n+\n+\t\tparse_pathspec(&ps, 0, 0, NULL, args.argv);\n+\t\tret = match_pathspec(&ps, path, strlen(path), 0, NULL, 1);\n+\n+\t\targv_array_clear(&args);\n+\t\tclear_pathspec(&ps);\n+\t\treturn ret;\n+\t}\n+\n+\t/* fallback to checking if the URL is set */\n+\tkey = xstrfmt(\"submodule.%s.url\", module->name);\n+\tret = !git_configset_get_string(repo->config, key, &value);\n+\n+\tfree(value);\n+\tfree(key);\n+\treturn ret;\n+}\n+\n int is_submodule_populated_gently(const char *path, int *return_error_code)\n {\n \tint ret = 0;\ndiff --git a/submodule.h b/submodule.h\nindex 266d81f1c..083f16ce5 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -5,6 +5,7 @@ struct diff_options;\n struct argv_array;\n struct oid_array;\n struct remote;\n+struct repo;\n \n enum {\n \tRECURSE_SUBMODULES_ONLY = -5,\n@@ -42,6 +43,7 @@ extern int submodule_config(const char *var, const char *value, void *cb);\n extern void gitmodules_config(void);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n extern int is_submodule_initialized(const char *path);\n+extern int is_submodule_active(struct repo *repo, const char *path);\n /*\n  * Determine if a submodule has been populated at a given 'path' by checking if\n  * the <path>/.git resolves to a valid git repository.\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320236","messageId":"20170518232134.163059-22-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 21/23] repo: add repo_read_gitmodules","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:32Z","receivedAt":"2017-05-18T23:23:14Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Add ability for a repository to poulate its own submodule_cache by\nreading the repository's gitmodules file.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n repo.c | 26 ++++++++++++++++++++++++++\n repo.h |  3 +++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/repo.c b/repo.c\nindex 223adf4c8..5449eb212 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -1,4 +1,6 @@\n #include \"cache.h\"\n+#include \"submodule.h\"\n+#include \"submodule-config.h\"\n #include \"repo.h\"\n \n char *\n@@ -33,6 +35,27 @@ repo_read_config(struct repo *repo)\n \t\t\t\t       NULL, &opts);\n }\n \n+static int\n+gitmodules_cb(const char *var, const char *value, void *data)\n+{\n+\tstruct repo *repo = data;\n+\treturn parse_submodule_config_option_cache(repo->submodule_cache, var, value);\n+}\n+\n+int\n+repo_read_gitmodules(struct repo *repo)\n+{\n+\tchar *gitmodules_path = xstrfmt(\"%s/.gitmodules\", repo->worktree);\n+\n+\tif (!repo->worktree)\n+\t\tdie(\"BUG: no worktree\");\n+\n+\trepo->submodule_cache = submodule_cache_alloc();\n+\tsubmodule_cache_init(repo->submodule_cache);\n+\tgit_config_from_file(gitmodules_cb, gitmodules_path, repo);\n+\treturn 0;\n+}\n+\n int\n repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n {\n@@ -83,4 +106,7 @@ repo_clear(struct repo *repo)\n \t\tgit_configset_clear(repo->config);\n \t\tfree(repo->config);\n \t}\n+\n+\tif (repo->submodule_cache)\n+\t\tsubmodule_cache_free(repo->submodule_cache);\n }\ndiff --git a/repo.h b/repo.h\nindex b4df774c3..9ff144957 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -10,10 +10,13 @@ struct repo {\n \tconst char *submodule_prefix;\n \tstruct index_state *index;\n \tstruct config_set *config;\n+\tstruct submodule_cache *submodule_cache;\n };\n \n extern int repo_read_index(struct repo *repo, const char *index_file);\n extern int repo_init(struct repo *repo, const char *gitdir, const char *worktree);\n extern void repo_clear(struct repo *repo);\n \n+extern int repo_read_gitmodules(struct repo *repo);\n+\n #endif /* REPO_H */\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320237","messageId":"20170518232134.163059-19-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 18/23] repo: add index_state to struct repo","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:29Z","receivedAt":"2017-05-18T23:23:15Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n repo.c | 19 +++++++++++++++++++\n repo.h |  2 ++\n 2 files changed, 21 insertions(+)\n\ndiff --git a/repo.c b/repo.c\nindex d47e98d95..7e5c03ac5 100644\n--- a/repo.c\n+++ b/repo.c\n@@ -2,6 +2,20 @@\n #include \"repo.h\"\n \n int\n+repo_read_index(struct repo *repo, const char *index_file)\n+{\n+\tchar *index_path = xstrfmt(\"%s/index\", repo->gitdir);\n+\tconst char *file = index_file ? index_file : index_path;\n+\n+\trepo->index = xcalloc(1, sizeof(struct index_state));\n+\tif (read_index_from(repo->index, file) < 0)\n+\t\tdie(\"failure reading index\\n\");\n+\n+\tfree(index_path);\n+\treturn 0;\n+}\n+\n+int\n repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n {\n \tint error = 0;\n@@ -39,4 +53,9 @@ repo_clear(struct repo *repo)\n \trepo->gitdir = NULL;\n \tfree(repo->worktree);\n \trepo->worktree = NULL;\n+\n+\tif (repo->index) {\n+\t\tdiscard_index(repo->index);\n+\t\tfree(repo->index);\n+\t}\n }\ndiff --git a/repo.h b/repo.h\nindex 55f2dbec6..15a0bdee9 100644\n--- a/repo.h\n+++ b/repo.h\n@@ -7,8 +7,10 @@ struct repo {\n \tchar *gitdir;\n \tchar *worktree;\n \tconst char *submodule_prefix;\n+\tstruct index_state *index;\n };\n \n+extern int repo_read_index(struct repo *repo, const char *index_file);\n extern int repo_init(struct repo *repo, const char *gitdir, const char *worktree);\n extern void repo_clear(struct repo *repo);\n \n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320238","messageId":"20170518232134.163059-18-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 17/23] repo: introduce new repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:28Z","receivedAt":"2017-05-18T23:23:16Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Introduce 'struct repo' an object used to represent a repository.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Makefile |  1 +\n repo.c   | 42 ++++++++++++++++++++++++++++++++++++++++++\n repo.h   | 15 +++++++++++++++\n 3 files changed, 58 insertions(+)\n create mode 100644 repo.c\n create mode 100644 repo.h\n\ndiff --git a/Makefile b/Makefile\nindex e35542e63..a49d2f96a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -821,6 +821,7 @@ LIB_OBJS += refs/ref-cache.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n+LIB_OBJS += repo.o\n LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\ndiff --git a/repo.c b/repo.c\nnew file mode 100644\nindex 000000000..d47e98d95\n--- /dev/null\n+++ b/repo.c\n@@ -0,0 +1,42 @@\n+#include \"cache.h\"\n+#include \"repo.h\"\n+\n+int\n+repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n+{\n+\tint error = 0;\n+\tchar *abspath = real_pathdup(gitdir, 1);\n+\tchar *suspect = xstrfmt(\"%s/.git\", abspath);\n+\tconst char *resolved_gitdir;\n+\n+\tmemset(repo, 0, sizeof(struct repo));\n+\n+\t/* First assume 'gitdir' references the gitdir directly */\n+\tresolved_gitdir = resolve_gitdir_gently(abspath, &error);\n+\t/* otherwise; try 'gitdir'.git */\n+\tif (!resolved_gitdir) {\n+\t\tresolved_gitdir = resolve_gitdir_gently(suspect, &error);\n+\t\tif (!resolved_gitdir) {\n+\t\t\tdie(\"'%s' is not a repository\\n\", abspath);\n+\t\t\treturn error;\n+\t\t}\n+\t}\n+\n+\trepo->gitdir = xstrdup(resolved_gitdir);\n+\t/* Maybe need a check to verify that a worktree is indeed a worktree? */\n+\trepo->worktree = xstrdup_or_null(worktree);\n+\n+\tfree(abspath);\n+\tfree(suspect);\n+\n+\treturn error;\n+}\n+\n+void\n+repo_clear(struct repo *repo)\n+{\n+\tfree(repo->gitdir);\n+\trepo->gitdir = NULL;\n+\tfree(repo->worktree);\n+\trepo->worktree = NULL;\n+}\ndiff --git a/repo.h b/repo.h\nnew file mode 100644\nindex 000000000..55f2dbec6\n--- /dev/null\n+++ b/repo.h\n@@ -0,0 +1,15 @@\n+#ifndef REPO_H\n+#define REPO_H\n+\n+struct index_state;\n+\n+struct repo {\n+\tchar *gitdir;\n+\tchar *worktree;\n+\tconst char *submodule_prefix;\n+};\n+\n+extern int repo_init(struct repo *repo, const char *gitdir, const char *worktree);\n+extern void repo_clear(struct repo *repo);\n+\n+#endif /* REPO_H */\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320239","messageId":"20170518232134.163059-14-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 13/23] ls-files: convert prune_cache to take an index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:24Z","receivedAt":"2017-05-18T23:23:18Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Signed-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex de02819c6..8448b04e8 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -380,30 +380,31 @@ static void show_files(struct dir_struct *dir)\n /*\n  * Prune the index to only contain stuff starting with \"prefix\"\n  */\n-static void prune_cache(const char *prefix, size_t prefixlen)\n+static void prune_index(struct index_state *istate,\n+\t\t\tconst char *prefix, size_t prefixlen)\n {\n \tint pos;\n \tunsigned int first, last;\n \n \tif (!prefix)\n \t\treturn;\n-\tpos = cache_name_pos(prefix, prefixlen);\n+\tpos = index_name_pos(istate, prefix, prefixlen);\n \tif (pos < 0)\n \t\tpos = -pos-1;\n \tfirst = pos;\n-\tlast = active_nr;\n+\tlast = istate->cache_nr;\n \twhile (last > first) {\n \t\tint next = (last + first) >> 1;\n-\t\tconst struct cache_entry *ce = active_cache[next];\n+\t\tconst struct cache_entry *ce = istate->cache[next];\n \t\tif (!strncmp(ce->name, prefix, prefixlen)) {\n \t\t\tfirst = next+1;\n \t\t\tcontinue;\n \t\t}\n \t\tlast = next;\n \t}\n-\tmemmove(active_cache, active_cache + pos,\n+\tmemmove(istate->cache, istate->cache + pos,\n \t\t(last - pos) * sizeof(struct cache_entry *));\n-\tactive_nr = last - pos;\n+\tistate->cache_nr = last - pos;\n }\n \n static int get_common_prefix_len(const char *common_prefix)\n@@ -661,7 +662,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_cache(max_prefix, max_prefix_len);\n+\tprune_index(&the_index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320240","messageId":"20170518232134.163059-24-bmwill@google.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"[WIP/RFC 23/23] ls-files: use repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-18T23:21:34Z","receivedAt":"2017-05-18T23:23:30Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert ls-files to use a repository struct and recurse submodules\ninprocess.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-files.c                     | 217 +++++++++++++++------------------\n git.c                                  |   2 +-\n t/t3007-ls-files-recurse-submodules.sh |  39 ++++++\n 3 files changed, 137 insertions(+), 121 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 456df61e4..98d448b4e 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -5,6 +5,7 @@\n  *\n  * Copyright (C) Linus Torvalds, 2005\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n@@ -16,6 +17,7 @@\n #include \"pathspec.h\"\n #include \"run-command.h\"\n #include \"submodule.h\"\n+#include \"repo.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -31,10 +33,8 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int show_eol;\n static int recurse_submodules;\n-static struct argv_array submodule_options = ARGV_ARRAY_INIT;\n \n static const char *prefix;\n-static const char *super_prefix;\n static int max_prefix_len;\n static int prefix_len;\n static struct pathspec pathspec;\n@@ -73,24 +73,11 @@ static void write_eolinfo(const struct index_state *istate,\n static void write_name(const char *name)\n {\n \t/*\n-\t * Prepend the super_prefix to name to construct the full_name to be\n-\t * written.\n-\t */\n-\tstruct strbuf full_name = STRBUF_INIT;\n-\tif (super_prefix) {\n-\t\tstrbuf_addstr(&full_name, super_prefix);\n-\t\tstrbuf_addstr(&full_name, name);\n-\t\tname = full_name.buf;\n-\t}\n-\n-\t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n \twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n \t\t\t\t   stdout, line_terminator);\n-\n-\tstrbuf_release(&full_name);\n }\n \n static const char *get_tag(const struct cache_entry *ce, const char *tag)\n@@ -209,101 +196,60 @@ static void show_killed_files(const struct index_state *istate,\n \t}\n }\n \n-/*\n- * Compile an argv_array with all of the options supported by --recurse_submodules\n- */\n-static void compile_submodule_options(const char **argv,\n-\t\t\t\t      const struct dir_struct *dir,\n-\t\t\t\t      int show_tag)\n-{\n-\tif (line_terminator == '\\0')\n-\t\targv_array_push(&submodule_options, \"-z\");\n-\tif (show_tag)\n-\t\targv_array_push(&submodule_options, \"-t\");\n-\tif (show_valid_bit)\n-\t\targv_array_push(&submodule_options, \"-v\");\n-\tif (show_cached)\n-\t\targv_array_push(&submodule_options, \"--cached\");\n-\tif (show_eol)\n-\t\targv_array_push(&submodule_options, \"--eol\");\n-\tif (debug_mode)\n-\t\targv_array_push(&submodule_options, \"--debug\");\n-\n-\t/* Add Pathspecs */\n-\targv_array_push(&submodule_options, \"--\");\n-\tfor (; *argv; argv++)\n-\t\targv_array_push(&submodule_options, *argv);\n-}\n+static void show_files(struct repo *repo, struct dir_struct *dir);\n \n-/**\n- * Recursively call ls-files on a submodule\n- */\n-static void show_gitlink(const struct cache_entry *ce)\n+static void show_submodule(const struct repo *superproject,\n+\t\t\t   struct dir_struct *dir, const char *path)\n {\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tint status;\n-\tchar *dir;\n-\n-\tprepare_submodule_repo_env(&cp.env_array);\n-\targv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);\n-\n-\tif (prefix_len)\n-\t\targv_array_pushf(&cp.env_array, \"%s=%s\",\n-\t\t\t\t GIT_TOPLEVEL_PREFIX_ENVIRONMENT,\n-\t\t\t\t prefix);\n-\targv_array_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t\t super_prefix ? super_prefix : \"\",\n-\t\t\t ce->name);\n-\targv_array_push(&cp.args, \"ls-files\");\n-\targv_array_push(&cp.args, \"--recurse-submodules\");\n-\n-\t/* add supported options */\n-\targv_array_pushv(&cp.args, submodule_options.argv);\n-\n-\tcp.git_cmd = 1;\n-\tdir = mkpathdup(\"%s/%s\", get_git_work_tree(), ce->name);\n-\tcp.dir = dir;\n-\tstatus = run_command(&cp);\n-\tfree(dir);\n-\tif (status)\n-\t\texit(status);\n+\tstruct repo submodule;\n+\tchar *gitdir = mkpathdup(\"%s/%s\", superproject->worktree, path);\n+\trepo_init(&submodule, gitdir, gitdir);\n+\n+\trepo_read_index(&submodule, NULL);\n+\trepo_read_gitmodules(&submodule);\n+\n+\tif (superproject->submodule_prefix)\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s%s/\", superproject->submodule_prefix, path);\n+\telse\n+\t\tsubmodule.submodule_prefix = xstrfmt(\"%s/\", path);\n+\tshow_files(&submodule, dir);\n+\n+\tfree((char *) submodule.submodule_prefix);\n+\trepo_clear(&submodule);\n+\tfree(gitdir);\n }\n \n-static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n+static void show_ce(struct repo *repo, struct dir_struct *dir,\n+\t\t    const struct cache_entry *ce, const char *fullname,\n+\t\t    const char *tag)\n {\n-\tstruct strbuf name = STRBUF_INIT;\n-\tint len = max_prefix_len;\n-\tif (super_prefix)\n-\t\tstrbuf_addstr(&name, super_prefix);\n-\tstrbuf_addstr(&name, ce->name);\n-\n-\tif (len > ce_namelen(ce))\n+\tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t    submodule_path_match(&pathspec, name.buf, ps_matched)) {\n-\t\tshow_gitlink(ce);\n-\t} else if (match_pathspec(&pathspec, name.buf, name.len,\n-\t\t\t\t  len, ps_matched,\n+\t    submodule_path_match(&pathspec, fullname, ps_matched) &&\n+\t    is_submodule_active(repo, ce->name)) {\n+\t\tshow_submodule(repo, dir, ce->name);\n+\t} else if (match_pathspec(&pathspec, fullname, strlen(fullname),\n+\t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n \t\t\t\t  S_ISGITLINK(ce->ce_mode))) {\n \t\ttag = get_tag(ce, tag);\n \n-\t\tif (!show_stage) {\n-\t\t\tfputs(tag, stdout);\n-\t\t} else {\n+\t\tif (show_stage) {\n \t\t\tprintf(\"%s%06o %s %d\\t\",\n \t\t\t       tag,\n \t\t\t       ce->ce_mode,\n \t\t\t       find_unique_abbrev(ce->oid.hash, abbrev),\n \t\t\t       ce_stage(ce));\n+\t\t} else {\n+\t\t\tfputs(tag, stdout);\n \t\t}\n-\t\twrite_eolinfo(&the_index, ce, ce->name);\n-\t\twrite_name(ce->name);\n+\n+\t\twrite_eolinfo(repo->index, ce, fullname);\n+\t\twrite_name(fullname);\n \t\tprint_debug(ce);\n \t}\n-\n-\tstrbuf_release(&name);\n }\n \n static void show_ru_info(const struct index_state *istate)\n@@ -336,59 +282,80 @@ static void show_ru_info(const struct index_state *istate)\n }\n \n static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n-\t\t       const struct cache_entry *ce)\n+\t\t       const char *fullname, const struct cache_entry *ce)\n {\n \tint dtype = ce_to_dtype(ce);\n-\treturn is_excluded(dir, istate, ce->name, &dtype);\n+\treturn is_excluded(dir, istate, fullname, &dtype);\n }\n \n-static void show_files(struct index_state *istate, struct dir_struct *dir)\n+static void construct_fullname(struct strbuf *out, const struct repo *repo,\n+\t\t\t       const struct cache_entry *ce)\n+{\n+\tstrbuf_reset(out);\n+\tif (repo->submodule_prefix)\n+\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tstrbuf_addstr(out, ce->name);\n+\n+}\n+\n+static void show_files(struct repo *repo, struct dir_struct *dir)\n {\n \tint i;\n+\tstruct strbuf fullname = STRBUF_INIT;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n \t\tif (!show_others)\n \t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n-\t\tfill_directory(dir, istate, &pathspec);\n+\t\tfill_directory(dir, repo->index, &pathspec);\n \t\tif (show_others)\n-\t\t\tshow_other_files(istate, dir);\n+\t\t\tshow_other_files(repo->index, dir);\n \t\tif (show_killed)\n-\t\t\tshow_killed_files(istate, dir);\n+\t\t\tshow_killed_files(repo->index, dir);\n \t}\n \tif (show_cached || show_stage) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n-\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf,\n+\t\t\t\tce_stage(ce) ? tag_unmerged :\n+\t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n+\t\t\t\t tag_cached));\n \t\t}\n \t}\n \tif (show_deleted || show_modified) {\n-\t\tfor (i = 0; i < istate->cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = istate->cache[i];\n+\t\tfor (i = 0; i < repo->index->cache_nr; i++) {\n+\t\t\tconst struct cache_entry *ce = repo->index->cache[i];\n \t\t\tstruct stat st;\n \t\t\tint err;\n+\n+\t\t\tconstruct_fullname(&fullname, repo, ce);\n+\n \t\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n-\t\t\t    !ce_excluded(dir, istate, ce))\n+\t\t\t    !ce_excluded(dir, repo->index, fullname.buf, ce))\n \t\t\t\tcontinue;\n \t\t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\t\tcontinue;\n \t\t\tif (ce_skip_worktree(ce))\n \t\t\t\tcontinue;\n-\t\t\terr = lstat(ce->name, &st);\n+\t\t\terr = lstat(fullname.buf, &st);\n \t\t\tif (show_deleted && err)\n-\t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ie_modified(istate, ce, &st, 0))\n-\t\t\t\tshow_ce_entry(tag_modified, ce);\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tif (show_modified && ie_modified(repo->index, ce, &st, 0))\n+\t\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n \t\t}\n \t}\n+\n+\tstrbuf_release(&fullname);\n }\n \n /*\n@@ -542,8 +509,9 @@ static int option_parse_exclude_standard(const struct option *opt,\n \n int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n {\n+\tstruct repo main_repository;\n \tint require_work_tree = 0, show_tag = 0, i;\n-\tconst char *max_prefix;\n+\tchar *max_prefix;\n \tstruct dir_struct dir;\n \tstruct exclude_list *el;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n@@ -613,11 +581,11 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tsuper_prefix = get_super_prefix();\n \tgit_config(git_default_config, NULL);\n \n-\tif (read_cache() < 0)\n-\t\tdie(\"index file corrupt\");\n+\trepo_init(&main_repository, get_git_dir(), get_git_work_tree());\n+\n+\trepo_read_index(&main_repository, get_index_file());\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n \t\t\tls_files_usage, 0);\n@@ -649,12 +617,14 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n-\tif (recurse_submodules)\n-\t\tcompile_submodule_options(argv, &dir, show_tag);\n+\tif (recurse_submodules) {\n+\t\trepo_read_gitmodules(&main_repository);\n+\t}\n \n \tif (recurse_submodules &&\n \t    (show_stage || show_deleted || show_others || show_unmerged ||\n-\t     show_killed || show_modified || show_resolve_undo || with_tree))\n+\t     show_killed || show_modified || show_resolve_undo || with_tree ||\n+\t     show_eol))\n \t\tdie(\"ls-files --recurse-submodules unsupported mode\");\n \n \tif (recurse_submodules && error_unmatch)\n@@ -668,7 +638,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t/*\n \t * Find common prefix for all pathspec's\n \t * This is used as a performance optimization which unfortunately cannot\n-\t * be done when recursing into submodules\n+\t * be done when recursing into submodules because when a pathspec is\n+\t * given which spans repository boundaries you can't simply remove the\n+\t * submodule entry because the pathspec may match something inside the\n+\t * submodule.\n \t */\n \tif (recurse_submodules)\n \t\tmax_prefix = NULL;\n@@ -676,7 +649,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(&the_index, max_prefix, max_prefix_len);\n+\tprune_index(main_repository.index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -697,11 +670,15 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n-\t\toverlay_tree_on_index(&the_index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(main_repository.index, with_tree, max_prefix);\n \t}\n-\tshow_files(&the_index, &dir);\n+\n+\tshow_files(&main_repository, &dir);\n+\n \tif (show_resolve_undo)\n-\t\tshow_ru_info(&the_index);\n+\t\tshow_ru_info(main_repository.index);\n+\n+\trepo_clear(&main_repository);\n \n \tif (ps_matched) {\n \t\tint bad;\ndiff --git a/git.c b/git.c\nindex 8ff44f081..8852ae944 100644\n--- a/git.c\n+++ b/git.c\n@@ -441,7 +441,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init-db\", cmd_init_db },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP_GENTLY },\n \t{ \"log\", cmd_log, RUN_SETUP },\n-\t{ \"ls-files\", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n \t{ \"ls-tree\", cmd_ls_tree, RUN_SETUP },\n \t{ \"mailinfo\", cmd_mailinfo, RUN_SETUP_GENTLY },\ndiff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh\nindex ebb956fd1..318b5bce7 100755\n--- a/t/t3007-ls-files-recurse-submodules.sh\n+++ b/t/t3007-ls-files-recurse-submodules.sh\n@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'inactive submodule' '\n+\ttest_when_finished \"git config --bool submodule.submodule.active true\" &&\n+\ttest_when_finished \"git -C submodule config --bool submodule.subsub.active true\" &&\n+\tgit config --bool submodule.submodule.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit config --bool submodule.submodule.active \"true\" &&\n+\tgit -C submodule config --bool submodule.subsub.active \"false\" &&\n+\n+\tcat >expect <<-\\EOF &&\n+\t.gitmodules\n+\ta\n+\tb/b\n+\th.txt\n+\tsib/file\n+\tsub/file\n+\tsubmodule/.gitmodules\n+\tsubmodule/c\n+\tsubmodule/f.TXT\n+\tsubmodule/g.txt\n+\tsubmodule/subsub\n+\tEOF\n+\n+\tgit ls-files --recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--recurse-submodules and pathspecs' '\n \tcat >expect <<-\\EOF &&\n \th.txt\n-- \n2.13.0.303.g4ebf302169-goog\n\n"},{"id":"320254","messageId":"623e5473-9fb0-07e4-0ac1-adabdc652c74@jeffhostetler.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-05-19T12:25:05Z","receivedAt":"2017-05-19T12:25:14Z","isPatch":false,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 5/18/2017 7:21 PM, Brandon Williams wrote:\n> When I first started working on the git project I found it very difficult to\n> understand parts of the code base because of the inherently global nature of\n> our code.  It also made working on submodules very difficult.  Since we can\n> only open up a single repository per process, you need to launch a child\n> process in order to process a submodule.  But you also need to be able to\n> communicate other stateful information to the children processes so that the\n> submodules know how best to format their output or match against a\n> pathspec...it ends up feeling like layering on hack after hack.  What I would\n> really like to do, is to have the ability to have a repository object so that I\n> can open a submodule in-process.\n> \n> Before this becomes a reality for all commands, much of the library code would\n> need to be refactored in order to work purely on handles instead of global\n> state.  As it turned out, ls-files is a pretty simple command and doesn't have\n> *too* many dependencies.  The biggest thing that needed to be changed was\n> piping through an index into a couple library routines so that they don't\n> inherently rely on 'the_index'.  A few of these changes I've sent out and can\n> be found at 'origin/bw/pathspec-sans-the-index' and\n> 'origin/bw/dir-c-stops-relying-on-the-index' which this series is based on.\n> \n> Patches 1-16 are refactorings to prepare either library code or ls-files itself\n> to be ready to handle passing around an index struct.  Patches 17-22 introduce\n> a repository struct and change a couple of things about how submodule caches\n> work (getting submodule information from .gitmodules).  And Patch 23 converts\n> ls-files to use a repository struct.\n> \n> The most interesting part of the series is from 17-23.  And 1-16 could be taken\n> as is without the rest of the series.\n> \n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n> \n> Thanks for taking the time to look at this and entertain my insane ideas :)\n\nVery nice and thanks for starting this.\nJeff\n\n"},{"id":"320280","messageId":"82cb1f56-4a26-4b27-3c8a-506821847c0e@gmail.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2017-05-19T18:28:52Z","receivedAt":"2017-05-19T18:31:40Z","isPatch":false,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"Glad to see you tackling this.  This is definitely a step in the right \ndirection.\n\nI realize that it will take a lot of work and that intermediate steps \nmay just be pushing it the global state one level higher but eventually \nit would be great to see an entire code path global state free!\n\nI'm personally interested because reducing the reliance on global state \nalso helps us in our performance work as it makes it more possible to \nuse threading to scale up the performance.\n\nBen\n\nOn 5/18/2017 7:21 PM, Brandon Williams wrote:\n> When I first started working on the git project I found it very difficult to\n> understand parts of the code base because of the inherently global nature of\n> our code.  It also made working on submodules very difficult.  Since we can\n> only open up a single repository per process, you need to launch a child\n> process in order to process a submodule.  But you also need to be able to\n> communicate other stateful information to the children processes so that the\n> submodules know how best to format their output or match against a\n> pathspec...it ends up feeling like layering on hack after hack.  What I would\n> really like to do, is to have the ability to have a repository object so that I\n> can open a submodule in-process.\n>\n> Before this becomes a reality for all commands, much of the library code would\n> need to be refactored in order to work purely on handles instead of global\n> state.  As it turned out, ls-files is a pretty simple command and doesn't have\n> *too* many dependencies.  The biggest thing that needed to be changed was\n> piping through an index into a couple library routines so that they don't\n> inherently rely on 'the_index'.  A few of these changes I've sent out and can\n> be found at 'origin/bw/pathspec-sans-the-index' and\n> 'origin/bw/dir-c-stops-relying-on-the-index' which this series is based on.\n>\n> Patches 1-16 are refactorings to prepare either library code or ls-files itself\n> to be ready to handle passing around an index struct.  Patches 17-22 introduce\n> a repository struct and change a couple of things about how submodule caches\n> work (getting submodule information from .gitmodules).  And Patch 23 converts\n> ls-files to use a repository struct.\n>\n> The most interesting part of the series is from 17-23.  And 1-16 could be taken\n> as is without the rest of the series.\n>\n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n>\n> Thanks for taking the time to look at this and entertain my insane ideas :)\n>\n> Brandon Williams (23):\n>   convert: convert get_cached_convert_stats_ascii to take an index\n>   convert: convert crlf_to_git to take an index\n>   convert: convert convert_to_git_filter_fd to take an index\n>   convert: convert convert_to_git to take an index\n>   convert: convert renormalize_buffer to take an index\n>   tree: convert read_tree to take an index parameter\n>   ls-files: convert overlay_tree_on_cache to take an index\n>   ls-files: convert write_eolinfo to take an index\n>   ls-files: convert show_killed_files to take an index\n>   ls-files: convert show_other_files to take an index\n>   ls-files: convert show_ru_info to take an index\n>   ls-files: convert ce_excluded to take an index\n>   ls-files: convert prune_cache to take an index\n>   ls-files: convert show_files to take an index\n>   ls-files: factor out debug info into a function\n>   ls-files: factor out tag calculation\n>   repo: introduce new repository object\n>   repo: add index_state to struct repo\n>   repo: add per repo config\n>   submodule-config: refactor to allow for multiple submodule_cache's\n>   repo: add repo_read_gitmodules\n>   submodule: add is_submodule_active\n>   ls-files: use repository object\n>\n>  Makefile                               |   1 +\n>  apply.c                                |   2 +-\n>  builtin/blame.c                        |   2 +-\n>  builtin/commit.c                       |   3 +-\n>  builtin/ls-files.c                     | 348 ++++++++++++++++-----------------\n>  cache.h                                |   4 +-\n>  combine-diff.c                         |   2 +-\n>  config.c                               |   2 +-\n>  convert.c                              |  31 +--\n>  convert.h                              |  19 +-\n>  diff.c                                 |   6 +-\n>  dir.c                                  |   2 +-\n>  git.c                                  |   2 +-\n>  ll-merge.c                             |   2 +-\n>  merge-recursive.c                      |   4 +-\n>  repo.c                                 | 112 +++++++++++\n>  repo.h                                 |  22 +++\n>  sha1_file.c                            |   6 +-\n>  submodule-config.c                     |  40 +++-\n>  submodule-config.h                     |  10 +\n>  submodule.c                            |  51 +++++\n>  submodule.h                            |   2 +\n>  t/t3007-ls-files-recurse-submodules.sh |  39 ++++\n>  tree.c                                 |  28 ++-\n>  tree.h                                 |   3 +-\n>  25 files changed, 513 insertions(+), 230 deletions(-)\n>  create mode 100644 repo.c\n>  create mode 100644 repo.h\n>\n"},{"id":"320324","messageId":"CAGZ79kZoCkrF_ruzkpULQVSZ7=WEgFP+8PcgDhacWBh7ZCac5Q@mail.gmail.com","threadId":"45999","inReplyTo":"20170518232134.163059-18-bmwill@google.com","subject":"Re: [WIP/RFC 17/23] repo: introduce new repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-20T21:25:20Z","receivedAt":"2017-05-20T21:25:29Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 18, 2017 at 4:21 PM, Brandon Williams <bmwill@google.com> wrote:\n> Introduce 'struct repo' an object used to represent a repository.\n\nIs this the right place to outline what you expect from a repo object?\nAre you planning to use it everywhere?\nIs it lazy-init'd and it takes care of it itself, or would the caller\nhave to take\ncare of the state of the repo? (\"the repo object is just a place to put the\ncurrent globals\")\n\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  Makefile |  1 +\n>  repo.c   | 42 ++++++++++++++++++++++++++++++++++++++++++\n>  repo.h   | 15 +++++++++++++++\n>  3 files changed, 58 insertions(+)\n>  create mode 100644 repo.c\n>  create mode 100644 repo.h\n>\n> diff --git a/Makefile b/Makefile\n> index e35542e63..a49d2f96a 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -821,6 +821,7 @@ LIB_OBJS += refs/ref-cache.o\n>  LIB_OBJS += ref-filter.o\n>  LIB_OBJS += remote.o\n>  LIB_OBJS += replace_object.o\n> +LIB_OBJS += repo.o\n>  LIB_OBJS += rerere.o\n>  LIB_OBJS += resolve-undo.o\n>  LIB_OBJS += revision.o\n> diff --git a/repo.c b/repo.c\n> new file mode 100644\n> index 000000000..d47e98d95\n> --- /dev/null\n> +++ b/repo.c\n> @@ -0,0 +1,42 @@\n> +#include \"cache.h\"\n> +#include \"repo.h\"\n> +\n> +int\n> +repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n\nstyle ;)\n\n\n> +       /* Maybe need a check to verify that a worktree is indeed a worktree? */\n\nadd NEEDSWORK/FIXME prefix to comment?\n\n> +void\n> +repo_clear(struct repo *repo)\n\nstyle ;)\n"},{"id":"320325","messageId":"CAGZ79kYY8sncbq-Zoi9iiqz+4qWOsA+y80T1RjO5c49OvY+uxA@mail.gmail.com","threadId":"45999","inReplyTo":"20170518232134.163059-19-bmwill@google.com","subject":"Re: [WIP/RFC 18/23] repo: add index_state to struct repo","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-20T21:27:25Z","receivedAt":"2017-05-20T21:27:30Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":">  int\n> +repo_read_index(struct repo *repo, const char *index_file)\n...\n> +\n> +int\n>  repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n\nThe version 2.13.0.303.g4ebf302169-goog doesn't have diff slider\nheuristics on by default, and you also did not enable it?\n(I am curious if the heuristics would have helped here)\n"},{"id":"320326","messageId":"CAGZ79kbvhRzjbfiUNuc364tM8j1TpNEtGt6rtfG2h9Y=v4TVHw@mail.gmail.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-20T21:37:59Z","receivedAt":"2017-05-20T21:38:06Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 18, 2017 at 4:21 PM, Brandon Williams <bmwill@google.com> wrote:\n\n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n\nI would be really happy to see this series land eventually.\n\nThe introduction of a repo object will deliver performance at a higher\nlevel, such as\n* (remarked by Ben): enabling of threading\n* submodules do not need to spawn processes\n* I would imagine that developer velocity will go up by having less global state\n  in the long run.\n\nThanks for working on this.\nStefan\n"},{"id":"320370","messageId":"CA+P7+xpTKWGtoauQ_radvue0SYgS9VEzS=jTghd_+N5xrX8Cwg@mail.gmail.com","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2017-05-21T08:23:20Z","receivedAt":"2017-05-21T08:23:48Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Thu, May 18, 2017 at 4:21 PM, Brandon Williams <bmwill@google.com> wrote:\n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n>\n> Thanks for taking the time to look at this and entertain my insane ideas :)\n>\n\nI haven't had time to read the patches yet, but the goal I think is\nworthy, and worth the pain. The ultimate goal allows us to more easily\nwrite submodule features (some of which are quite difficult today, due\nto having to pass in all kinds of state to the submodule, and\nlaunching a process is expensive when you have a lot of them).\n\nI can't say much about this particular code yet, but I hope to be able\nto look in more detail in the next few days.\n\nThanks,\nJake\n"},{"id":"320378","messageId":"20170521162816.xio7ttltdrlqmb6m@genre.crustytoothpaste.net","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2017-05-21T16:28:16Z","receivedAt":"2017-05-21T16:28:28Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Thu, May 18, 2017 at 04:21:11PM -0700, Brandon Williams wrote:\n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n\nI haven't spent a lot of time looking at the patches, but I like this\nidea.  I expect that moving in this direction will help us avoid a lot\nof globals and move us in a direction of more re-entrant code.  I can\nthink of a lot of things that could really benefit from this.\n-- \nbrian m. carlson / brian with sandals: Houston, Texas, US\n+1 832 623 2791 | https://www.crustytoothpaste.net/~bmc | My opinion only\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"320410","messageId":"alpine.DEB.2.21.1.1705221501540.3610@virtualbox","threadId":"45999","inReplyTo":"CAGZ79kbvhRzjbfiUNuc364tM8j1TpNEtGt6rtfG2h9Y=v4TVHw@mail.gmail.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-05-22T13:03:24Z","receivedAt":"2017-05-22T13:04:06Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Stefan,\n\nOn Sat, 20 May 2017, Stefan Beller wrote:\n\n> On Thu, May 18, 2017 at 4:21 PM, Brandon Williams <bmwill@google.com> wrote:\n> \n> > This is still very much in a WIP state, though it does pass all tests.  What\n> > I'm hoping for here is to get a discussion started about the feasibility of a\n> > change like this and hopefully to get the ball rolling.  Is this a direction we\n> > want to move in?  Is it worth the pain?\n> \n> I would be really happy to see this series land eventually.\n> \n> The introduction of a repo object will deliver performance at a higher\n> level, such as\n> * (remarked by Ben): enabling of threading\n> * submodules do not need to spawn processes\n> * I would imagine that developer velocity will go up by having less global state\n>   in the long run.\n\n* avoiding really ugly hacks such as save_env_before_alias() which are\n  even incomplete, as git_dir is not reset upon restore_env().\n\nCiao,\nDscho\n"},{"id":"320463","messageId":"20170522193535.7cgivd6pmmqhw7ze@sigill.intra.peff.net","threadId":"45999","inReplyTo":"20170518232134.163059-1-bmwill@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-05-22T19:35:35Z","receivedAt":"2017-05-22T19:35:54Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 18, 2017 at 04:21:11PM -0700, Brandon Williams wrote:\n\n> When I first started working on the git project I found it very difficult to\n> understand parts of the code base because of the inherently global nature of\n> our code.  It also made working on submodules very difficult.  Since we can\n> only open up a single repository per process, you need to launch a child\n> process in order to process a submodule.  But you also need to be able to\n> communicate other stateful information to the children processes so that the\n> submodules know how best to format their output or match against a\n> pathspec...it ends up feeling like layering on hack after hack.  What I would\n> really like to do, is to have the ability to have a repository object so that I\n> can open a submodule in-process.\n\nWe could always buy in fully to the multi-process model and just\nimplement a generic RPC protocol between the parent and submodule gits.\nDoes CORBA still exist?\n\n(No, I am not serious about any of that).\n\n> This is still very much in a WIP state, though it does pass all tests.  What\n> I'm hoping for here is to get a discussion started about the feasibility of a\n> change like this and hopefully to get the ball rolling.  Is this a direction we\n> want to move in?  Is it worth the pain?\n\nI think the really painful part is going to be all of the system calls\nthat rely on global state provided by the OS. Like, say, every\nfilesystem call that expects to find working tree files without\nprepending the working tree path.\n\nThat said, even if we never reached the point where we could handle all\nsubmodule requests in-process, I think sticking the repo-related global\nstate in a struct certainly could not hurt general readability. So it's\na good direction regardless of whether we take it all the way.\n\n-Peff\n"},{"id":"320562","messageId":"20170523172634.GA115919@google.com","threadId":"45999","inReplyTo":"20170522193535.7cgivd6pmmqhw7ze@sigill.intra.peff.net","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-23T17:26:34Z","receivedAt":"2017-05-23T17:26:42Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/22, Jeff King wrote:\n> On Thu, May 18, 2017 at 04:21:11PM -0700, Brandon Williams wrote:\n> \n> > When I first started working on the git project I found it very difficult to\n> > understand parts of the code base because of the inherently global nature of\n> > our code.  It also made working on submodules very difficult.  Since we can\n> > only open up a single repository per process, you need to launch a child\n> > process in order to process a submodule.  But you also need to be able to\n> > communicate other stateful information to the children processes so that the\n> > submodules know how best to format their output or match against a\n> > pathspec...it ends up feeling like layering on hack after hack.  What I would\n> > really like to do, is to have the ability to have a repository object so that I\n> > can open a submodule in-process.\n> \n> We could always buy in fully to the multi-process model and just\n> implement a generic RPC protocol between the parent and submodule gits.\n> Does CORBA still exist?\n> \n> (No, I am not serious about any of that).\n> \n> > This is still very much in a WIP state, though it does pass all tests.  What\n> > I'm hoping for here is to get a discussion started about the feasibility of a\n> > change like this and hopefully to get the ball rolling.  Is this a direction we\n> > want to move in?  Is it worth the pain?\n> \n> I think the really painful part is going to be all of the system calls\n> that rely on global state provided by the OS. Like, say, every\n> filesystem call that expects to find working tree files without\n> prepending the working tree path.\n\nYeah that's going to be one of the more challenging things to deal\nwith...\n\n> \n> That said, even if we never reached the point where we could handle all\n> submodule requests in-process, I think sticking the repo-related global\n> state in a struct certainly could not hurt general readability. So it's\n> a good direction regardless of whether we take it all the way.\n\nGlad you think so!\n\n-- \nBrandon Williams\n"},{"id":"320563","messageId":"20170523172908.GB115919@google.com","threadId":"45999","inReplyTo":"82cb1f56-4a26-4b27-3c8a-506821847c0e@gmail.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-23T17:29:08Z","receivedAt":"2017-05-23T17:29:16Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/19, Ben Peart wrote:\n> Glad to see you tackling this.  This is definitely a step in the\n> right direction.\n> \n> I realize that it will take a lot of work and that intermediate\n> steps may just be pushing it the global state one level higher but\n> eventually it would be great to see an entire code path global state\n> free!\n> \n> I'm personally interested because reducing the reliance on global\n> state also helps us in our performance work as it makes it more\n> possible to use threading to scale up the performance.\n\nI'm glad that more people than just me are interesting in moving in this\ndirection.  It's definitely going to take some work and hopefully I can\nconvince some more people to help achieve this goal :D\n\n> \n> Ben\n> \n> On 5/18/2017 7:21 PM, Brandon Williams wrote:\n> >When I first started working on the git project I found it very difficult to\n> >understand parts of the code base because of the inherently global nature of\n> >our code.  It also made working on submodules very difficult.  Since we can\n> >only open up a single repository per process, you need to launch a child\n> >process in order to process a submodule.  But you also need to be able to\n> >communicate other stateful information to the children processes so that the\n> >submodules know how best to format their output or match against a\n> >pathspec...it ends up feeling like layering on hack after hack.  What I would\n> >really like to do, is to have the ability to have a repository object so that I\n> >can open a submodule in-process.\n> >\n> >Before this becomes a reality for all commands, much of the library code would\n> >need to be refactored in order to work purely on handles instead of global\n> >state.  As it turned out, ls-files is a pretty simple command and doesn't have\n> >*too* many dependencies.  The biggest thing that needed to be changed was\n> >piping through an index into a couple library routines so that they don't\n> >inherently rely on 'the_index'.  A few of these changes I've sent out and can\n> >be found at 'origin/bw/pathspec-sans-the-index' and\n> >'origin/bw/dir-c-stops-relying-on-the-index' which this series is based on.\n> >\n> >Patches 1-16 are refactorings to prepare either library code or ls-files itself\n> >to be ready to handle passing around an index struct.  Patches 17-22 introduce\n> >a repository struct and change a couple of things about how submodule caches\n> >work (getting submodule information from .gitmodules).  And Patch 23 converts\n> >ls-files to use a repository struct.\n> >\n> >The most interesting part of the series is from 17-23.  And 1-16 could be taken\n> >as is without the rest of the series.\n> >\n> >This is still very much in a WIP state, though it does pass all tests.  What\n> >I'm hoping for here is to get a discussion started about the feasibility of a\n> >change like this and hopefully to get the ball rolling.  Is this a direction we\n> >want to move in?  Is it worth the pain?\n> >\n> >Thanks for taking the time to look at this and entertain my insane ideas :)\n> >\n> >Brandon Williams (23):\n> >  convert: convert get_cached_convert_stats_ascii to take an index\n> >  convert: convert crlf_to_git to take an index\n> >  convert: convert convert_to_git_filter_fd to take an index\n> >  convert: convert convert_to_git to take an index\n> >  convert: convert renormalize_buffer to take an index\n> >  tree: convert read_tree to take an index parameter\n> >  ls-files: convert overlay_tree_on_cache to take an index\n> >  ls-files: convert write_eolinfo to take an index\n> >  ls-files: convert show_killed_files to take an index\n> >  ls-files: convert show_other_files to take an index\n> >  ls-files: convert show_ru_info to take an index\n> >  ls-files: convert ce_excluded to take an index\n> >  ls-files: convert prune_cache to take an index\n> >  ls-files: convert show_files to take an index\n> >  ls-files: factor out debug info into a function\n> >  ls-files: factor out tag calculation\n> >  repo: introduce new repository object\n> >  repo: add index_state to struct repo\n> >  repo: add per repo config\n> >  submodule-config: refactor to allow for multiple submodule_cache's\n> >  repo: add repo_read_gitmodules\n> >  submodule: add is_submodule_active\n> >  ls-files: use repository object\n> >\n> > Makefile                               |   1 +\n> > apply.c                                |   2 +-\n> > builtin/blame.c                        |   2 +-\n> > builtin/commit.c                       |   3 +-\n> > builtin/ls-files.c                     | 348 ++++++++++++++++-----------------\n> > cache.h                                |   4 +-\n> > combine-diff.c                         |   2 +-\n> > config.c                               |   2 +-\n> > convert.c                              |  31 +--\n> > convert.h                              |  19 +-\n> > diff.c                                 |   6 +-\n> > dir.c                                  |   2 +-\n> > git.c                                  |   2 +-\n> > ll-merge.c                             |   2 +-\n> > merge-recursive.c                      |   4 +-\n> > repo.c                                 | 112 +++++++++++\n> > repo.h                                 |  22 +++\n> > sha1_file.c                            |   6 +-\n> > submodule-config.c                     |  40 +++-\n> > submodule-config.h                     |  10 +\n> > submodule.c                            |  51 +++++\n> > submodule.h                            |   2 +\n> > t/t3007-ls-files-recurse-submodules.sh |  39 ++++\n> > tree.c                                 |  28 ++-\n> > tree.h                                 |   3 +-\n> > 25 files changed, 513 insertions(+), 230 deletions(-)\n> > create mode 100644 repo.c\n> > create mode 100644 repo.h\n> >\n\n-- \nBrandon Williams\n"},{"id":"320564","messageId":"20170523173509.GC115919@google.com","threadId":"45999","inReplyTo":"CAGZ79kZoCkrF_ruzkpULQVSZ7=WEgFP+8PcgDhacWBh7ZCac5Q@mail.gmail.com","subject":"Re: [WIP/RFC 17/23] repo: introduce new repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-23T17:35:09Z","receivedAt":"2017-05-23T17:35:40Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/20, Stefan Beller wrote:\n> On Thu, May 18, 2017 at 4:21 PM, Brandon Williams <bmwill@google.com> wrote:\n> > Introduce 'struct repo' an object used to represent a repository.\n> \n> Is this the right place to outline what you expect from a repo object?\n> Are you planning to use it everywhere?\n> Is it lazy-init'd and it takes care of it itself, or would the caller\n> have to take\n> care of the state of the repo? (\"the repo object is just a place to put the\n> current globals\")\n\nThose are all great questions, questions that I don't think I have all\nthe answers for right now.  Since this is still in the idea phase I'm\nhoping to hear what other people think this would look like in an ideal\nworld.  I don't think everything would need to be lazy-init'd or can\neasily be done that way.  At least the index stuff isn't set up to\nbe able to do that.  I can see the config being lazy-init'd in one way\nor another, though that would require passing in a repo object instead\nof a config-set when you want to look-up a config value (which is\nprobably very reasonable) that way the config-set stored in the repo\nobject can be properly initialized.\n\n> \n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  Makefile |  1 +\n> >  repo.c   | 42 ++++++++++++++++++++++++++++++++++++++++++\n> >  repo.h   | 15 +++++++++++++++\n> >  3 files changed, 58 insertions(+)\n> >  create mode 100644 repo.c\n> >  create mode 100644 repo.h\n> >\n> > diff --git a/Makefile b/Makefile\n> > index e35542e63..a49d2f96a 100644\n> > --- a/Makefile\n> > +++ b/Makefile\n> > @@ -821,6 +821,7 @@ LIB_OBJS += refs/ref-cache.o\n> >  LIB_OBJS += ref-filter.o\n> >  LIB_OBJS += remote.o\n> >  LIB_OBJS += replace_object.o\n> > +LIB_OBJS += repo.o\n> >  LIB_OBJS += rerere.o\n> >  LIB_OBJS += resolve-undo.o\n> >  LIB_OBJS += revision.o\n> > diff --git a/repo.c b/repo.c\n> > new file mode 100644\n> > index 000000000..d47e98d95\n> > --- /dev/null\n> > +++ b/repo.c\n> > @@ -0,0 +1,42 @@\n> > +#include \"cache.h\"\n> > +#include \"repo.h\"\n> > +\n> > +int\n> > +repo_init(struct repo *repo, const char *gitdir, const char *worktree)\n> \n> style ;)\n\nDarn, I forgot to change this before sending out.  An easy fix, though I\nstill like this style better :P\n\n> \n> \n> > +       /* Maybe need a check to verify that a worktree is indeed a worktree? */\n> \n> add NEEDSWORK/FIXME prefix to comment?\n> \n> > +void\n> > +repo_clear(struct repo *repo)\n> \n> style ;)\n\n-- \nBrandon Williams\n"},{"id":"320609","messageId":"xmqqshjvhv9g.fsf@gitster.mtv.corp.google.com","threadId":"45999","inReplyTo":"20170523172634.GA115919@google.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-05-24T01:57:15Z","receivedAt":"2017-05-24T01:57:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n> On 05/22, Jeff King wrote:\n>> That said, even if we never reached the point where we could handle all\n>> submodule requests in-process, I think sticking the repo-related global\n>> state in a struct certainly could not hurt general readability. So it's\n>> a good direction regardless of whether we take it all the way.\n>\n> Glad you think so!\n\nYup, what Jeff said ;-)\n"},{"id":"320939","messageId":"CACsJy8DmsG_+ASEkisUTLejVkiOmYytvTCTQs=RCH6q=BeDAhg@mail.gmail.com","threadId":"45999","inReplyTo":"20170522193535.7cgivd6pmmqhw7ze@sigill.intra.peff.net","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-05-29T10:36:37Z","receivedAt":"2017-05-29T10:37:15Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, May 23, 2017 at 2:35 AM, Jeff King <peff@peff.net> wrote:\n> On Thu, May 18, 2017 at 04:21:11PM -0700, Brandon Williams wrote:\n>\n>> When I first started working on the git project I found it very difficult to\n>> understand parts of the code base because of the inherently global nature of\n>> our code.  It also made working on submodules very difficult.  Since we can\n>> only open up a single repository per process, you need to launch a child\n>> process in order to process a submodule.  But you also need to be able to\n>> communicate other stateful information to the children processes so that the\n>> submodules know how best to format their output or match against a\n>> pathspec...it ends up feeling like layering on hack after hack.  What I would\n>> really like to do, is to have the ability to have a repository object so that I\n>> can open a submodule in-process.\n>\n> We could always buy in fully to the multi-process model and just\n> implement a generic RPC protocol between the parent and submodule gits.\n> Does CORBA still exist?\n>\n> (No, I am not serious about any of that).\n\nCORBA or not, submodule IPC is a real pain. That was what I felt\nreading the super-prefix changes a few weeks ago. Some operations\nmight benefit from staying in the same process, but probably not all\n(and we lose process protection, which sometimes is a good thing)\n\n>> This is still very much in a WIP state, though it does pass all tests.  What\n>> I'm hoping for here is to get a discussion started about the feasibility of a\n>> change like this and hopefully to get the ball rolling.  Is this a direction we\n>> want to move in?  Is it worth the pain?\n>\n> I think the really painful part is going to be all of the system calls\n> that rely on global state provided by the OS. Like, say, every\n> filesystem call that expects to find working tree files without\n> prepending the working tree path.\n>\n> That said, even if we never reached the point where we could handle all\n> submodule requests in-process, I think sticking the repo-related global\n> state in a struct certainly could not hurt general readability. So it's\n> a good direction regardless of whether we take it all the way.\n\nI doubt we would reach the point where libgit.a can handle all\nsubmodule operations in-process either. That would put libgit.a in a\ndirect competitor position with libgit2. I do hope though that having\nclearer/modular data structure will improve readability, not hurt it\n(e.g. you see the data model and could largely guess how the code\ninteracts before digging deep in).\n-- \nDuy\n"},{"id":"320949","messageId":"CACBZZX5GRxecDQkoqLv55FLuiSohGSR3U1U+sG0vFFpexcc54A@mail.gmail.com","threadId":"45999","inReplyTo":"CACsJy8DmsG_+ASEkisUTLejVkiOmYytvTCTQs=RCH6q=BeDAhg@mail.gmail.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-05-29T11:23:22Z","receivedAt":"2017-05-29T11:23:54Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, May 29, 2017 at 12:36 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Tue, May 23, 2017 at 2:35 AM, Jeff King <peff@peff.net> wrote:\n>> On Thu, May 18, 2017 at 04:21:11PM -0700, Brandon Williams wrote:\n>>\n>>> When I first started working on the git project I found it very difficult to\n>>> understand parts of the code base because of the inherently global nature of\n>>> our code.  It also made working on submodules very difficult.  Since we can\n>>> only open up a single repository per process, you need to launch a child\n>>> process in order to process a submodule.  But you also need to be able to\n>>> communicate other stateful information to the children processes so that the\n>>> submodules know how best to format their output or match against a\n>>> pathspec...it ends up feeling like layering on hack after hack.  What I would\n>>> really like to do, is to have the ability to have a repository object so that I\n>>> can open a submodule in-process.\n>>\n>> We could always buy in fully to the multi-process model and just\n>> implement a generic RPC protocol between the parent and submodule gits.\n>> Does CORBA still exist?\n>>\n>> (No, I am not serious about any of that).\n>\n> CORBA or not, submodule IPC is a real pain. That was what I felt\n> reading the super-prefix changes a few weeks ago. Some operations\n> might benefit from staying in the same process, but probably not all\n> (and we lose process protection, which sometimes is a good thing)\n>\n>>> This is still very much in a WIP state, though it does pass all tests.  What\n>>> I'm hoping for here is to get a discussion started about the feasibility of a\n>>> change like this and hopefully to get the ball rolling.  Is this a direction we\n>>> want to move in?  Is it worth the pain?\n>>\n>> I think the really painful part is going to be all of the system calls\n>> that rely on global state provided by the OS. Like, say, every\n>> filesystem call that expects to find working tree files without\n>> prepending the working tree path.\n>>\n>> That said, even if we never reached the point where we could handle all\n>> submodule requests in-process, I think sticking the repo-related global\n>> state in a struct certainly could not hurt general readability. So it's\n>> a good direction regardless of whether we take it all the way.\n>\n> I doubt we would reach the point where libgit.a can handle all\n> submodule operations in-process either. That would put libgit.a in a\n> direct competitor position with libgit2.\n\nWouldn't that be a good thing? We already have some users (e.g.\nMicrosoft) choosing not to use libgit and instead use git.git because\nthe latter is generally more mature, if git.git gains more libgit\nfeatures without harming other things it'll be more useful to more\npeople.\n"},{"id":"320952","messageId":"CACsJy8AtMNAE=5jihV+sYZqyx40JCJ0hkZAvqFbkOU1g5sZSYA@mail.gmail.com","threadId":"45999","inReplyTo":"CACBZZX5GRxecDQkoqLv55FLuiSohGSR3U1U+sG0vFFpexcc54A@mail.gmail.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-05-29T11:31:05Z","receivedAt":"2017-05-29T11:31:40Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, May 29, 2017 at 6:23 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>>> That said, even if we never reached the point where we could handle all\n>>> submodule requests in-process, I think sticking the repo-related global\n>>> state in a struct certainly could not hurt general readability. So it's\n>>> a good direction regardless of whether we take it all the way.\n>>\n>> I doubt we would reach the point where libgit.a can handle all\n>> submodule operations in-process either. That would put libgit.a in a\n>> direct competitor position with libgit2.\n>\n> Wouldn't that be a good thing? We already have some users (e.g.\n> Microsoft) choosing not to use libgit and instead use git.git because\n> the latter is generally more mature, if git.git gains more libgit\n> features without harming other things it'll be more useful to more\n> people.\n\nWhether it's a good thing might depend on view point. Similar to linux\nkernel, we might want some freedom to break ABI and refactor the code.\nBut I think it's too early  to discuss this right now. There's lots of\nwork (the \"die()\" minefield comes to mind) before we reach the point\nwhere libgit.a may be good enough for external use.\n-- \nDuy\n"},{"id":"321034","messageId":"20170530171217.GB2798@google.com","threadId":"45999","inReplyTo":"CACsJy8AtMNAE=5jihV+sYZqyx40JCJ0hkZAvqFbkOU1g5sZSYA@mail.gmail.com","subject":"Re: [WIP/RFC 00/23] repository object","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-05-30T17:12:17Z","receivedAt":"2017-05-30T17:12:26Z","isPatch":false,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 05/29, Duy Nguyen wrote:\n> On Mon, May 29, 2017 at 6:23 PM, Ævar Arnfjörð Bjarmason\n> <avarab@gmail.com> wrote:\n> >>> That said, even if we never reached the point where we could handle all\n> >>> submodule requests in-process, I think sticking the repo-related global\n> >>> state in a struct certainly could not hurt general readability. So it's\n> >>> a good direction regardless of whether we take it all the way.\n> >>\n> >> I doubt we would reach the point where libgit.a can handle all\n> >> submodule operations in-process either. That would put libgit.a in a\n> >> direct competitor position with libgit2.\n> >\n> > Wouldn't that be a good thing? We already have some users (e.g.\n> > Microsoft) choosing not to use libgit and instead use git.git because\n> > the latter is generally more mature, if git.git gains more libgit\n> > features without harming other things it'll be more useful to more\n> > people.\n> \n> Whether it's a good thing might depend on view point. Similar to linux\n> kernel, we might want some freedom to break ABI and refactor the code.\n> But I think it's too early  to discuss this right now. There's lots of\n> work (the \"die()\" minefield comes to mind) before we reach the point\n> where libgit.a may be good enough for external use.\n\nMy personal end goal is making the code easier to parse and to make\nsubmodule work easier.  I know I've only worked on the project for a\nshort time but I already regret some of the submodule changes that I've\nmade because they are straight up hacks which I want to eradicate sooner\nrather than later (just look at my patches to get 'git grep' to handle\nsubmodules...).\n\nI wasn't thinking about libgit2 and don't really haven't thought too\nmuch about the possibility of being in competition with that project.\n\n-- \nBrandon Williams\n"}]}