{"thread":{"id":"48624","subject":"[PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","startedAt":"2018-06-01T16:12:06Z","lastAt":"2018-06-14T20:57:42Z","messageCount":92,"participants":["Nguyễn Thái Ngọc Duy","Elijah Newren","Stefan Beller","Duy Nguyen","Brandon Williams","Ramsay Jones"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"349002","messageId":"20180601161153.15192-1-pclouds@gmail.com","threadId":"48624","inReplyTo":null,"subject":"[PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-01T16:11:53Z","receivedAt":"2018-06-01T16:12:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"unpack-trees code works on multiple indexes specified in\nunpack_trees_options. Although they normally all refer to the_index at\nthe call site, that is the caller's business. unpack-trees.c should\nnot make any assumption about that and should use the correct index\nfield in unpack_trees_options.\n\nThis patch is actually confusing because sometimes the function\nparameter is also named \"the_index\" while some other times \"the_index\"\nis the global variable because the function just does not have a\nparameter of the same name! The only subtle difference is that the\nfunction parameter is a pointer while the global one is not.\n\nThis is more of a bug report than an actual fix because I'm not sure\nif \"o->src_index\" is always the correct answer instead of \"the_index\"\nhere. But this is very similar to 7db118303a (unpack_trees: fix\nbreakage when o->src_index != o->dst_index - 2018-04-23) and could\npotentially break things again...\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 45 ++++++++++++++++++++++++++-------------------\n 1 file changed, 26 insertions(+), 19 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3a85a02a77..114496cfc2 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -18,6 +18,9 @@\n #include \"fsmonitor.h\"\n #include \"fetch-object.h\"\n \n+/* Do not use the_index here, you probably want o->src_index */\n+#define the_index the_index_should_not_be_used here\n+\n /*\n  * Error messages expected by scripts out of plumbing commands such as\n  * read-tree.  Non-scripted Porcelain is not required to use these messages\n@@ -1085,13 +1088,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n \treturn mask;\n }\n \n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval);\n \n /* Whole directory matching */\n-static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_dir(struct index_state *istate,\n+\t\t\t      struct cache_entry **cache, int nr,\n \t\t\t      struct strbuf *prefix,\n \t\t\t      char *basename,\n \t\t\t      int select_mask, int clear_mask,\n@@ -1100,7 +1105,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \tstruct cache_entry **cache_end;\n \tint dtype = DT_DIR;\n \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n-\t\t\t\t\tbasename, &dtype, el, &the_index);\n+\t\t\t\t\tbasename, &dtype, el, istate);\n \tint rc;\n \n \tstrbuf_addch(prefix, '/');\n@@ -1122,7 +1127,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \t * calling clear_ce_flags_1(). That function will call\n \t * the expensive is_excluded_from_list() on every entry.\n \t */\n-\trc = clear_ce_flags_1(cache, cache_end - cache,\n+\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t      prefix,\n \t\t\t      select_mask, clear_mask,\n \t\t\t      el, ret);\n@@ -1145,7 +1150,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n  *   cache[0]->name[0..(prefix_len-1)]\n  * Top level path has prefix_len zero.\n  */\n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval)\n@@ -1179,7 +1185,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\tlen = slash - name;\n \t\t\tstrbuf_add(prefix, name, len);\n \n-\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n+\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n \t\t\t\t\t\t       prefix,\n \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n \t\t\t\t\t\t       select_mask, clear_mask,\n@@ -1193,7 +1199,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\t}\n \n \t\t\tstrbuf_addch(prefix, '/');\n-\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n+\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t\t\t\t  prefix,\n \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n@@ -1203,7 +1209,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t/* Non-directory */\n \t\tdtype = ce_to_dtype(ce);\n \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n-\t\t\t\t\t    name, &dtype, el, &the_index);\n+\t\t\t\t\t    name, &dtype, el, istate);\n \t\tif (ret < 0)\n \t\t\tret = defval;\n \t\tif (ret > 0)\n@@ -1213,15 +1219,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \treturn nr - (cache_end - cache);\n }\n \n-static int clear_ce_flags(struct cache_entry **cache, int nr,\n-\t\t\t    int select_mask, int clear_mask,\n-\t\t\t    struct exclude_list *el)\n+static int clear_ce_flags(struct index_state *istate,\n+\t\t\t  int select_mask, int clear_mask,\n+\t\t\t  struct exclude_list *el)\n {\n \tstatic struct strbuf prefix = STRBUF_INIT;\n \n \tstrbuf_reset(&prefix);\n \n-\treturn clear_ce_flags_1(cache, nr,\n+\treturn clear_ce_flags_1(istate,\n+\t\t\t\tistate->cache,\n+\t\t\t\tistate->cache_nr,\n \t\t\t\t&prefix,\n \t\t\t\tselect_mask, clear_mask,\n \t\t\t\tel, 0);\n@@ -1231,7 +1239,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n  */\n static void mark_new_skip_worktree(struct exclude_list *el,\n-\t\t\t\t   struct index_state *the_index,\n+\t\t\t\t   struct index_state *istate,\n \t\t\t\t   int select_flag, int skip_wt_flag)\n {\n \tint i;\n@@ -1240,8 +1248,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 1. Pretend the narrowest worktree: only unmerged entries\n \t * are checked out\n \t */\n-\tfor (i = 0; i < the_index->cache_nr; i++) {\n-\t\tstruct cache_entry *ce = the_index->cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \n \t\tif (select_flag && !(ce->ce_flags & select_flag))\n \t\t\tcontinue;\n@@ -1256,8 +1264,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n-\t\t       select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n@@ -1636,7 +1643,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);\n+\ti = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\treturn o->gently ? -1 :\n \t\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);\n@@ -1678,7 +1685,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\treturn 0;\n \n \tif (o->dir &&\n-\t    is_excluded(o->dir, &the_index, name, &dtype))\n+\t    is_excluded(o->dir, o->src_index, name, &dtype))\n \t\t/*\n \t\t * ce->name is explicitly excluded, so it is Ok to\n \t\t * overwrite it.\n-- \n2.18.0.rc0.309.g77c7720784\n\n"},{"id":"349007","messageId":"CABPp-BFaFR-ZTg2Wj4gcBPLyb4sejw+guNhWRFXfRRR0UZq4nw@mail.gmail.com","threadId":"48624","inReplyTo":"20180601161153.15192-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-01T18:34:20Z","receivedAt":"2018-06-01T18:34:31Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi,\n\nOn Fri, Jun 1, 2018 at 9:11 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> unpack-trees code works on multiple indexes specified in\n> unpack_trees_options. Although they normally all refer to the_index at\n> the call site, that is the caller's business. unpack-trees.c should\n> not make any assumption about that and should use the correct index\n> field in unpack_trees_options.\n>\n> This patch is actually confusing because sometimes the function\n> parameter is also named \"the_index\" while some other times \"the_index\"\n> is the global variable because the function just does not have a\n> parameter of the same name! The only subtle difference is that the\n> function parameter is a pointer while the global one is not.\n>\n> This is more of a bug report than an actual fix because I'm not sure\n> if \"o->src_index\" is always the correct answer instead of \"the_index\"\n> here. But this is very similar to 7db118303a (unpack_trees: fix\n> breakage when o->src_index != o->dst_index - 2018-04-23) and could\n> potentially break things again...\n\nActually, I don't think the patch will break anything in the current\ncode.  Currently, all callers of unpack_trees() (even merge recursive\nwhich uses different src_index and dst_index now) set src_index =\n&the_index.  So, these changes should continue to work as before (with\na minor possible exception of merge-recursive calling into other\nfunctions from unpack-trees.c after unpack_trees() has finished..).\nThat's not to say that your patch is bug free, just that I think any\nbugs shouldn't be triggerable from the current codebase.\n\nAlso, if any of the changes you made are wrong, what was there before\nwas also clearly wrong.  So I think we're at least no worse off.\n\nBut, I agree, it's not easy to verify what the correct thing should be\nin all cases.  I'll try to take a closer look in the next couple days.\n\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  unpack-trees.c | 45 ++++++++++++++++++++++++++-------------------\n>  1 file changed, 26 insertions(+), 19 deletions(-)\n>\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 3a85a02a77..114496cfc2 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -18,6 +18,9 @@\n>  #include \"fsmonitor.h\"\n>  #include \"fetch-object.h\"\n>\n> +/* Do not use the_index here, you probably want o->src_index */\n> +#define the_index the_index_should_not_be_used here\n\nGood call.\n"},{"id":"349008","messageId":"CAGZ79kbOKPgBPJpoez7S5k7Y6L-+ncjcAvs3MaADLT1z_dv3+A@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BFaFR-ZTg2Wj4gcBPLyb4sejw+guNhWRFXfRRR0UZq4nw@mail.gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-01T18:51:29Z","receivedAt":"2018-06-01T18:51:33Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Jun 1, 2018 at 11:34 AM, Elijah Newren <newren@gmail.com> wrote:\n\n>> +/* Do not use the_index here, you probably want o->src_index */\n>> +#define the_index the_index_should_not_be_used here\n>\n> Good call.\n\nIs the space instead of the underscore between the last two words intentional?\n"},{"id":"349068","messageId":"CACsJy8A4mAuq0rCdvR+JmY7Ghcy4nqVvyQEUNC=7JUY_x+PTYA@mail.gmail.com","threadId":"48624","inReplyTo":"CAGZ79kbOKPgBPJpoez7S5k7Y6L-+ncjcAvs3MaADLT1z_dv3+A@mail.gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-02T05:01:27Z","receivedAt":"2018-06-02T05:02:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jun 1, 2018 at 8:51 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Fri, Jun 1, 2018 at 11:34 AM, Elijah Newren <newren@gmail.com> wrote:\n>\n>>> +/* Do not use the_index here, you probably want o->src_index */\n>>> +#define the_index the_index_should_not_be_used here\n>>\n>> Good call.\n>\n> Is the space instead of the underscore between the last two words intentional?\n\nUnintentional. I wanted gcc to show this phrase when a developer\naccidentally uses the_index here (it's basically\n\"the_index_should_not_be_used_here is not declared blah blah\"). Two\nwords would cause a different syntax error.\n-- \nDuy\n"},{"id":"349069","messageId":"CACsJy8Ai5befewi9OxKzUxTOOOON9wgWpqcNy3AuK1YBk7MbxQ@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BFaFR-ZTg2Wj4gcBPLyb4sejw+guNhWRFXfRRR0UZq4nw@mail.gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-02T05:03:27Z","receivedAt":"2018-06-02T05:04:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jun 1, 2018 at 8:34 PM, Elijah Newren <newren@gmail.com> wrote:\n> Hi,\n>\n> On Fri, Jun 1, 2018 at 9:11 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> unpack-trees code works on multiple indexes specified in\n>> unpack_trees_options. Although they normally all refer to the_index at\n>> the call site, that is the caller's business. unpack-trees.c should\n>> not make any assumption about that and should use the correct index\n>> field in unpack_trees_options.\n>>\n>> This patch is actually confusing because sometimes the function\n>> parameter is also named \"the_index\" while some other times \"the_index\"\n>> is the global variable because the function just does not have a\n>> parameter of the same name! The only subtle difference is that the\n>> function parameter is a pointer while the global one is not.\n>>\n>> This is more of a bug report than an actual fix because I'm not sure\n>> if \"o->src_index\" is always the correct answer instead of \"the_index\"\n>> here. But this is very similar to 7db118303a (unpack_trees: fix\n>> breakage when o->src_index != o->dst_index - 2018-04-23) and could\n>> potentially break things again...\n>\n> Actually, I don't think the patch will break anything in the current\n> code.  Currently, all callers of unpack_trees() (even merge recursive\n> which uses different src_index and dst_index now) set src_index =\n> &the_index.  So, these changes should continue to work as before (with\n> a minor possible exception of merge-recursive calling into other\n> functions from unpack-trees.c after unpack_trees() has finished..).\n> That's not to say that your patch is bug free, just that I think any\n> bugs shouldn't be triggerable from the current codebase.\n\nAh.. I thought merge-recursive would do fancier things and used some\ntemporary index. Good to know.\n\n> Also, if any of the changes you made are wrong, what was there before\n> was also clearly wrong.  So I think we're at least no worse off.\n>\n> But, I agree, it's not easy to verify what the correct thing should be\n> in all cases.  I'll try to take a closer look in the next couple days.\n\nThanks. I will also stare at this code some more in the next couple\ndays trying to remember what these functions do.\n-- \nDuy\n"},{"id":"349107","messageId":"CABPp-BEMUUrYd_=a1sPYV941rMCdWh_x-4j5uUiCEUFA0Fwoww@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8Ai5befewi9OxKzUxTOOOON9wgWpqcNy3AuK1YBk7MbxQ@mail.gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-03T04:58:41Z","receivedAt":"2018-06-03T04:58:46Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jun 1, 2018 at 10:03 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Fri, Jun 1, 2018 at 8:34 PM, Elijah Newren <newren@gmail.com> wrote:\n>> On Fri, Jun 1, 2018 at 9:11 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>>> This is more of a bug report than an actual fix because I'm not sure\n>>> if \"o->src_index\" is always the correct answer instead of \"the_index\"\n>>> here. But this is very similar to 7db118303a (unpack_trees: fix\n>>> breakage when o->src_index != o->dst_index - 2018-04-23) and could\n>>> potentially break things again...\n\nI'm pretty sure your patch is correct.  Adding Brandon Williams to the\ncc for comment since his patches came up in the analysis below...\n\n>> Actually, I don't think the patch will break anything in the current\n>> code.  Currently, all callers of unpack_trees() (even merge recursive\n>> which uses different src_index and dst_index now) set src_index =\n>> &the_index.  So, these changes should continue to work as before (with\n>> a minor possible exception of merge-recursive calling into other\n>> functions from unpack-trees.c after unpack_trees() has finished..).\n>> That's not to say that your patch is bug free, just that I think any\n>> bugs shouldn't be triggerable from the current codebase.\n>\n> Ah.. I thought merge-recursive would do fancier things and used some\n> temporary index. Good to know.\n\nWell, it does does use a temporary index, but for dst_index rather\nthan src_index.  It then does some fancier things, but not until the\ncall to unpack_trees() is over.  In particular, at that point, it\nswaps the_index and tmp_index, reversing their roles so that now\ntmp_index is the original index and the_index becomes the result after\nunpack_trees() is run.  That's done because I later want to use the\noriginal index for calling verify_uptodate().  verify_uptodate() is\nthen used for was_tracked_and_matches() and was_tracked().\n\nAnyway, the whole upshot of this is:\n  * merge-recursive uses src_index == &the_index for the unpack_trees() call.\n  * merge-recursive uses src_index == o->orig_index for subsequent\ncalls to verify_uptodate(), but verify_uptodate() doesn't call into\nany of the sites you have modified.\n\nFurther:\n  * Every other existing caller of unpack-trees in the code sets\nsrc_index == &the_index, so this won't break any of them.\n  * There are only two callers in the codebase that set dst_index to\nsomething other than &the_index -- diff-lib.c (which sets it to NULL)\nand merge-recursive (which does the stuff described above).\n\nSo, having done that analysis, I am now pretty convinced your patch\nwon't break anything.  That's one half...\n\n>> Also, if any of the changes you made are wrong, what was there before\n>> was also clearly wrong.  So I think we're at least no worse off.\n>>\n>> But, I agree, it's not easy to verify what the correct thing should be\n>> in all cases.  I'll try to take a closer look in the next couple days.\n>\n> Thanks. I will also stare at this code some more in the next couple\n> days trying to remember what these functions do.\n\nYour patch has two divisible parts:\n\n1) Your modifications to\n  * clear_ce_flags_1()\n  * clear_ce_flags_dir()\n  * clear_ce_flags()\n  * mark_new_skip_worktree()\nThe clear_ce_flags*() functions are only called by each other and by\nmark_new_skip_worktree(), which in turn is only called from\nunpack_trees().  Also, in all of these, your change ends up only\nmodifying what index_state is passed to is_excluded_from_list().\n\n2) Your modifications to\n  * verify_clean_subdirectory()\n  * check_ok_to_remove()\nIn this case, the former is only called by the latter, and the latter\nends up only being called (via verify_absent_1()) from verify_absent()\nand verify_absent_sparse().\n\nI'll address each, in reverse order.\n\n2) The stuff that affects verify_absent()\n\nWhile verify_absent() is not called from merge-recursive right now, it\nwas something I wanted to use in the future for very similar reasons\nthat verify_uptodate() started being called directly from\nmerge-recursive.  In particular, if the rewrite of merge-recursive[A]\nI want to do sets index_only when calling unpack_trees(), then does\nthe whole merge without touching the worktree, then at the end goes to\nupdate the working tree, it will need to do extra checks.\nverify_absent() will come in handy as one of those extra checks.  For\nthat case, using the_index (the new index just created with lots of\nchanges) would be wrong in all the same ways that using the_index\ncaused massive problems for was_tracked() in merge-recursive (e.g. the\nblow up of when Junio merged the original directory rename detection\nseries into master and subsequently reverted it); we'd instead want\nsrc_index (which was the index that existed when merge was called)\ninstead.  So, with this patch you've fixed some important bugs that I\nwould have hit later.\n\n[A] sidenote: see\nhttps://public-inbox.org/git/xmqqk1ydkbx0.fsf@gitster.mtv.corp.google.com/\nfor more details\n\n1) mark_new_skip_worktree() ... is_excluded_from_list().\n\nSadly, I'm not very familiar with the skip_worktree and sparse\ncheckout stuff.  However, the fact that mark_new_skip_worktree()\nexplicitly takes an index_state (and a different one is passed to it\nthe two different times it is called), and that it is the only caller\nof the clear_ce_flags*() family of functions, and that those function\nuse the cache entries from the index passed to them in all cases other\nthan the calls to is_excluded_from_list() makes those two look like\noversights.  In fact, a little more digging turns up commit\n   fba92be8f7 (\"dir: convert is_excluded_from_list to take an index\",\n2017-05-05)\nand before then, those functions didn't use the_index directly.  But\nthey did use it indirectly, because they called a function in dir.c\nthat had it hardcoded.  So it looks like Brandon fixed part of the bug\nfor us, but moved the incorrect hardcoding from dir.c to\nunpack-trees.c.  Your patch is just fixing it up.  In fact, a little\nmore digging turns up:\n\n2c1eb10454 (\"dir: convert read_directory to take an index\", 2017-05-05)\na0bba65b10 (\"dir: convert is_excluded to take an index\", 2017-05-05)\n\nwhich appear to be the culprits behind the other two uses of the_index\ncalled from verify_absent().  It looks like before these commits that\nunpack_trees() was carefully using the appropriate index, except that\nfunctions in dir.c had use of the_index hardcoded.  Brandon fix the\nfunctions in dir.c for us, but ended up still hardcoding the_index in\nunpack-trees.c.  Basically, he did most of the necessary lifting, and\nyour patch just finally changes them over to use the correct index.\n\nBrandon: Does anything look off in my analysis above?\n"},{"id":"349289","messageId":"20180604173338.GA91449@google.com","threadId":"48624","inReplyTo":"CABPp-BEMUUrYd_=a1sPYV941rMCdWh_x-4j5uUiCEUFA0Fwoww@mail.gmail.com","subject":"Re: [PATCH/RFC/BUG] unpack-trees.c: do not use \"the_index\"","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-04T17:33:38Z","receivedAt":"2018-06-04T17:33:44Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/02, Elijah Newren wrote:\n> On Fri, Jun 1, 2018 at 10:03 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> > On Fri, Jun 1, 2018 at 8:34 PM, Elijah Newren <newren@gmail.com> wrote:\n> >> On Fri, Jun 1, 2018 at 9:11 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> >>> This is more of a bug report than an actual fix because I'm not sure\n> >>> if \"o->src_index\" is always the correct answer instead of \"the_index\"\n> >>> here. But this is very similar to 7db118303a (unpack_trees: fix\n> >>> breakage when o->src_index != o->dst_index - 2018-04-23) and could\n> >>> potentially break things again...\n> \n> I'm pretty sure your patch is correct.  Adding Brandon Williams to the\n> cc for comment since his patches came up in the analysis below...\n> \n> >> Actually, I don't think the patch will break anything in the current\n> >> code.  Currently, all callers of unpack_trees() (even merge recursive\n> >> which uses different src_index and dst_index now) set src_index =\n> >> &the_index.  So, these changes should continue to work as before (with\n> >> a minor possible exception of merge-recursive calling into other\n> >> functions from unpack-trees.c after unpack_trees() has finished..).\n> >> That's not to say that your patch is bug free, just that I think any\n> >> bugs shouldn't be triggerable from the current codebase.\n> >\n> > Ah.. I thought merge-recursive would do fancier things and used some\n> > temporary index. Good to know.\n> \n> Well, it does does use a temporary index, but for dst_index rather\n> than src_index.  It then does some fancier things, but not until the\n> call to unpack_trees() is over.  In particular, at that point, it\n> swaps the_index and tmp_index, reversing their roles so that now\n> tmp_index is the original index and the_index becomes the result after\n> unpack_trees() is run.  That's done because I later want to use the\n> original index for calling verify_uptodate().  verify_uptodate() is\n> then used for was_tracked_and_matches() and was_tracked().\n> \n> Anyway, the whole upshot of this is:\n>   * merge-recursive uses src_index == &the_index for the unpack_trees() call.\n>   * merge-recursive uses src_index == o->orig_index for subsequent\n> calls to verify_uptodate(), but verify_uptodate() doesn't call into\n> any of the sites you have modified.\n> \n> Further:\n>   * Every other existing caller of unpack-trees in the code sets\n> src_index == &the_index, so this won't break any of them.\n>   * There are only two callers in the codebase that set dst_index to\n> something other than &the_index -- diff-lib.c (which sets it to NULL)\n> and merge-recursive (which does the stuff described above).\n> \n> So, having done that analysis, I am now pretty convinced your patch\n> won't break anything.  That's one half...\n> \n> >> Also, if any of the changes you made are wrong, what was there before\n> >> was also clearly wrong.  So I think we're at least no worse off.\n> >>\n> >> But, I agree, it's not easy to verify what the correct thing should be\n> >> in all cases.  I'll try to take a closer look in the next couple days.\n> >\n> > Thanks. I will also stare at this code some more in the next couple\n> > days trying to remember what these functions do.\n> \n> Your patch has two divisible parts:\n> \n> 1) Your modifications to\n>   * clear_ce_flags_1()\n>   * clear_ce_flags_dir()\n>   * clear_ce_flags()\n>   * mark_new_skip_worktree()\n> The clear_ce_flags*() functions are only called by each other and by\n> mark_new_skip_worktree(), which in turn is only called from\n> unpack_trees().  Also, in all of these, your change ends up only\n> modifying what index_state is passed to is_excluded_from_list().\n> \n> 2) Your modifications to\n>   * verify_clean_subdirectory()\n>   * check_ok_to_remove()\n> In this case, the former is only called by the latter, and the latter\n> ends up only being called (via verify_absent_1()) from verify_absent()\n> and verify_absent_sparse().\n> \n> I'll address each, in reverse order.\n> \n> 2) The stuff that affects verify_absent()\n> \n> While verify_absent() is not called from merge-recursive right now, it\n> was something I wanted to use in the future for very similar reasons\n> that verify_uptodate() started being called directly from\n> merge-recursive.  In particular, if the rewrite of merge-recursive[A]\n> I want to do sets index_only when calling unpack_trees(), then does\n> the whole merge without touching the worktree, then at the end goes to\n> update the working tree, it will need to do extra checks.\n> verify_absent() will come in handy as one of those extra checks.  For\n> that case, using the_index (the new index just created with lots of\n> changes) would be wrong in all the same ways that using the_index\n> caused massive problems for was_tracked() in merge-recursive (e.g. the\n> blow up of when Junio merged the original directory rename detection\n> series into master and subsequently reverted it); we'd instead want\n> src_index (which was the index that existed when merge was called)\n> instead.  So, with this patch you've fixed some important bugs that I\n> would have hit later.\n> \n> [A] sidenote: see\n> https://public-inbox.org/git/xmqqk1ydkbx0.fsf@gitster.mtv.corp.google.com/\n> for more details\n> \n> 1) mark_new_skip_worktree() ... is_excluded_from_list().\n> \n> Sadly, I'm not very familiar with the skip_worktree and sparse\n> checkout stuff.  However, the fact that mark_new_skip_worktree()\n> explicitly takes an index_state (and a different one is passed to it\n> the two different times it is called), and that it is the only caller\n> of the clear_ce_flags*() family of functions, and that those function\n> use the cache entries from the index passed to them in all cases other\n> than the calls to is_excluded_from_list() makes those two look like\n> oversights.  In fact, a little more digging turns up commit\n>    fba92be8f7 (\"dir: convert is_excluded_from_list to take an index\",\n> 2017-05-05)\n> and before then, those functions didn't use the_index directly.  But\n> they did use it indirectly, because they called a function in dir.c\n> that had it hardcoded.  So it looks like Brandon fixed part of the bug\n> for us, but moved the incorrect hardcoding from dir.c to\n> unpack-trees.c.  Your patch is just fixing it up.  In fact, a little\n> more digging turns up:\n> \n> 2c1eb10454 (\"dir: convert read_directory to take an index\", 2017-05-05)\n> a0bba65b10 (\"dir: convert is_excluded to take an index\", 2017-05-05)\n> \n> which appear to be the culprits behind the other two uses of the_index\n> called from verify_absent().  It looks like before these commits that\n> unpack_trees() was carefully using the appropriate index, except that\n> functions in dir.c had use of the_index hardcoded.  Brandon fix the\n> functions in dir.c for us, but ended up still hardcoding the_index in\n> unpack-trees.c.  Basically, he did most of the necessary lifting, and\n> your patch just finally changes them over to use the correct index.\n> \n> Brandon: Does anything look off in my analysis above?\n\nNope your analysis is correct with regards to the changes I made to dir.\nBack when I was converting ls-files and grep to recursively work on\nsubmodules I needed to make it so that some of the dir functions\nexplicitly accepted an index parameter instead of implicitly relying on\nthe_index.  So I bubbled up the hardcoded the_index to the places I\nwasn't passing in a specific index (which would be when the_index\nappeared in unpack-trees.c) and allowed for arbitrary index's to be\npassed in like in ls-files.\n\nThis is one of the larger issues with working in our codebase,\nimplicitly relying on global state.  It makes it very difficult to\nreason if a section of code is correct or not, as is in this case.  Is\nit a bug that we use o->src_index in some places and the_index in\nothers?  Well maybe not, but that's because they usually are the same\nthing in the few cases that it matters (at least now its a bit more\nexplicit to see this, whereas before it was very implicit).  Of course I\nknow stefan has done work with making unpack-trees recursive so maybe\nit can be a bug in the recursive case.\n\n-- \nBrandon Williams\n"},{"id":"349351","messageId":"20180605154334.22613-1-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180601161153.15192-1-pclouds@gmail.com","subject":"[PATCH 0/6] Fix \"the_index\" usage in unpack-trees.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:28Z","receivedAt":"2018-06-05T15:43:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is a potential problem that is exposed after Brandon kicked\nthe_index out of dir.c (big thanks!) and could be seen as a\ncontinuation of bw/dir-c-stops-relying-on-the-index. Also thanks to\nElijah for helping analyze this code.\n\nThe last patch may be debatable. If we go this route, we may end up\nwith plenty of \"#define NO_THIS\" and \"#define NO_THAT\" until we\nfinally achieve \"#define THIS_IS_TRUE_LIB_CODE\" many years later.\n\nNguyễn Thái Ngọc Duy (6):\n  unpack-trees: remove 'extern' on function declaration\n  unpack-trees: add a note about path invalidation\n  unpack-trees: don't shadow global var the_index\n  unpack-tress: convert clear_ce_flags* to avoid the_index\n  unpack-trees: avoid the_index in verify_absent()\n  Forbid \"the_index\" in dir.c and unpack-trees.c\n\n cache.h        |  2 ++\n dir.c          |  2 ++\n unpack-trees.c | 55 +++++++++++++++++++++++++++++++++-----------------\n unpack-trees.h |  4 ++--\n 4 files changed, 42 insertions(+), 21 deletions(-)\n\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349352","messageId":"20180605154334.22613-2-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 1/6] unpack-trees: remove 'extern' on function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:29Z","receivedAt":"2018-06-05T15:43:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex c2b434c606..534358fcc5 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -82,8 +82,8 @@ struct unpack_trees_options {\n \tstruct exclude_list *el; /* for internal use */\n };\n \n-extern int unpack_trees(unsigned n, struct tree_desc *t,\n-\t\tstruct unpack_trees_options *options);\n+int unpack_trees(unsigned n, struct tree_desc *t,\n+\t\t struct unpack_trees_options *options);\n \n int verify_uptodate(const struct cache_entry *ce,\n \t\t    struct unpack_trees_options *o);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349353","messageId":"20180605154334.22613-4-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 3/6] unpack-trees: don't shadow global var the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:31Z","receivedAt":"2018-06-05T15:43:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function mark_new_skip_worktree() has an argument named the_index\nwhich is also the name of a global variable. While they have different\ntypes (the global the_index is not a pointer) mistakes can easily\nhappen and it's also confusing for readers. Rename the function\nargument to something other than the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5d06aa9c98..60d1138e08 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1231,7 +1231,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n  */\n static void mark_new_skip_worktree(struct exclude_list *el,\n-\t\t\t\t   struct index_state *the_index,\n+\t\t\t\t   struct index_state *istate,\n \t\t\t\t   int select_flag, int skip_wt_flag)\n {\n \tint i;\n@@ -1240,8 +1240,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 1. Pretend the narrowest worktree: only unmerged entries\n \t * are checked out\n \t */\n-\tfor (i = 0; i < the_index->cache_nr; i++) {\n-\t\tstruct cache_entry *ce = the_index->cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \n \t\tif (select_flag && !(ce->ce_flags & select_flag))\n \t\t\tcontinue;\n@@ -1256,8 +1256,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n-\t\t       select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349354","messageId":"20180605154334.22613-5-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 4/6] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:32Z","receivedAt":"2018-06-05T15:43:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\nthe_index when running the exclude machinery. fba92be8f7 helps show\nthis problem clearer because unpack-trees operation is supposed to\nwork on whatever index the caller specifies... not specifically\nthe_index.\n\nUpdate the code to use \"istate\" argument that's originally from\nmark_new_skip_worktree(). From the call sites, both in unpack_trees(),\nyou can see that this function works on two separate indexes:\no->src_index and o->result. The second mark_new_skip_worktree() so far\nhas incorecctly applied exclude rules on o->src_index instead of\no->result. It's unclear what is the consequences of this, but it's\ndefinitely wrong.\n\n[1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n    2017-05-05)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 29 +++++++++++++++++------------\n 1 file changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 60d1138e08..5268de7af5 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1085,13 +1085,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n \treturn mask;\n }\n \n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval);\n \n /* Whole directory matching */\n-static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_dir(struct index_state *istate,\n+\t\t\t      struct cache_entry **cache, int nr,\n \t\t\t      struct strbuf *prefix,\n \t\t\t      char *basename,\n \t\t\t      int select_mask, int clear_mask,\n@@ -1100,7 +1102,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \tstruct cache_entry **cache_end;\n \tint dtype = DT_DIR;\n \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n-\t\t\t\t\tbasename, &dtype, el, &the_index);\n+\t\t\t\t\tbasename, &dtype, el, istate);\n \tint rc;\n \n \tstrbuf_addch(prefix, '/');\n@@ -1122,7 +1124,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \t * calling clear_ce_flags_1(). That function will call\n \t * the expensive is_excluded_from_list() on every entry.\n \t */\n-\trc = clear_ce_flags_1(cache, cache_end - cache,\n+\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t      prefix,\n \t\t\t      select_mask, clear_mask,\n \t\t\t      el, ret);\n@@ -1145,7 +1147,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n  *   cache[0]->name[0..(prefix_len-1)]\n  * Top level path has prefix_len zero.\n  */\n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval)\n@@ -1179,7 +1182,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\tlen = slash - name;\n \t\t\tstrbuf_add(prefix, name, len);\n \n-\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n+\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n \t\t\t\t\t\t       prefix,\n \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n \t\t\t\t\t\t       select_mask, clear_mask,\n@@ -1193,7 +1196,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\t}\n \n \t\t\tstrbuf_addch(prefix, '/');\n-\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n+\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t\t\t\t  prefix,\n \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n@@ -1203,7 +1206,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t/* Non-directory */\n \t\tdtype = ce_to_dtype(ce);\n \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n-\t\t\t\t\t    name, &dtype, el, &the_index);\n+\t\t\t\t\t    name, &dtype, el, istate);\n \t\tif (ret < 0)\n \t\t\tret = defval;\n \t\tif (ret > 0)\n@@ -1213,15 +1216,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \treturn nr - (cache_end - cache);\n }\n \n-static int clear_ce_flags(struct cache_entry **cache, int nr,\n-\t\t\t    int select_mask, int clear_mask,\n-\t\t\t    struct exclude_list *el)\n+static int clear_ce_flags(struct index_state *istate,\n+\t\t\t  int select_mask, int clear_mask,\n+\t\t\t  struct exclude_list *el)\n {\n \tstatic struct strbuf prefix = STRBUF_INIT;\n \n \tstrbuf_reset(&prefix);\n \n-\treturn clear_ce_flags_1(cache, nr,\n+\treturn clear_ce_flags_1(istate,\n+\t\t\t\tistate->cache,\n+\t\t\t\tistate->cache_nr,\n \t\t\t\t&prefix,\n \t\t\t\tselect_mask, clear_mask,\n \t\t\t\tel, 0);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349355","messageId":"20180605154334.22613-6-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 5/6] unpack-trees: avoid the_index in verify_absent()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:33Z","receivedAt":"2018-06-05T15:43:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Both functions that are updated in this commit are called by\nverify_absent(), which is part of the \"unpack-trees\" operation that is\nsupposed to work on any index file specified by the caller. Thanks to\nBrandon [1] [2], an implicit dependency on the_index is exposed. This\ncommit fixes it.\n\nIn both functions, it makes sense to use src_index to check for\nexclusion because it's almost unchanged and should give us the same\noutcome as if running the exclude check before the unpack.\n\nIt's \"almost unchanged\" because we do invalidate cache-tree and\nuntracked cache in the source index. But this should not affect how\nexclude machinery uses the index: to see if a file is tracked, and to\nread a blob from the index instead of worktree if it's marked\nskip-worktree (i.e. it's not available in worktree)\n\n[1] a0bba65b10 (dir: convert is_excluded to take an index - 2017-05-05\n[2] 2c1eb10454 (dir: convert read_directory to take an index - 2017-05-05)\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5268de7af5..3ace82ca27 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1651,7 +1651,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);\n+\ti = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\treturn o->gently ? -1 :\n \t\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);\n@@ -1693,7 +1693,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\treturn 0;\n \n \tif (o->dir &&\n-\t    is_excluded(o->dir, &the_index, name, &dtype))\n+\t    is_excluded(o->dir, o->src_index, name, &dtype))\n \t\t/*\n \t\t * ce->name is explicitly excluded, so it is Ok to\n \t\t * overwrite it.\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349356","messageId":"20180605154334.22613-7-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 6/6] Forbid \"the_index\" in dir.c and unpack-trees.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:34Z","receivedAt":"2018-06-05T15:43:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Use of global variables like the_index makes it very hard to follow\nthe code flow, especially when it's buried deep in some minor helper\nfunction.\n\nWe are gradually avoiding global variables, this hopefully will make\nit one step closer. The end game is, the set of \"library\" source files\nwill have just one macro set: \"LIB_CODE\" (or something). This macro\nwill prevent access to most (if not all) global variables in those\nfiles. We can't do that now, so we just prevent one thing at a time.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Should I keep my trick of defining the_index to\n the_index_should_not_be_used_here? It may help somewhat when people\n accidentally use the_index.\n\n cache.h        | 2 ++\n dir.c          | 2 ++\n unpack-trees.c | 2 ++\n 3 files changed, 6 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex 89a107a7f7..ecc96ccb0e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -330,7 +330,9 @@ struct index_state {\n \tstruct ewah_bitmap *fsmonitor_dirty;\n };\n \n+#ifndef NO_GLOBAL_INDEX\n extern struct index_state the_index;\n+#endif\n \n /* Name hashing */\n extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);\ndiff --git a/dir.c b/dir.c\nindex ccf8b4975e..74d848db5a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -8,6 +8,8 @@\n  *\t\t Junio Hamano, 2005-2006\n  */\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n+/* Do not use the_index. You should have access to it via function arg */\n+#define NO_GLOBAL_INDEX\n #include \"cache.h\"\n #include \"config.h\"\n #include \"dir.h\"\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3ace82ca27..9aebe9762b 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1,4 +1,6 @@\n #define NO_THE_INDEX_COMPATIBILITY_MACROS\n+/* Do not use the_index here, you probably want o->src_index */\n+#define NO_GLOBAL_INDEX\n #include \"cache.h\"\n #include \"argv-array.h\"\n #include \"repository.h\"\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349357","messageId":"20180605154334.22613-3-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH 2/6] unpack-trees: add a note about path invalidation","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-05T15:43:30Z","receivedAt":"2018-06-05T15:44:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3a85a02a77..5d06aa9c98 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1545,6 +1545,17 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);\n }\n \n+/*\n+ * TODO: We should actually invalidate o->result, not src_index [1].\n+ * But since cache tree and untracked cache both are not copied to\n+ * o->result until unpacking is complete, we invalidate them on\n+ * src_index instead with the assumption that they will be copied to\n+ * dst_index at the end.\n+ *\n+ * [1] src_index->cache_tree is also used in unpack_callback() so if\n+ * we invalidate o->result, we need to update it to use\n+ * o->result.cache_tree as well.\n+ */\n static void invalidate_ce_path(const struct cache_entry *ce,\n \t\t\t       struct unpack_trees_options *o)\n {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349365","messageId":"20180605165826.GB158365@google.com","threadId":"48624","inReplyTo":"20180605154334.22613-7-pclouds@gmail.com","subject":"Re: [PATCH 6/6] Forbid \"the_index\" in dir.c and unpack-trees.c","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-05T16:58:26Z","receivedAt":"2018-06-05T16:58:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/05, Nguyễn Thái Ngọc Duy wrote:\n> Use of global variables like the_index makes it very hard to follow\n> the code flow, especially when it's buried deep in some minor helper\n> function.\n> \n> We are gradually avoiding global variables, this hopefully will make\n> it one step closer. The end game is, the set of \"library\" source files\n> will have just one macro set: \"LIB_CODE\" (or something). This macro\n> will prevent access to most (if not all) global variables in those\n> files. We can't do that now, so we just prevent one thing at a time.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Should I keep my trick of defining the_index to\n>  the_index_should_not_be_used_here? It may help somewhat when people\n>  accidentally use the_index.\n\nWe already have a set of index compatibility macros which this could\nmaybe be a part of.  Though if we want to go this way I think we should\ndo the reverse of this and instead have GLOBAL_INDEX which must be\ndefined in order to have access to the global.  That way new files are\nalready protected by this and it may be easier to reduce the number of\nthese defines through our codebase than to add them to every single\nfile.\n\n> \n>  cache.h        | 2 ++\n>  dir.c          | 2 ++\n>  unpack-trees.c | 2 ++\n>  3 files changed, 6 insertions(+)\n> \n> diff --git a/cache.h b/cache.h\n> index 89a107a7f7..ecc96ccb0e 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -330,7 +330,9 @@ struct index_state {\n>  \tstruct ewah_bitmap *fsmonitor_dirty;\n>  };\n>  \n> +#ifndef NO_GLOBAL_INDEX\n>  extern struct index_state the_index;\n> +#endif\n>  \n>  /* Name hashing */\n>  extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);\n> diff --git a/dir.c b/dir.c\n> index ccf8b4975e..74d848db5a 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -8,6 +8,8 @@\n>   *\t\t Junio Hamano, 2005-2006\n>   */\n>  #define NO_THE_INDEX_COMPATIBILITY_MACROS\n> +/* Do not use the_index. You should have access to it via function arg */\n> +#define NO_GLOBAL_INDEX\n>  #include \"cache.h\"\n>  #include \"config.h\"\n>  #include \"dir.h\"\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 3ace82ca27..9aebe9762b 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -1,4 +1,6 @@\n>  #define NO_THE_INDEX_COMPATIBILITY_MACROS\n> +/* Do not use the_index here, you probably want o->src_index */\n> +#define NO_GLOBAL_INDEX\n>  #include \"cache.h\"\n>  #include \"argv-array.h\"\n>  #include \"repository.h\"\n> -- \n> 2.18.0.rc0.333.g22e6ee6cdf\n> \n\n-- \nBrandon Williams\n"},{"id":"349367","messageId":"3db23386-5c9f-5e0d-5a26-311184d11bc7@ramsayjones.plus.com","threadId":"48624","inReplyTo":"20180605154334.22613-4-pclouds@gmail.com","subject":"Re: [PATCH 3/6] unpack-trees: don't shadow global var the_index","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-06-05T17:11:20Z","receivedAt":"2018-06-05T17:11:55Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 05/06/18 16:43, Nguyễn Thái Ngọc Duy wrote:\n> This function mark_new_skip_worktree() has an argument named the_index\n> which is also the name of a global variable. While they have different\n> types (the global the_index is not a pointer) mistakes can easily\n> happen and it's also confusing for readers. Rename the function\n> argument to something other than the_index.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  unpack-trees.c | 9 ++++-----\n>  1 file changed, 4 insertions(+), 5 deletions(-)\n> \n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 5d06aa9c98..60d1138e08 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -1231,7 +1231,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n>   * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n>   */\n>  static void mark_new_skip_worktree(struct exclude_list *el,\n> -\t\t\t\t   struct index_state *the_index,\n> +\t\t\t\t   struct index_state *istate,\n>  \t\t\t\t   int select_flag, int skip_wt_flag)\n>  {\n>  \tint i;\n> @@ -1240,8 +1240,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n>  \t * 1. Pretend the narrowest worktree: only unmerged entries\n>  \t * are checked out\n>  \t */\n> -\tfor (i = 0; i < the_index->cache_nr; i++) {\n> -\t\tstruct cache_entry *ce = the_index->cache[i];\n> +\tfor (i = 0; i < istate->cache_nr; i++) {\n> +\t\tstruct cache_entry *ce = istate->cache[i];\n>  \n>  \t\tif (select_flag && !(ce->ce_flags & select_flag))\n>  \t\t\tcontinue;\n> @@ -1256,8 +1256,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n>  \t * 2. Widen worktree according to sparse-checkout file.\n>  \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n>  \t */\n> -\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n> -\t\t       select_flag, skip_wt_flag, el);\n> +\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n\nThis looks a bit suspect. The clear_ce_flags() function has\nnot been modified to take a 'struct index_state *' as its first\nparameter, right? (If you look back at the first hunk header, you\nwill see that it still takes 'struct cache_entry **, int, ...') ;-)\n\nATB,\nRamsay Jones\n\n"},{"id":"349368","messageId":"567d24d8-538e-3e0e-efc6-0d01dcc8e89e@ramsayjones.plus.com","threadId":"48624","inReplyTo":"20180605154334.22613-5-pclouds@gmail.com","subject":"Re: [PATCH 4/6] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-06-05T17:37:07Z","receivedAt":"2018-06-05T17:37:12Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 05/06/18 16:43, Nguyễn Thái Ngọc Duy wrote:\n> Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\n> the_index when running the exclude machinery. fba92be8f7 helps show\n> this problem clearer because unpack-trees operation is supposed to\n> work on whatever index the caller specifies... not specifically\n> the_index.\n> \n> Update the code to use \"istate\" argument that's originally from\n> mark_new_skip_worktree(). From the call sites, both in unpack_trees(),\n> you can see that this function works on two separate indexes:\n> o->src_index and o->result. The second mark_new_skip_worktree() so far\n> has incorecctly applied exclude rules on o->src_index instead of\n> o->result. It's unclear what is the consequences of this, but it's\n> definitely wrong.\n> \n> [1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n>     2017-05-05)\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  unpack-trees.c | 29 +++++++++++++++++------------\n>  1 file changed, 17 insertions(+), 12 deletions(-)\n> \n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 60d1138e08..5268de7af5 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -1085,13 +1085,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n>  \treturn mask;\n>  }\n>  \n> -static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n> +static int clear_ce_flags_1(struct index_state *istate,\n> +\t\t\t    struct cache_entry **cache, int nr,\n>  \t\t\t    struct strbuf *prefix,\n>  \t\t\t    int select_mask, int clear_mask,\n>  \t\t\t    struct exclude_list *el, int defval);\n>  \n>  /* Whole directory matching */\n> -static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n> +static int clear_ce_flags_dir(struct index_state *istate,\n> +\t\t\t      struct cache_entry **cache, int nr,\n>  \t\t\t      struct strbuf *prefix,\n>  \t\t\t      char *basename,\n>  \t\t\t      int select_mask, int clear_mask,\n> @@ -1100,7 +1102,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n>  \tstruct cache_entry **cache_end;\n>  \tint dtype = DT_DIR;\n>  \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n> -\t\t\t\t\tbasename, &dtype, el, &the_index);\n> +\t\t\t\t\tbasename, &dtype, el, istate);\n>  \tint rc;\n>  \n>  \tstrbuf_addch(prefix, '/');\n> @@ -1122,7 +1124,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n>  \t * calling clear_ce_flags_1(). That function will call\n>  \t * the expensive is_excluded_from_list() on every entry.\n>  \t */\n> -\trc = clear_ce_flags_1(cache, cache_end - cache,\n> +\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n>  \t\t\t      prefix,\n>  \t\t\t      select_mask, clear_mask,\n>  \t\t\t      el, ret);\n> @@ -1145,7 +1147,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n>   *   cache[0]->name[0..(prefix_len-1)]\n>   * Top level path has prefix_len zero.\n>   */\n> -static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n> +static int clear_ce_flags_1(struct index_state *istate,\n> +\t\t\t    struct cache_entry **cache, int nr,\n>  \t\t\t    struct strbuf *prefix,\n>  \t\t\t    int select_mask, int clear_mask,\n>  \t\t\t    struct exclude_list *el, int defval)\n> @@ -1179,7 +1182,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n>  \t\t\tlen = slash - name;\n>  \t\t\tstrbuf_add(prefix, name, len);\n>  \n> -\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n> +\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n>  \t\t\t\t\t\t       prefix,\n>  \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n>  \t\t\t\t\t\t       select_mask, clear_mask,\n> @@ -1193,7 +1196,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n>  \t\t\t}\n>  \n>  \t\t\tstrbuf_addch(prefix, '/');\n> -\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n> +\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n>  \t\t\t\t\t\t  prefix,\n>  \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n>  \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n> @@ -1203,7 +1206,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n>  \t\t/* Non-directory */\n>  \t\tdtype = ce_to_dtype(ce);\n>  \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n> -\t\t\t\t\t    name, &dtype, el, &the_index);\n> +\t\t\t\t\t    name, &dtype, el, istate);\n>  \t\tif (ret < 0)\n>  \t\t\tret = defval;\n>  \t\tif (ret > 0)\n> @@ -1213,15 +1216,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n>  \treturn nr - (cache_end - cache);\n>  }\n>  \n> -static int clear_ce_flags(struct cache_entry **cache, int nr,\n> -\t\t\t    int select_mask, int clear_mask,\n> -\t\t\t    struct exclude_list *el)\n> +static int clear_ce_flags(struct index_state *istate,\n> +\t\t\t  int select_mask, int clear_mask,\n> +\t\t\t  struct exclude_list *el)\n\nOK, so that last hunk of patch #3 should be moved to the\nend of this patch. (A 'git rebase -i' problem?)\n\nATB,\nRamsay Jones\n\n"},{"id":"349432","messageId":"CACsJy8CB4-vVNY7dhyv=2ZyZgbKb9XVgB9djxBbJKa9AtxvYVg@mail.gmail.com","threadId":"48624","inReplyTo":"20180605165826.GB158365@google.com","subject":"Re: [PATCH 6/6] Forbid \"the_index\" in dir.c and unpack-trees.c","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T04:57:38Z","receivedAt":"2018-06-06T04:58:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jun 5, 2018 at 6:58 PM, Brandon Williams <bmwill@google.com> wrote:\n> On 06/05, Nguyễn Thái Ngọc Duy wrote:\n>> Use of global variables like the_index makes it very hard to follow\n>> the code flow, especially when it's buried deep in some minor helper\n>> function.\n>>\n>> We are gradually avoiding global variables, this hopefully will make\n>> it one step closer. The end game is, the set of \"library\" source files\n>> will have just one macro set: \"LIB_CODE\" (or something). This macro\n>> will prevent access to most (if not all) global variables in those\n>> files. We can't do that now, so we just prevent one thing at a time.\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>>  Should I keep my trick of defining the_index to\n>>  the_index_should_not_be_used_here? It may help somewhat when people\n>>  accidentally use the_index.\n>\n> We already have a set of index compatibility macros which this could\n> maybe be a part of.\n\nI like it. Only attr.c and submodule.c fail to build if I make\nthe_index declaration part of NO_THE_INDEX_COMPATIBILITY_MACROS. So\nI'm going to drop this patch for now, work on kicking the_index out of\nsubmodule.c and attr.c then move the_index decl there in a separate\nseries.\n\n> Though if we want to go this way I think we should\n> do the reverse of this and instead have GLOBAL_INDEX which must be\n> defined in order to have access to the global.  That way new files are\n> already protected by this and it may be easier to reduce the number of\n> these defines through our codebase than to add them to every single\n> file.\n>\n>>\n>>  cache.h        | 2 ++\n>>  dir.c          | 2 ++\n>>  unpack-trees.c | 2 ++\n>>  3 files changed, 6 insertions(+)\n>>\n>> diff --git a/cache.h b/cache.h\n>> index 89a107a7f7..ecc96ccb0e 100644\n>> --- a/cache.h\n>> +++ b/cache.h\n>> @@ -330,7 +330,9 @@ struct index_state {\n>>       struct ewah_bitmap *fsmonitor_dirty;\n>>  };\n>>\n>> +#ifndef NO_GLOBAL_INDEX\n>>  extern struct index_state the_index;\n>> +#endif\n>>\n>>  /* Name hashing */\n>>  extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);\n>> diff --git a/dir.c b/dir.c\n>> index ccf8b4975e..74d848db5a 100644\n>> --- a/dir.c\n>> +++ b/dir.c\n>> @@ -8,6 +8,8 @@\n>>   *            Junio Hamano, 2005-2006\n>>   */\n>>  #define NO_THE_INDEX_COMPATIBILITY_MACROS\n>> +/* Do not use the_index. You should have access to it via function arg */\n>> +#define NO_GLOBAL_INDEX\n>>  #include \"cache.h\"\n>>  #include \"config.h\"\n>>  #include \"dir.h\"\n>> diff --git a/unpack-trees.c b/unpack-trees.c\n>> index 3ace82ca27..9aebe9762b 100644\n>> --- a/unpack-trees.c\n>> +++ b/unpack-trees.c\n>> @@ -1,4 +1,6 @@\n>>  #define NO_THE_INDEX_COMPATIBILITY_MACROS\n>> +/* Do not use the_index here, you probably want o->src_index */\n>> +#define NO_GLOBAL_INDEX\n>>  #include \"cache.h\"\n>>  #include \"argv-array.h\"\n>>  #include \"repository.h\"\n>> --\n>> 2.18.0.rc0.333.g22e6ee6cdf\n>>\n>\n> --\n> Brandon Williams\n\n\n\n-- \nDuy\n"},{"id":"349433","messageId":"20180606050207.13556-1-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180605154334.22613-1-pclouds@gmail.com","subject":"[PATCH v2 0/5] Fix \"the_index\" usage in unpack-trees.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:02Z","receivedAt":"2018-06-06T05:02:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v2 fixes an incorrect patch splitting (I should have built one more\ntime :P) between 3/5 and 4/5. v1's 6/6 is dropped. Brandon suggested a\nbetter way of doing it which may happen later.\n\nNguyễn Thái Ngọc Duy (5):\n  unpack-trees: remove 'extern' on function declaration\n  unpack-trees: add a note about path invalidation\n  unpack-trees: don't shadow global var the_index\n  unpack-tress: convert clear_ce_flags* to avoid the_index\n  unpack-trees: avoid the_index in verify_absent()\n\n unpack-trees.c | 53 ++++++++++++++++++++++++++++++++------------------\n unpack-trees.h |  4 ++--\n 2 files changed, 36 insertions(+), 21 deletions(-)\n\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349434","messageId":"20180606050207.13556-2-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v2 1/5] unpack-trees: remove 'extern' on function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:03Z","receivedAt":"2018-06-06T05:02:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex c2b434c606..534358fcc5 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -82,8 +82,8 @@ struct unpack_trees_options {\n \tstruct exclude_list *el; /* for internal use */\n };\n \n-extern int unpack_trees(unsigned n, struct tree_desc *t,\n-\t\tstruct unpack_trees_options *options);\n+int unpack_trees(unsigned n, struct tree_desc *t,\n+\t\t struct unpack_trees_options *options);\n \n int verify_uptodate(const struct cache_entry *ce,\n \t\t    struct unpack_trees_options *o);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349435","messageId":"20180606050207.13556-5-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v2 4/5] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:06Z","receivedAt":"2018-06-06T05:02:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\nthe_index when running the exclude machinery. fba92be8f7 helps show\nthis problem clearer because unpack-trees operation is supposed to\nwork on whatever index the caller specifies... not specifically\nthe_index.\n\nUpdate the code to use \"istate\" argument that's originally from\nmark_new_skip_worktree(). From the call sites, both in unpack_trees(),\nyou can see that this function works on two separate indexes:\no->src_index and o->result. The second mark_new_skip_worktree() so far\nhas incorecctly applied exclude rules on o->src_index instead of\no->result. It's unclear what is the consequences of this, but it's\ndefinitely wrong.\n\n[1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n    2017-05-05)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 31 ++++++++++++++++++-------------\n 1 file changed, 18 insertions(+), 13 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 45fcda3169..5268de7af5 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1085,13 +1085,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n \treturn mask;\n }\n \n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval);\n \n /* Whole directory matching */\n-static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_dir(struct index_state *istate,\n+\t\t\t      struct cache_entry **cache, int nr,\n \t\t\t      struct strbuf *prefix,\n \t\t\t      char *basename,\n \t\t\t      int select_mask, int clear_mask,\n@@ -1100,7 +1102,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \tstruct cache_entry **cache_end;\n \tint dtype = DT_DIR;\n \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n-\t\t\t\t\tbasename, &dtype, el, &the_index);\n+\t\t\t\t\tbasename, &dtype, el, istate);\n \tint rc;\n \n \tstrbuf_addch(prefix, '/');\n@@ -1122,7 +1124,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \t * calling clear_ce_flags_1(). That function will call\n \t * the expensive is_excluded_from_list() on every entry.\n \t */\n-\trc = clear_ce_flags_1(cache, cache_end - cache,\n+\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t      prefix,\n \t\t\t      select_mask, clear_mask,\n \t\t\t      el, ret);\n@@ -1145,7 +1147,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n  *   cache[0]->name[0..(prefix_len-1)]\n  * Top level path has prefix_len zero.\n  */\n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval)\n@@ -1179,7 +1182,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\tlen = slash - name;\n \t\t\tstrbuf_add(prefix, name, len);\n \n-\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n+\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n \t\t\t\t\t\t       prefix,\n \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n \t\t\t\t\t\t       select_mask, clear_mask,\n@@ -1193,7 +1196,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\t}\n \n \t\t\tstrbuf_addch(prefix, '/');\n-\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n+\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t\t\t\t  prefix,\n \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n@@ -1203,7 +1206,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t/* Non-directory */\n \t\tdtype = ce_to_dtype(ce);\n \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n-\t\t\t\t\t    name, &dtype, el, &the_index);\n+\t\t\t\t\t    name, &dtype, el, istate);\n \t\tif (ret < 0)\n \t\t\tret = defval;\n \t\tif (ret > 0)\n@@ -1213,15 +1216,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \treturn nr - (cache_end - cache);\n }\n \n-static int clear_ce_flags(struct cache_entry **cache, int nr,\n-\t\t\t    int select_mask, int clear_mask,\n-\t\t\t    struct exclude_list *el)\n+static int clear_ce_flags(struct index_state *istate,\n+\t\t\t  int select_mask, int clear_mask,\n+\t\t\t  struct exclude_list *el)\n {\n \tstatic struct strbuf prefix = STRBUF_INIT;\n \n \tstrbuf_reset(&prefix);\n \n-\treturn clear_ce_flags_1(cache, nr,\n+\treturn clear_ce_flags_1(istate,\n+\t\t\t\tistate->cache,\n+\t\t\t\tistate->cache_nr,\n \t\t\t\t&prefix,\n \t\t\t\tselect_mask, clear_mask,\n \t\t\t\tel, 0);\n@@ -1256,7 +1261,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349436","messageId":"20180606050207.13556-4-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v2 3/5] unpack-trees: don't shadow global var the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:05Z","receivedAt":"2018-06-06T05:02:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function mark_new_skip_worktree() has an argument named the_index\nwhich is also the name of a global variable. While they have different\ntypes (the global the_index is not a pointer) mistakes can easily\nhappen and it's also confusing for readers. Rename the function\nargument to something other than the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5d06aa9c98..45fcda3169 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1231,7 +1231,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n  */\n static void mark_new_skip_worktree(struct exclude_list *el,\n-\t\t\t\t   struct index_state *the_index,\n+\t\t\t\t   struct index_state *istate,\n \t\t\t\t   int select_flag, int skip_wt_flag)\n {\n \tint i;\n@@ -1240,8 +1240,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 1. Pretend the narrowest worktree: only unmerged entries\n \t * are checked out\n \t */\n-\tfor (i = 0; i < the_index->cache_nr; i++) {\n-\t\tstruct cache_entry *ce = the_index->cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \n \t\tif (select_flag && !(ce->ce_flags & select_flag))\n \t\t\tcontinue;\n@@ -1256,8 +1256,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n-\t\t       select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349437","messageId":"20180606050207.13556-3-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v2 2/5] unpack-trees: add a note about path invalidation","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:04Z","receivedAt":"2018-06-06T05:02:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3a85a02a77..5d06aa9c98 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1545,6 +1545,17 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);\n }\n \n+/*\n+ * TODO: We should actually invalidate o->result, not src_index [1].\n+ * But since cache tree and untracked cache both are not copied to\n+ * o->result until unpacking is complete, we invalidate them on\n+ * src_index instead with the assumption that they will be copied to\n+ * dst_index at the end.\n+ *\n+ * [1] src_index->cache_tree is also used in unpack_callback() so if\n+ * we invalidate o->result, we need to update it to use\n+ * o->result.cache_tree as well.\n+ */\n static void invalidate_ce_path(const struct cache_entry *ce,\n \t\t\t       struct unpack_trees_options *o)\n {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349438","messageId":"20180606050207.13556-6-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v2 5/5] unpack-trees: avoid the_index in verify_absent()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T05:02:07Z","receivedAt":"2018-06-06T05:02:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Both functions that are updated in this commit are called by\nverify_absent(), which is part of the \"unpack-trees\" operation that is\nsupposed to work on any index file specified by the caller. Thanks to\nBrandon [1] [2], an implicit dependency on the_index is exposed. This\ncommit fixes it.\n\nIn both functions, it makes sense to use src_index to check for\nexclusion because it's almost unchanged and should give us the same\noutcome as if running the exclude check before the unpack.\n\nIt's \"almost unchanged\" because we do invalidate cache-tree and\nuntracked cache in the source index. But this should not affect how\nexclude machinery uses the index: to see if a file is tracked, and to\nread a blob from the index instead of worktree if it's marked\nskip-worktree (i.e. it's not available in worktree)\n\n[1] a0bba65b10 (dir: convert is_excluded to take an index - 2017-05-05\n[2] 2c1eb10454 (dir: convert read_directory to take an index - 2017-05-05)\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5268de7af5..3ace82ca27 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1651,7 +1651,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);\n+\ti = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\treturn o->gently ? -1 :\n \t\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);\n@@ -1693,7 +1693,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\treturn 0;\n \n \tif (o->dir &&\n-\t    is_excluded(o->dir, &the_index, name, &dtype))\n+\t    is_excluded(o->dir, o->src_index, name, &dtype))\n \t\t/*\n \t\t * ce->name is explicitly excluded, so it is Ok to\n \t\t * overwrite it.\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349441","messageId":"20180606073933.14755-1-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606050207.13556-1-pclouds@gmail.com","subject":"[PATCH v3 00/20] Fix incorrect use of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:13Z","receivedAt":"2018-06-06T07:39:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jun 6, 2018 at 7:02 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> v2 fixes an incorrect patch splitting (I should have built one more\n> time :P) between 3/5 and 4/5. v1's 6/6 is dropped. Brandon suggested a\n> better way of doing it which may happen later.\n\nI started looking into Brandon's suggestion, did some mindless\nconversion, then found out a couple more incorrect uses of the_index\n:( So here's the whole thing.\n\nNguyễn Thái Ngọc Duy (20):\n  unpack-trees: remove 'extern' on function declaration\n  unpack-trees: add a note about path invalidation\n  unpack-trees: don't shadow global var the_index\n  unpack-tress: convert clear_ce_flags* to avoid the_index\n  unpack-trees: avoid the_index in verify_absent()\n  attr.h: drop extern from function declaration\n  attr: remove an implicit dependency on the_index\n  convert.h: drop 'extern' from function declaration\n  convert.c: remove an implicit dependency on the_index\n  dir.c: remove an implicit dependency on the_index in pathspec code\n  ls-files: correct index argument to get_convert_attr_ascii()\n  pathspec.c: use the right index instead of the_index\n  submodule.c: use the right index instead of the_index\n  entry.c: use the right index instead of the_index\n  attr: remove index from git_attr_set_direction()\n  preload-index.c: use the right index instead of the_index\n  cache.c: remove an implicit dependency on the_index\n  resolve-undo.c: use the right index instead of the_index\n  grep: use the right index instead of the_index\n  cache.h: make the_index part of \"compatibility macros\"\n\n apply.c                     |  4 +--\n archive.c                   |  8 ++---\n attr.c                      | 52 ++++++++++++++++++-------------\n attr.h                      | 31 ++++++++++---------\n builtin/add.c               |  6 ++--\n builtin/cat-file.c          |  2 +-\n builtin/check-attr.c        |  6 ++--\n builtin/checkout-index.c    |  1 +\n builtin/checkout.c          |  4 +--\n builtin/clean.c             |  2 +-\n builtin/commit.c            |  2 +-\n builtin/difftool.c          |  4 +--\n builtin/grep.c              |  6 ++--\n builtin/ls-files.c          | 17 ++++++-----\n builtin/pack-objects.c      |  2 +-\n builtin/reset.c             |  2 +-\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c |  2 +-\n builtin/update-index.c      |  2 +-\n cache.h                     |  9 +++---\n convert.c                   | 41 ++++++++++++++-----------\n convert.h                   | 61 +++++++++++++++++++++----------------\n diff-lib.c                  |  4 +--\n diff.c                      |  2 +-\n dir.c                       | 27 +++++++++-------\n dir.h                       | 16 ++++++----\n entry.c                     | 10 +++---\n ll-merge.c                  |  4 +--\n merge-recursive.c           |  4 +--\n pathspec.c                  |  2 +-\n preload-index.c             |  3 +-\n read-cache.c                | 19 +++++++-----\n rerere.c                    |  2 +-\n resolve-undo.c              |  5 +--\n revision.c                  |  2 +-\n sha1-file.c                 |  4 +--\n submodule.c                 |  8 ++---\n unpack-trees.c              | 57 +++++++++++++++++++++-------------\n unpack-trees.h              |  4 +--\n userdiff.c                  |  2 +-\n ws.c                        |  2 +-\n wt-status.c                 |  6 ++--\n 42 files changed, 255 insertions(+), 194 deletions(-)\n\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349442","messageId":"20180606073933.14755-3-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 02/20] unpack-trees: add a note about path invalidation","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:15Z","receivedAt":"2018-06-06T07:39:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3a85a02a77..5d06aa9c98 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1545,6 +1545,17 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);\n }\n \n+/*\n+ * TODO: We should actually invalidate o->result, not src_index [1].\n+ * But since cache tree and untracked cache both are not copied to\n+ * o->result until unpacking is complete, we invalidate them on\n+ * src_index instead with the assumption that they will be copied to\n+ * dst_index at the end.\n+ *\n+ * [1] src_index->cache_tree is also used in unpack_callback() so if\n+ * we invalidate o->result, we need to update it to use\n+ * o->result.cache_tree as well.\n+ */\n static void invalidate_ce_path(const struct cache_entry *ce,\n \t\t\t       struct unpack_trees_options *o)\n {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349443","messageId":"20180606073933.14755-2-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 01/20] unpack-trees: remove 'extern' on function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:14Z","receivedAt":"2018-06-06T07:39:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex c2b434c606..534358fcc5 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -82,8 +82,8 @@ struct unpack_trees_options {\n \tstruct exclude_list *el; /* for internal use */\n };\n \n-extern int unpack_trees(unsigned n, struct tree_desc *t,\n-\t\tstruct unpack_trees_options *options);\n+int unpack_trees(unsigned n, struct tree_desc *t,\n+\t\t struct unpack_trees_options *options);\n \n int verify_uptodate(const struct cache_entry *ce,\n \t\t    struct unpack_trees_options *o);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349444","messageId":"20180606073933.14755-5-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 04/20] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:17Z","receivedAt":"2018-06-06T07:39:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\nthe_index when running the exclude machinery. fba92be8f7 helps show\nthis problem clearer because unpack-trees operation is supposed to\nwork on whatever index the caller specifies... not specifically\nthe_index.\n\nUpdate the code to use \"istate\" argument that's originally from\nmark_new_skip_worktree(). From the call sites, both in unpack_trees(),\nyou can see that this function works on two separate indexes:\no->src_index and o->result. The second mark_new_skip_worktree() so far\nhas incorecctly applied exclude rules on o->src_index instead of\no->result. It's unclear what is the consequences of this, but it's\ndefinitely wrong.\n\n[1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n    2017-05-05)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 31 ++++++++++++++++++-------------\n 1 file changed, 18 insertions(+), 13 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 45fcda3169..5268de7af5 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1085,13 +1085,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n \treturn mask;\n }\n \n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval);\n \n /* Whole directory matching */\n-static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_dir(struct index_state *istate,\n+\t\t\t      struct cache_entry **cache, int nr,\n \t\t\t      struct strbuf *prefix,\n \t\t\t      char *basename,\n \t\t\t      int select_mask, int clear_mask,\n@@ -1100,7 +1102,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \tstruct cache_entry **cache_end;\n \tint dtype = DT_DIR;\n \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n-\t\t\t\t\tbasename, &dtype, el, &the_index);\n+\t\t\t\t\tbasename, &dtype, el, istate);\n \tint rc;\n \n \tstrbuf_addch(prefix, '/');\n@@ -1122,7 +1124,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \t * calling clear_ce_flags_1(). That function will call\n \t * the expensive is_excluded_from_list() on every entry.\n \t */\n-\trc = clear_ce_flags_1(cache, cache_end - cache,\n+\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t      prefix,\n \t\t\t      select_mask, clear_mask,\n \t\t\t      el, ret);\n@@ -1145,7 +1147,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n  *   cache[0]->name[0..(prefix_len-1)]\n  * Top level path has prefix_len zero.\n  */\n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval)\n@@ -1179,7 +1182,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\tlen = slash - name;\n \t\t\tstrbuf_add(prefix, name, len);\n \n-\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n+\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n \t\t\t\t\t\t       prefix,\n \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n \t\t\t\t\t\t       select_mask, clear_mask,\n@@ -1193,7 +1196,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\t}\n \n \t\t\tstrbuf_addch(prefix, '/');\n-\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n+\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t\t\t\t  prefix,\n \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n@@ -1203,7 +1206,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t/* Non-directory */\n \t\tdtype = ce_to_dtype(ce);\n \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n-\t\t\t\t\t    name, &dtype, el, &the_index);\n+\t\t\t\t\t    name, &dtype, el, istate);\n \t\tif (ret < 0)\n \t\t\tret = defval;\n \t\tif (ret > 0)\n@@ -1213,15 +1216,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \treturn nr - (cache_end - cache);\n }\n \n-static int clear_ce_flags(struct cache_entry **cache, int nr,\n-\t\t\t    int select_mask, int clear_mask,\n-\t\t\t    struct exclude_list *el)\n+static int clear_ce_flags(struct index_state *istate,\n+\t\t\t  int select_mask, int clear_mask,\n+\t\t\t  struct exclude_list *el)\n {\n \tstatic struct strbuf prefix = STRBUF_INIT;\n \n \tstrbuf_reset(&prefix);\n \n-\treturn clear_ce_flags_1(cache, nr,\n+\treturn clear_ce_flags_1(istate,\n+\t\t\t\tistate->cache,\n+\t\t\t\tistate->cache_nr,\n \t\t\t\t&prefix,\n \t\t\t\tselect_mask, clear_mask,\n \t\t\t\tel, 0);\n@@ -1256,7 +1261,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349445","messageId":"20180606073933.14755-6-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 05/20] unpack-trees: avoid the_index in verify_absent()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:18Z","receivedAt":"2018-06-06T07:39:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Both functions that are updated in this commit are called by\nverify_absent(), which is part of the \"unpack-trees\" operation that is\nsupposed to work on any index file specified by the caller. Thanks to\nBrandon [1] [2], an implicit dependency on the_index is exposed. This\ncommit fixes it.\n\nIn both functions, it makes sense to use src_index to check for\nexclusion because it's almost unchanged and should give us the same\noutcome as if running the exclude check before the unpack.\n\nIt's \"almost unchanged\" because we do invalidate cache-tree and\nuntracked cache in the source index. But this should not affect how\nexclude machinery uses the index: to see if a file is tracked, and to\nread a blob from the index instead of worktree if it's marked\nskip-worktree (i.e. it's not available in worktree)\n\n[1] a0bba65b10 (dir: convert is_excluded to take an index - 2017-05-05\n[2] 2c1eb10454 (dir: convert read_directory to take an index - 2017-05-05)\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5268de7af5..3ace82ca27 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1651,7 +1651,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);\n+\ti = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\treturn o->gently ? -1 :\n \t\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);\n@@ -1693,7 +1693,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\treturn 0;\n \n \tif (o->dir &&\n-\t    is_excluded(o->dir, &the_index, name, &dtype))\n+\t    is_excluded(o->dir, o->src_index, name, &dtype))\n \t\t/*\n \t\t * ce->name is explicitly excluded, so it is Ok to\n \t\t * overwrite it.\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349446","messageId":"20180606073933.14755-4-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 03/20] unpack-trees: don't shadow global var the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:16Z","receivedAt":"2018-06-06T07:40:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function mark_new_skip_worktree() has an argument named the_index\nwhich is also the name of a global variable. While they have different\ntypes (the global the_index is not a pointer) mistakes can easily\nhappen and it's also confusing for readers. Rename the function\nargument to something other than the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5d06aa9c98..45fcda3169 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1231,7 +1231,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n  */\n static void mark_new_skip_worktree(struct exclude_list *el,\n-\t\t\t\t   struct index_state *the_index,\n+\t\t\t\t   struct index_state *istate,\n \t\t\t\t   int select_flag, int skip_wt_flag)\n {\n \tint i;\n@@ -1240,8 +1240,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 1. Pretend the narrowest worktree: only unmerged entries\n \t * are checked out\n \t */\n-\tfor (i = 0; i < the_index->cache_nr; i++) {\n-\t\tstruct cache_entry *ce = the_index->cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \n \t\tif (select_flag && !(ce->ce_flags & select_flag))\n \t\t\tcontinue;\n@@ -1256,8 +1256,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n-\t\t       select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349447","messageId":"20180606073933.14755-12-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 11/20] ls-files: correct index argument to get_convert_attr_ascii()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:24Z","receivedAt":"2018-06-06T07:40:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"write_eolinfo() does take an istate as function argument and it should\nbe used instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 17 +++++++++--------\n 1 file changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 7233b92794..7f9919a362 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate,\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(&the_index, path);\n+\t\tconst char *a_txt = get_convert_attr_ascii(istate, path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n \t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\n@@ -121,18 +121,19 @@ static void print_debug(const struct cache_entry *ce)\n \t}\n }\n \n-static void show_dir_entry(const char *tag, struct dir_entry *ent)\n+static void show_dir_entry(const struct index_state *istate,\n+\t\t\t   const char *tag, struct dir_entry *ent)\n {\n \tint len = max_prefix_len;\n \n \tif (len > ent->len)\n \t\tdie(\"git ls-files: internal error - directory entry not superset of prefix\");\n \n-\tif (!dir_path_match(&the_index, ent, &pathspec, len, ps_matched))\n+\tif (!dir_path_match(istate, ent, &pathspec, len, ps_matched))\n \t\treturn;\n \n \tfputs(tag, stdout);\n-\twrite_eolinfo(NULL, NULL, ent->name);\n+\twrite_eolinfo(istate, NULL, ent->name);\n \twrite_name(ent->name);\n }\n \n@@ -145,7 +146,7 @@ static void show_other_files(const struct index_state *istate,\n \t\tstruct dir_entry *ent = dir->entries[i];\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\tshow_dir_entry(istate, tag_other, ent);\n \t}\n }\n \n@@ -196,7 +197,7 @@ static void show_killed_files(const struct index_state *istate,\n \t\t\t}\n \t\t}\n \t\tif (killed)\n-\t\t\tshow_dir_entry(tag_killed, dir->entries[i]);\n+\t\t\tshow_dir_entry(istate, tag_killed, dir->entries[i]);\n \t}\n }\n \n@@ -228,7 +229,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,\n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n \t    is_submodule_active(repo, ce->name)) {\n \t\tshow_submodule(repo, dir, ce->name);\n-\t} else if (match_pathspec(&the_index, &pathspec, fullname, strlen(fullname),\n+\t} else if (match_pathspec(repo->index, &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@@ -264,7 +265,7 @@ static void show_ru_info(const struct index_state *istate)\n \t\tlen = strlen(path);\n \t\tif (len < max_prefix_len)\n \t\t\tcontinue; /* outside of the prefix */\n-\t\tif (!match_pathspec(&the_index, &pathspec, path, len,\n+\t\tif (!match_pathspec(istate, &pathspec, path, len,\n \t\t\t\t    max_prefix_len, ps_matched, 0))\n \t\t\tcontinue; /* uninterested */\n \t\tfor (i = 0; i < 3; i++) {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349448","messageId":"20180606073933.14755-11-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 10/20] dir.c: remove an implicit dependency on the_index in pathspec code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:23Z","receivedAt":"2018-06-06T07:40:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the match_patchspec API and friends take an index_state instead\nof assuming the_index in dir.c. All external call sites are converted\nblindly to keep the patch simple and retain current behavior.\nIndividual call sites may receive further updates to use the right\nindex instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c                   |  2 +-\n builtin/add.c               |  6 +++---\n builtin/checkout.c          |  2 +-\n builtin/clean.c             |  2 +-\n builtin/commit.c            |  2 +-\n builtin/grep.c              |  6 +++---\n builtin/ls-files.c          |  6 +++---\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c |  2 +-\n builtin/update-index.c      |  2 +-\n diff-lib.c                  |  4 ++--\n dir.c                       | 27 ++++++++++++++++-----------\n dir.h                       | 16 ++++++++++------\n pathspec.c                  |  2 +-\n preload-index.c             |  2 +-\n read-cache.c                |  2 +-\n rerere.c                    |  2 +-\n resolve-undo.c              |  2 +-\n revision.c                  |  2 +-\n submodule.c                 |  2 +-\n wt-status.c                 |  6 +++---\n 21 files changed, 54 insertions(+), 45 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex f3631a4fb5..1b44503ebb 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -312,7 +312,7 @@ static int reject_entry(const struct object_id *oid, struct strbuf *base,\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstrbuf_addbuf(&sb, base);\n \t\tstrbuf_addstr(&sb, filename);\n-\t\tif (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))\n+\t\tif (!match_pathspec(&the_index, context, sb.buf, sb.len, 0, NULL, 1))\n \t\t\tret = READ_TREE_RECURSIVE;\n \t\tstrbuf_release(&sb);\n \t}\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 8a155dd41e..066623a195 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -40,7 +40,7 @@ static void chmod_pathspec(struct pathspec *pathspec, char flip)\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n \n-\t\tif (pathspec && !ce_path_match(ce, pathspec, NULL))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \n \t\tif (chmod_cache_entry(ce, flip) < 0)\n@@ -135,7 +135,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)\n \t\t\tcontinue; /* do not touch unmerged paths */\n \t\tif (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))\n \t\t\tcontinue; /* do not touch non blobs */\n-\t\tif (pathspec && !ce_path_match(ce, pathspec, NULL))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\tretval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE);\n \t}\n@@ -155,7 +155,7 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,\n \ti = dir->nr;\n \twhile (--i >= 0) {\n \t\tstruct dir_entry *entry = *src++;\n-\t\tif (dir_path_match(entry, pathspec, prefix, seen))\n+\t\tif (dir_path_match(&the_index, entry, pathspec, prefix, seen))\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2e1d2376d2..f8c208cea1 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -316,7 +316,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t * match_pathspec() for _all_ entries when\n \t\t * opts->source_tree != NULL.\n \t\t */\n-\t\tif (ce_path_match(ce, &opts->pathspec, ps_matched))\n+\t\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n \t\t\tce->ce_flags |= CE_MATCHED;\n \t}\n \ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex fad533a0a7..d4ca64904f 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -981,7 +981,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \n \t\tif (pathspec.nr)\n-\t\t\tmatches = dir_path_match(ent, &pathspec, 0, NULL);\n+\t\t\tmatches = dir_path_match(&the_index, ent, &pathspec, 0, NULL);\n \n \t\tif (pathspec.nr && !matches)\n \t\t\tcontinue;\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex a842fea666..f593ec1bbc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -238,7 +238,7 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, pattern, m))\n+\t\tif (!ce_path_match(&the_index, ce, pattern, m))\n \t\t\tcontinue;\n \t\titem = string_list_insert(list, ce->name);\n \t\tif (ce_skip_worktree(ce))\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex ee753a403e..2eae397e92 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\tstrbuf_addstr(&name, ce->name);\n \n \t\tif (S_ISREG(ce->ce_mode) &&\n-\t\t    match_pathspec(pathspec, name.buf, name.len, 0, NULL,\n+\t\t    match_pathspec(&the_index, pathspec, name.buf, name.len, 0, NULL,\n \t\t\t\t   S_ISDIR(ce->ce_mode) ||\n \t\t\t\t   S_ISGITLINK(ce->ce_mode))) {\n \t\t\t/*\n@@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\t\t\thit |= grep_file(opt, name.buf);\n \t\t\t}\n \t\t} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t\t\t   submodule_path_match(pathspec, name.buf, NULL)) {\n+\t\t\t   submodule_path_match(&the_index, pathspec, name.buf, NULL)) {\n \t\t\thit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);\n \t\t} else {\n \t\t\tcontinue;\n@@ -678,7 +678,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,\n \n \tfill_directory(&dir, &the_index, pathspec);\n \tfor (i = 0; i < dir.nr; i++) {\n-\t\tif (!dir_path_match(dir.entries[i], pathspec, 0, NULL))\n+\t\tif (!dir_path_match(&the_index, dir.entries[i], pathspec, 0, NULL))\n \t\t\tcontinue;\n \t\thit |= grep_file(opt, dir.entries[i]->name);\n \t\tif (hit && opt->status_only)\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex d996734b45..7233b92794 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -128,7 +128,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \tif (len > ent->len)\n \t\tdie(\"git ls-files: internal error - directory entry not superset of prefix\");\n \n-\tif (!dir_path_match(ent, &pathspec, len, ps_matched))\n+\tif (!dir_path_match(&the_index, ent, &pathspec, len, ps_matched))\n \t\treturn;\n \n \tfputs(tag, stdout);\n@@ -228,7 +228,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,\n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\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} else if (match_pathspec(&the_index, &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@@ -264,7 +264,7 @@ static void show_ru_info(const struct index_state *istate)\n \t\tlen = strlen(path);\n \t\tif (len < max_prefix_len)\n \t\t\tcontinue; /* outside of the prefix */\n-\t\tif (!match_pathspec(&pathspec, path, len,\n+\t\tif (!match_pathspec(&the_index, &pathspec, path, len,\n \t\t\t\t    max_prefix_len, ps_matched, 0))\n \t\t\tcontinue; /* uninterested */\n \t\tfor (i = 0; i < 3; i++) {\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 65b448ef8e..eebdc4aab1 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -278,7 +278,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \n \tfor (i = 0; i < active_nr; i++) {\n \t\tconst struct cache_entry *ce = active_cache[i];\n-\t\tif (!ce_path_match(ce, &pathspec, seen))\n+\t\tif (!ce_path_match(&the_index, ce, &pathspec, seen))\n \t\t\tcontinue;\n \t\tALLOC_GROW(list.entry, list.nr + 1, list.alloc);\n \t\tlist.entry[list.nr].name = xstrdup(ce->name);\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bd250ca216..d59c6a988e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -330,7 +330,7 @@ static int module_list_compute(int argc, const char **argv,\n \tfor (i = 0; i < active_nr; i++) {\n \t\tconst struct cache_entry *ce = active_cache[i];\n \n-\t\tif (!match_pathspec(pathspec, ce->name, ce_namelen(ce),\n+\t\tif (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),\n \t\t\t\t    0, ps_matched, 1) ||\n \t\t    !S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex a8709a26ec..a181b5c14c 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -751,7 +751,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tint save_nr;\n \t\tchar *path;\n \n-\t\tif (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))\n+\t\tif (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (has_head)\n \t\t\told = read_one_ent(NULL, &head_oid,\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 104f954a25..068d00705e 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -109,7 +109,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\tif (diff_can_quit_early(&revs->diffopt))\n \t\t\tbreak;\n \n-\t\tif (!ce_path_match(ce, &revs->prune_data, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &revs->prune_data, NULL))\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n@@ -470,7 +470,7 @@ static int oneway_diff(const struct cache_entry * const *src,\n \tif (tree == o->df_conflict_entry)\n \t\ttree = NULL;\n \n-\tif (ce_path_match(idx ? idx : tree, &revs->prune_data, NULL)) {\n+\tif (ce_path_match(&the_index, idx ? idx : tree, &revs->prune_data, NULL)) {\n \t\tdo_oneway_diff(o, idx, tree);\n \t\tif (diff_can_quit_early(&revs->diffopt)) {\n \t\t\to->exiting_early = 1;\ndiff --git a/dir.c b/dir.c\nindex a541be3032..1f50559548 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -275,12 +275,13 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,\n #define DO_MATCH_DIRECTORY (1<<1)\n #define DO_MATCH_SUBMODULE (1<<2)\n \n-static int match_attrs(const char *name, int namelen,\n+static int match_attrs(const struct index_state *istate,\n+\t\t       const char *name, int namelen,\n \t\t       const struct pathspec_item *item)\n {\n \tint i;\n \n-\tgit_check_attr(&the_index, name, item->attr_check);\n+\tgit_check_attr(istate, name, item->attr_check);\n \tfor (i = 0; i < item->attr_match_nr; i++) {\n \t\tconst char *value;\n \t\tint matched;\n@@ -317,7 +318,8 @@ static int match_attrs(const char *name, int namelen,\n  *\n  * It returns 0 when there is no match.\n  */\n-static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n+static int match_pathspec_item(const struct index_state *istate,\n+\t\t\t       const struct pathspec_item *item, int prefix,\n \t\t\t       const char *name, int namelen, unsigned flags)\n {\n \t/* name/namelen has prefix cut off by caller */\n@@ -357,7 +359,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n \t    strncmp(item->match, name - prefix, item->prefix))\n \t\treturn 0;\n \n-\tif (item->attr_match_nr && !match_attrs(name, namelen, item))\n+\tif (item->attr_match_nr && !match_attrs(istate, name, namelen, item))\n \t\treturn 0;\n \n \t/* If the match was just the prefix, we matched */\n@@ -425,7 +427,8 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n  * pathspec did not match any names, which could indicate that the\n  * user mistyped the nth pathspec.\n  */\n-static int do_match_pathspec(const struct pathspec *ps,\n+static int do_match_pathspec(const struct index_state *istate,\n+\t\t\t     const struct pathspec *ps,\n \t\t\t     const char *name, int namelen,\n \t\t\t     int prefix, char *seen,\n \t\t\t     unsigned flags)\n@@ -471,7 +474,7 @@ static int do_match_pathspec(const struct pathspec *ps,\n \t\t */\n \t\tif (seen && ps->items[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tseen[i] = MATCHED_FNMATCH;\n-\t\thow = match_pathspec_item(ps->items+i, prefix, name,\n+\t\thow = match_pathspec_item(istate, ps->items+i, prefix, name,\n \t\t\t\t\t  namelen, flags);\n \t\tif (ps->recursive &&\n \t\t    (ps->magic & PATHSPEC_MAXDEPTH) &&\n@@ -495,17 +498,18 @@ static int do_match_pathspec(const struct pathspec *ps,\n \treturn retval;\n }\n \n-int match_pathspec(const struct pathspec *ps,\n+int match_pathspec(const struct index_state *istate,\n+\t\t   const struct pathspec *ps,\n \t\t   const char *name, int namelen,\n \t\t   int prefix, char *seen, int is_dir)\n {\n \tint positive, negative;\n \tunsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;\n-\tpositive = do_match_pathspec(ps, name, namelen,\n+\tpositive = do_match_pathspec(istate, ps, name, namelen,\n \t\t\t\t     prefix, seen, flags);\n \tif (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)\n \t\treturn positive;\n-\tnegative = do_match_pathspec(ps, name, namelen,\n+\tnegative = do_match_pathspec(istate, ps, name, namelen,\n \t\t\t\t     prefix, seen,\n \t\t\t\t     flags | DO_MATCH_EXCLUDE);\n \treturn negative ? 0 : positive;\n@@ -514,11 +518,12 @@ int match_pathspec(const struct pathspec *ps,\n /**\n  * Check if a submodule is a superset of the pathspec\n  */\n-int submodule_path_match(const struct pathspec *ps,\n+int submodule_path_match(const struct index_state *istate,\n+\t\t\t const struct pathspec *ps,\n \t\t\t const char *submodule_name,\n \t\t\t char *seen)\n {\n-\tint matched = do_match_pathspec(ps, submodule_name,\n+\tint matched = do_match_pathspec(istate, ps, submodule_name,\n \t\t\t\t\tstrlen(submodule_name),\n \t\t\t\t\t0, seen,\n \t\t\t\t\tDO_MATCH_DIRECTORY |\ndiff --git a/dir.h b/dir.h\nindex f5fdedbab2..e3ec26143d 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -216,7 +216,8 @@ extern int count_slashes(const char *s);\n extern int simple_length(const char *match);\n extern int no_wildcard(const char *string);\n extern char *common_prefix(const struct pathspec *pathspec);\n-extern int match_pathspec(const struct pathspec *pathspec,\n+extern int match_pathspec(const struct index_state *istate,\n+\t\t\t  const struct pathspec *pathspec,\n \t\t\t  const char *name, int namelen,\n \t\t\t  int prefix, char *seen, int is_dir);\n extern int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);\n@@ -326,25 +327,28 @@ extern int git_fnmatch(const struct pathspec_item *item,\n \t\t       const char *pattern, const char *string,\n \t\t       int prefix);\n \n-extern int submodule_path_match(const struct pathspec *ps,\n+extern int submodule_path_match(const struct index_state *istate,\n+\t\t\t\tconst struct pathspec *ps,\n \t\t\t\tconst char *submodule_name,\n \t\t\t\tchar *seen);\n \n-static inline int ce_path_match(const struct cache_entry *ce,\n+static inline int ce_path_match(const struct index_state *istate,\n+\t\t\t\tconst struct cache_entry *ce,\n \t\t\t\tconst struct pathspec *pathspec,\n \t\t\t\tchar *seen)\n {\n-\treturn match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen,\n+\treturn match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,\n \t\t\t      S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));\n }\n \n-static inline int dir_path_match(const struct dir_entry *ent,\n+static inline int dir_path_match(const struct index_state *istate,\n+\t\t\t\t const struct dir_entry *ent,\n \t\t\t\t const struct pathspec *pathspec,\n \t\t\t\t int prefix, char *seen)\n {\n \tint has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/';\n \tint len = has_trailing_dir ? ent->len - 1 : ent->len;\n-\treturn match_pathspec(pathspec, ent->name, len, prefix, seen,\n+\treturn match_pathspec(istate, pathspec, ent->name, len, prefix, seen,\n \t\t\t      has_trailing_dir);\n }\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 27cd606786..897cb9cbbe 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -37,7 +37,7 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,\n \t\treturn;\n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tce_path_match(ce, pathspec, seen);\n+\t\tce_path_match(&the_index, ce, pathspec, seen);\n \t}\n }\n \ndiff --git a/preload-index.c b/preload-index.c\nindex 4d08d44874..d61d7662d5 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -58,7 +58,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce->ce_flags & CE_FSMONITOR_VALID)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, &p->pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &p->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\ndiff --git a/read-cache.c b/read-cache.c\nindex 372588260e..12cc22d157 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1415,7 +1415,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \t\tif (ignore_submodules && S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (pathspec && !ce_path_match(ce, pathspec, seen))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))\n \t\t\tfiltered = 1;\n \n \t\tif (ce_stage(ce)) {\ndiff --git a/rerere.c b/rerere.c\nindex e0862e2778..e3b572296d 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -1118,7 +1118,7 @@ int rerere_forget(struct pathspec *pathspec)\n \tfind_conflict(&conflict);\n \tfor (i = 0; i < conflict.nr; i++) {\n \t\tstruct string_list_item *it = &conflict.items[i];\n-\t\tif (!match_pathspec(pathspec, it->string,\n+\t\tif (!match_pathspec(&the_index, pathspec, it->string,\n \t\t\t\t    strlen(it->string), 0, NULL, 0))\n \t\t\tcontinue;\n \t\trerere_forget_one_path(it->string, &merge_rr);\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex fc5b3b83d9..5e4c8c5f75 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -186,7 +186,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)\n \n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_path_match(ce, pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\ti = unmerge_index_entry_at(istate, i);\n \t}\ndiff --git a/revision.c b/revision.c\nindex 40fd91ff2b..cf6aa1f443 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1501,7 +1501,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\tconst struct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (ce_path_match(ce, &revs->prune_data, NULL)) {\n+\t\tif (ce_path_match(&the_index, ce, &revs->prune_data, NULL)) {\n \t\t\tprune_num++;\n \t\t\tREALLOC_ARRAY(prune, prune_num);\n \t\t\tprune[prune_num-2] = ce->name;\ndiff --git a/submodule.c b/submodule.c\nindex 939d6870ec..955560bdbb 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -258,7 +258,7 @@ int is_submodule_active(struct repository *repo, const char *path)\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+\t\tret = match_pathspec(&the_index, &ps, path, strlen(path), 0, NULL, 1);\n \n \t\targv_array_clear(&args);\n \t\tclear_pathspec(&ps);\ndiff --git a/wt-status.c b/wt-status.c\nindex d1c05145a4..d384294c12 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -647,7 +647,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\tstruct wt_status_change_data *d;\n \t\tconst struct cache_entry *ce = active_cache[i];\n \n-\t\tif (!ce_path_match(ce, &s->pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &s->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (ce_intent_to_add(ce))\n \t\t\tcontinue;\n@@ -703,7 +703,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\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\t    dir_path_match(ent, &s->pathspec, 0, NULL))\n+\t\t    dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))\n \t\t\tstring_list_insert(&s->untracked, ent->name);\n \t\tfree(ent);\n \t}\n@@ -711,7 +711,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \tfor (i = 0; i < dir.ignored_nr; i++) {\n \t\tstruct dir_entry *ent = dir.ignored[i];\n \t\tif (cache_name_is_other(ent->name, ent->len) &&\n-\t\t    dir_path_match(ent, &s->pathspec, 0, NULL))\n+\t\t    dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))\n \t\t\tstring_list_insert(&s->ignored, ent->name);\n \t\tfree(ent);\n \t}\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349449","messageId":"20180606073933.14755-15-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 14/20] entry.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:27Z","receivedAt":"2018-06-06T07:40:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"checkout-index.c needs update because if checkout->istate is NULL,\nie_match_stat() will crash. Previously this is ie_match_stat(&the_index, ..)\nso it will not crash, but it is not technically correct either.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout-index.c |  1 +\n entry.c                  | 10 ++++++----\n 2 files changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex a730f6a1aa..d92db62fbd 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -190,6 +190,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, builtin_checkout_index_options,\n \t\t\tbuiltin_checkout_index_usage, 0);\n+\tstate.istate = &the_index;\n \tstate.force = force;\n \tstate.quiet = quiet;\n \tstate.not_new = not_new;\ndiff --git a/entry.c b/entry.c\nindex 12d9191051..02752f7b53 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"blob.h\"\n #include \"dir.h\"\n@@ -265,7 +266,7 @@ static int write_entry(struct cache_entry *ce,\n \tconst struct submodule *sub;\n \n \tif (ce_mode_s_ifmt == S_IFREG) {\n-\t\tstruct stream_filter *filter = get_stream_filter(&the_index, ce->name,\n+\t\tstruct stream_filter *filter = get_stream_filter(state->istate, ce->name,\n \t\t\t\t\t\t\t\t &ce->oid);\n \t\tif (filter &&\n \t\t    !streaming_write_entry(ce, path, filter,\n@@ -313,14 +314,14 @@ static int write_entry(struct cache_entry *ce,\n \t\t * Convert from git internal format to working tree format\n \t\t */\n \t\tif (dco && dco->state != CE_NO_DELAY) {\n-\t\t\tret = async_convert_to_working_tree(&the_index, ce->name, new_blob,\n+\t\t\tret = async_convert_to_working_tree(state->istate, ce->name, new_blob,\n \t\t\t\t\t\t\t    size, &buf, dco);\n \t\t\tif (ret && string_list_has_string(&dco->paths, ce->name)) {\n \t\t\t\tfree(new_blob);\n \t\t\t\tgoto delayed;\n \t\t\t}\n \t\t} else\n-\t\t\tret = convert_to_working_tree(&the_index, ce->name, new_blob, size, &buf);\n+\t\t\tret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf);\n \n \t\tif (ret) {\n \t\t\tfree(new_blob);\n@@ -421,7 +422,8 @@ int checkout_entry(struct cache_entry *ce,\n \n \tif (!check_path(path.buf, path.len, &st, state->base_dir_len)) {\n \t\tconst struct submodule *sub;\n-\t\tunsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n+\t\tunsigned changed = ie_match_stat(state->istate, ce, &st,\n+\t\t\t\t\t\t CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n \t\t/*\n \t\t * Needs to be checked before !changed returns early,\n \t\t * as the possibly empty directory was not changed\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349450","messageId":"20180606073933.14755-10-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 09/20] convert.c: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:22Z","receivedAt":"2018-06-06T07:40:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the convert API take an index_state instead of assuming the_index\nin convert.c. All external call sites are converted blindly to keep\nthe patch simple and retain current behavior. Individual call sites\nmay receive further updates to use the right index instead of\nthe_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n apply.c            |  2 +-\n archive.c          |  2 +-\n builtin/cat-file.c |  2 +-\n builtin/ls-files.c |  2 +-\n convert.c          | 41 ++++++++++++++++++++++++-----------------\n convert.h          | 15 ++++++++++-----\n diff.c             |  2 +-\n entry.c            |  6 +++---\n merge-recursive.c  |  2 +-\n sha1-file.c        |  4 ++--\n 10 files changed, 45 insertions(+), 33 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex d79e61591b..9720855590 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4333,7 +4333,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,\n \tif (fd < 0)\n \t\treturn 1;\n \n-\tif (convert_to_working_tree(path, buf, size, &nbuf)) {\n+\tif (convert_to_working_tree(&the_index, path, buf, size, &nbuf)) {\n \t\tsize = nbuf.len;\n \t\tbuf  = nbuf.buf;\n \t}\ndiff --git a/archive.c b/archive.c\nindex 3b4db8956a..f3631a4fb5 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -78,7 +78,7 @@ void *object_file_to_archive(const struct archiver_args *args,\n \t\tsize_t size = 0;\n \n \t\tstrbuf_attach(&buf, buffer, *sizep, *sizep + 1);\n-\t\tconvert_to_working_tree(path, buf.buf, buf.len, &buf);\n+\t\tconvert_to_working_tree(&the_index, path, buf.buf, buf.len, &buf);\n \t\tif (commit)\n \t\t\tformat_subst(commit, buf.buf, buf.len, &buf);\n \t\tbuffer = strbuf_detach(&buf, &size);\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 665b581949..a615a0048b 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -38,7 +38,7 @@ static int filter_object(const char *path, unsigned mode,\n \t\t\t     oid_to_hex(oid), path);\n \tif ((type == OBJ_BLOB) && S_ISREG(mode)) {\n \t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n+\t\tif (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) {\n \t\t\tfree(*buf);\n \t\t\t*size = strbuf.len;\n \t\t\t*buf = strbuf_detach(&strbuf, NULL);\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 88bb2019ad..d996734b45 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate,\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\tconst char *a_txt = get_convert_attr_ascii(&the_index, path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n \t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\ndiff --git a/convert.c b/convert.c\nindex 9d5dc32564..2b1a87a104 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1290,7 +1290,8 @@ struct conv_attrs {\n \tconst char *working_tree_encoding; /* Supported encoding or default encoding if NULL */\n };\n \n-static void convert_attrs(struct conv_attrs *ca, const char *path)\n+static void convert_attrs(const struct index_state *istate,\n+\t\t\t  struct conv_attrs *ca, const char *path)\n {\n \tstatic struct attr_check *check;\n \n@@ -1302,7 +1303,7 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tgit_config(read_convert_config, NULL);\n \t}\n \n-\tif (!git_check_attr(&the_index, path, check)) {\n+\tif (!git_check_attr(istate, path, check)) {\n \t\tstruct attr_check_item *ccheck = check->items;\n \t\tca->crlf_action = git_path_check_crlf(ccheck + 4);\n \t\tif (ca->crlf_action == CRLF_UNDEFINED)\n@@ -1339,11 +1340,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->crlf_action = CRLF_AUTO_INPUT;\n }\n \n-int would_convert_to_git_filter_fd(const char *path)\n+int would_convert_to_git_filter_fd(const struct index_state *istate, const char *path)\n {\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tif (!ca.drv)\n \t\treturn 0;\n \n@@ -1358,11 +1359,11 @@ int would_convert_to_git_filter_fd(const char *path)\n \treturn apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL);\n }\n \n-const char *get_convert_attr_ascii(const char *path)\n+const char *get_convert_attr_ascii(const struct index_state *istate, const char *path)\n {\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tswitch (ca.attr_action) {\n \tcase CRLF_UNDEFINED:\n \t\treturn \"\";\n@@ -1391,7 +1392,7 @@ int convert_to_git(const struct index_state *istate,\n \tint ret = 0;\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);\n \tif (!ret && ca.drv && ca.drv->required)\n@@ -1423,7 +1424,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \t\t\t      int conv_flags)\n {\n \tstruct conv_attrs ca;\n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tassert(ca.drv);\n \tassert(ca.drv->clean || ca.drv->process);\n@@ -1436,14 +1437,15 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-static int convert_to_working_tree_internal(const char *path, const char *src,\n+static int convert_to_working_tree_internal(const struct index_state *istate,\n+\t\t\t\t\t    const char *path, const char *src,\n \t\t\t\t\t    size_t len, struct strbuf *dst,\n \t\t\t\t\t    int normalizing, struct delayed_checkout *dco)\n {\n \tint ret = 0, ret_filter = 0;\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tret |= ident_to_worktree(path, src, len, dst, ca.ident);\n \tif (ret) {\n@@ -1477,22 +1479,25 @@ static int convert_to_working_tree_internal(const char *path, const char *src,\n \treturn ret | ret_filter;\n }\n \n-int async_convert_to_working_tree(const char *path, const char *src,\n+int async_convert_to_working_tree(const struct index_state *istate,\n+\t\t\t\t  const char *path, const char *src,\n \t\t\t\t  size_t len, struct strbuf *dst,\n \t\t\t\t  void *dco)\n {\n-\treturn convert_to_working_tree_internal(path, src, len, dst, 0, dco);\n+\treturn convert_to_working_tree_internal(istate, path, src, len, dst, 0, dco);\n }\n \n-int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)\n+int convert_to_working_tree(const struct index_state *istate,\n+\t\t\t    const char *path, const char *src,\n+\t\t\t    size_t len, struct strbuf *dst)\n {\n-\treturn convert_to_working_tree_internal(path, src, len, dst, 0, NULL);\n+\treturn convert_to_working_tree_internal(istate, path, src, len, dst, 0, NULL);\n }\n \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, NULL);\n+\tint ret = convert_to_working_tree_internal(istate, path, src, len, dst, 1, NULL);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1926,12 +1931,14 @@ static struct stream_filter *ident_filter(const struct object_id *oid)\n  * Note that you would be crazy to set CRLF, smuge/clean or ident to a\n  * large binary blob you would want us not to slurp into the memory!\n  */\n-struct stream_filter *get_stream_filter(const char *path, const struct object_id *oid)\n+struct stream_filter *get_stream_filter(const struct index_state *istate,\n+\t\t\t\t\tconst char *path,\n+\t\t\t\t\tconst struct object_id *oid)\n {\n \tstruct conv_attrs ca;\n \tstruct stream_filter *filter = NULL;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tif (ca.drv && (ca.drv->process || ca.drv->smudge || ca.drv->clean))\n \t\treturn NULL;\n \ndiff --git a/convert.h b/convert.h\nindex 0a0fa15b58..6d0ee887ed 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -60,15 +60,18 @@ extern char *check_roundtrip_encoding;\n const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n \t\t\t\t\t   const char *path);\n const char *get_wt_convert_stats_ascii(const char *path);\n-const char *get_convert_attr_ascii(const char *path);\n+const char *get_convert_attr_ascii(const struct index_state *istate,\n+\t\t\t\t   const char *path);\n \n /* returns 1 if *dst was used */\n int convert_to_git(const struct index_state *istate,\n \t\t   const char *path, const char *src, size_t len,\n \t\t   struct strbuf *dst, int conv_flags);\n-int convert_to_working_tree(const char *path, const char *src,\n+int convert_to_working_tree(const struct index_state *istate,\n+\t\t\t    const char *path, const char *src,\n \t\t\t    size_t len, struct strbuf *dst);\n-int async_convert_to_working_tree(const char *path, const char *src,\n+int async_convert_to_working_tree(const struct index_state *istate,\n+\t\t\t\t  const char *path, const char *src,\n \t\t\t\t  size_t len, struct strbuf *dst,\n \t\t\t\t  void *dco);\n int async_query_available_blobs(const char *cmd,\n@@ -86,7 +89,8 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \t\t\t      const char *path, int fd,\n \t\t\t      struct strbuf *dst,\n \t\t\t      int conv_flags);\n-int would_convert_to_git_filter_fd(const char *path);\n+int would_convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t\t   const char *path);\n \n /*****************************************************************\n  *\n@@ -96,7 +100,8 @@ int would_convert_to_git_filter_fd(const char *path);\n \n struct stream_filter; /* opaque */\n \n-struct stream_filter *get_stream_filter(const char *path,\n+struct stream_filter *get_stream_filter(const struct index_state *istate,\n+\t\t\t\t\tconst char *path,\n \t\t\t\t\tconst struct object_id *);\n void free_stream_filter(struct stream_filter *);\n int is_null_stream_filter(struct stream_filter *);\ndiff --git a/diff.c b/diff.c\nindex 136d44b455..526ee2e911 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3695,7 +3695,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\n \ttemp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1);\n \tif (!temp->tempfile)\n \t\tdie_errno(\"unable to create temp-file\");\n-\tif (convert_to_working_tree(path,\n+\tif (convert_to_working_tree(&the_index, path,\n \t\t\t(const char *)blob, (size_t)size, &buf)) {\n \t\tblob = buf.buf;\n \t\tsize = buf.len;\ndiff --git a/entry.c b/entry.c\nindex 2101201a11..12d9191051 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -265,7 +265,7 @@ static int write_entry(struct cache_entry *ce,\n \tconst struct submodule *sub;\n \n \tif (ce_mode_s_ifmt == S_IFREG) {\n-\t\tstruct stream_filter *filter = get_stream_filter(ce->name,\n+\t\tstruct stream_filter *filter = get_stream_filter(&the_index, ce->name,\n \t\t\t\t\t\t\t\t &ce->oid);\n \t\tif (filter &&\n \t\t    !streaming_write_entry(ce, path, filter,\n@@ -313,14 +313,14 @@ static int write_entry(struct cache_entry *ce,\n \t\t * Convert from git internal format to working tree format\n \t\t */\n \t\tif (dco && dco->state != CE_NO_DELAY) {\n-\t\t\tret = async_convert_to_working_tree(ce->name, new_blob,\n+\t\t\tret = async_convert_to_working_tree(&the_index, ce->name, new_blob,\n \t\t\t\t\t\t\t    size, &buf, dco);\n \t\t\tif (ret && string_list_has_string(&dco->paths, ce->name)) {\n \t\t\t\tfree(new_blob);\n \t\t\t\tgoto delayed;\n \t\t\t}\n \t\t} else\n-\t\t\tret = convert_to_working_tree(ce->name, new_blob, size, &buf);\n+\t\t\tret = convert_to_working_tree(&the_index, ce->name, new_blob, size, &buf);\n \n \t\tif (ret) {\n \t\t\tfree(new_blob);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ac27abbd4c..b404ebac7c 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -961,7 +961,7 @@ static int update_file_flags(struct merge_options *o,\n \t\t}\n \t\tif (S_ISREG(mode)) {\n \t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(path, buf, size, &strbuf)) {\n+\t\t\tif (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {\n \t\t\t\tfree(buf);\n \t\t\t\tsize = strbuf.len;\n \t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\ndiff --git a/sha1-file.c b/sha1-file.c\nindex 555e780f4b..0b0834452d 100644\n--- a/sha1-file.c\n+++ b/sha1-file.c\n@@ -1860,7 +1860,7 @@ static int index_stream_convert_blob(struct object_id *oid, int fd,\n \tstruct strbuf sbuf = STRBUF_INIT;\n \n \tassert(path);\n-\tassert(would_convert_to_git_filter_fd(path));\n+\tassert(would_convert_to_git_filter_fd(&the_index, path));\n \n \tconvert_to_git_filter_fd(&the_index, path, fd, &sbuf,\n \t\t\t\t get_conv_flags(flags));\n@@ -1950,7 +1950,7 @@ int index_fd(struct object_id *oid, int fd, struct stat *st,\n \t * Call xsize_t() only when needed to avoid potentially unnecessary\n \t * die() for large files.\n \t */\n-\tif (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(path))\n+\tif (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(&the_index, path))\n \t\tret = index_stream_convert_blob(oid, fd, path, flags);\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(oid, fd, type, path, flags);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349451","messageId":"20180606073933.14755-20-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 19/20] grep: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:32Z","receivedAt":"2018-06-06T07:40:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 2eae397e92..a8cef2b159 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\tstrbuf_addstr(&name, ce->name);\n \n \t\tif (S_ISREG(ce->ce_mode) &&\n-\t\t    match_pathspec(&the_index, pathspec, name.buf, name.len, 0, NULL,\n+\t\t    match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,\n \t\t\t\t   S_ISDIR(ce->ce_mode) ||\n \t\t\t\t   S_ISGITLINK(ce->ce_mode))) {\n \t\t\t/*\n@@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\t\t\thit |= grep_file(opt, name.buf);\n \t\t\t}\n \t\t} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t\t\t   submodule_path_match(&the_index, pathspec, name.buf, NULL)) {\n+\t\t\t   submodule_path_match(repo->index, pathspec, name.buf, NULL)) {\n \t\t\thit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);\n \t\t} else {\n \t\t\tcontinue;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349452","messageId":"20180606073933.14755-18-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 17/20] cache.c: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:30Z","receivedAt":"2018-06-06T07:40:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make some index API take an index_state instead of assuming the_index\nin read-cache.c. All external call sites are converted blindly to keep\nthe patch simple and retain current behavior.  Individual call sites\nmay receive further updates to use the right index instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n apply.c            |  2 +-\n builtin/checkout.c |  2 +-\n builtin/difftool.c |  4 ++--\n builtin/reset.c    |  2 +-\n cache.h            |  5 +++--\n merge-recursive.c  |  2 +-\n read-cache.c       | 19 +++++++++++--------\n resolve-undo.c     |  2 +-\n 8 files changed, 21 insertions(+), 17 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 9720855590..811ff2ad5e 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4090,7 +4090,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n \t\t\treturn error(_(\"sha1 information is lacking or useless \"\n \t\t\t\t       \"(%s).\"), name);\n \n-\t\tce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);\n+\t\tce = make_cache_entry(&the_index, patch->old_mode, oid.hash, name, 0, 0);\n \t\tif (!ce)\n \t\t\treturn error(_(\"make_cache_entry failed for path '%s'\"),\n \t\t\t\t     name);\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex f8c208cea1..3c8218304e 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -230,7 +230,7 @@ static int checkout_merged(int pos, const struct checkout *state)\n \tif (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n \tfree(result_buf.ptr);\n-\tce = make_cache_entry(mode, oid.hash, path, 2, 0);\n+\tce = make_cache_entry(&the_index, mode, oid.hash, path, 2, 0);\n \tif (!ce)\n \t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex bc97d4aef2..e34e75a42d 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -321,7 +321,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(mode, oid->hash, path, 0, 0);\n+\tce = make_cache_entry(&the_index, mode, oid->hash, path, 0, 0);\n \tret = checkout_entry(ce, state, NULL);\n \n \tfree(ce);\n@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\t * index.\n \t\t\t\t */\n \t\t\t\tstruct cache_entry *ce2 =\n-\t\t\t\t\tmake_cache_entry(rmode, roid.hash,\n+\t\t\t\t\tmake_cache_entry(&the_index, rmode, roid.hash,\n \t\t\t\t\t\t\t dst_path, 0, 0);\n \n \t\t\t\tadd_index_entry(&wtindex, ce2,\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex a862c70fab..0ea0a19d5e 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tce = make_cache_entry(one->mode, one->oid.hash, one->path,\n+\t\tce = make_cache_entry(&the_index, one->mode, one->oid.hash, one->path,\n \t\t\t\t      0, 0);\n \t\tif (!ce)\n \t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\ndiff --git a/cache.h b/cache.h\nindex 89a107a7f7..5939233eb7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -355,6 +355,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerged_cache() unmerged_index(&the_index)\n #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))\n #define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))\n+#define refresh_cache_entry(ce, flags) refresh_index_entry(&the_index, ce, flags)\n #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))\n #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))\n #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))\n@@ -698,7 +699,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n \n-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n+extern struct cache_entry *make_cache_entry(struct index_state *istate,unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);\n@@ -751,7 +752,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n #define REFRESH_IGNORE_SUBMODULES\t0x0010\t/* ignore submodules */\n #define REFRESH_IN_PORCELAIN\t0x0020\t/* user friendly output, not \"needs update\" */\n extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);\n-extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);\n+extern struct cache_entry *refresh_index_entry(struct index_state *istate, struct cache_entry *, unsigned int);\n \n /*\n  * Opportunistically update the index but do not complain if we can't.\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex b404ebac7c..9280deb6a1 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n+\tce = make_cache_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n \tif (!ce)\n \t\treturn err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 12cc22d157..c083318aa7 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -745,9 +745,11 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \treturn add_to_index(istate, path, &st, flags);\n }\n \n-struct cache_entry *make_cache_entry(unsigned int mode,\n-\t\tconst unsigned char *sha1, const char *path, int stage,\n-\t\tunsigned int refresh_options)\n+struct cache_entry *make_cache_entry(struct index_state *istate,\n+\t\t\t\t     unsigned int mode,\n+\t\t\t\t     const unsigned char *sha1,\n+\t\t\t\t     const char *path, int stage,\n+\t\t\t\t     unsigned int refresh_options)\n {\n \tint size, len;\n \tstruct cache_entry *ce, *ret;\n@@ -767,7 +769,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n \tce->ce_namelen = len;\n \tce->ce_mode = create_ce_mode(mode);\n \n-\tret = refresh_cache_entry(ce, refresh_options);\n+\tret = refresh_index_entry(istate, ce, refresh_options);\n \tif (ret != ce)\n \t\tfree(ce);\n \treturn ret;\n@@ -1415,7 +1417,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \t\tif (ignore_submodules && S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))\n+\t\tif (pathspec && !ce_path_match(istate, ce, pathspec, seen))\n \t\t\tfiltered = 1;\n \n \t\tif (ce_stage(ce)) {\n@@ -1473,10 +1475,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \treturn has_errors;\n }\n \n-struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n-\t\t\t\t\t       unsigned int options)\n+struct cache_entry *refresh_index_entry(struct index_state *istate,\n+\t\t\t\t\tstruct cache_entry *ce,\n+\t\t\t\t\tunsigned int options)\n {\n-\treturn refresh_cache_ent(&the_index, ce, options, NULL, NULL);\n+\treturn refresh_cache_ent(istate, ce, options, NULL, NULL);\n }\n \n \ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex 5e4c8c5f75..9c45fe5d1d 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -146,7 +146,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tstruct cache_entry *nce;\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n-\t\tnce = make_cache_entry(ru->mode[i], ru->oid[i].hash,\n+\t\tnce = make_cache_entry(&the_index, ru->mode[i], ru->oid[i].hash,\n \t\t\t\t       name, i + 1, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349453","messageId":"20180606073933.14755-19-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 18/20] resolve-undo.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:31Z","receivedAt":"2018-06-06T07:40:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n resolve-undo.c | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex 9c45fe5d1d..a4918546c3 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"dir.h\"\n #include \"resolve-undo.h\"\n@@ -146,7 +147,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tstruct cache_entry *nce;\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n-\t\tnce = make_cache_entry(&the_index, ru->mode[i], ru->oid[i].hash,\n+\t\tnce = make_cache_entry(istate, ru->mode[i], ru->oid[i].hash,\n \t\t\t\t       name, i + 1, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n@@ -186,7 +187,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)\n \n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_path_match(&the_index, ce, pathspec, NULL))\n+\t\tif (!ce_path_match(istate, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\ti = unmerge_index_entry_at(istate, i);\n \t}\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349454","messageId":"20180606073933.14755-21-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 20/20] cache.h: make the_index part of \"compatibility macros\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:33Z","receivedAt":"2018-06-06T07:40:21Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"While the_index is not actually a macro, its use throughout the code\nbase is dangerous because developers sometimes may not see that some\nfunction is using the_index (instead of some other index that the devs\nare interested in).\n\nBy keeping the_index part of this NO_ macro, we try to reduce its use\nmore and more until it's completely gone.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 5939233eb7..242aaa5498 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -330,8 +330,6 @@ struct index_state {\n \tstruct ewah_bitmap *fsmonitor_dirty;\n };\n \n-extern struct index_state the_index;\n-\n /* Name hashing */\n extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);\n extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);\n@@ -340,6 +338,8 @@ extern void free_name_hash(struct index_state *istate);\n \n \n #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS\n+extern struct index_state the_index;\n+\n #define active_cache (the_index.cache)\n #define active_nr (the_index.cache_nr)\n #define active_alloc (the_index.cache_alloc)\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349455","messageId":"20180606073933.14755-17-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 16/20] preload-index.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:29Z","receivedAt":"2018-06-06T07:40:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n preload-index.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/preload-index.c b/preload-index.c\nindex d61d7662d5..cc2b579791 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -1,6 +1,7 @@\n /*\n  * Copyright (C) 2008 Linus Torvalds\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"pathspec.h\"\n #include \"dir.h\"\n@@ -58,7 +59,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce->ce_flags & CE_FSMONITOR_VALID)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(&the_index, ce, &p->pathspec, NULL))\n+\t\tif (!ce_path_match(index, ce, &p->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349456","messageId":"20180606073933.14755-13-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 12/20] pathspec.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:25Z","receivedAt":"2018-06-06T07:40:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 897cb9cbbe..6f005996fd 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -37,7 +37,7 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,\n \t\treturn;\n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tce_path_match(&the_index, ce, pathspec, seen);\n+\t\tce_path_match(istate, ce, pathspec, seen);\n \t}\n }\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349457","messageId":"20180606073933.14755-16-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 15/20] attr: remove index from git_attr_set_direction()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:28Z","receivedAt":"2018-06-06T07:40:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Since attr checking API now take the index, there's no need to set an\nindex in advance with this call. Most call sites are straightforward\nbecause they either pass the_index or NULL (which defaults back to\nthe_index previously). There's only one suspicious call site in\nunpack-trees.c where it sets a different index.\n\nThis code in unpack-trees is about to checking out entries from the\nnew/temporary index after merging is done in it. The attributes will\nbe used by entry.c code to do crlf conversion if needed. entry.c now\nrespects struct checkout's istate field, and this field is correctly\nset in unpack-trees.c, there should be no regression from this change.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c            |  2 +-\n attr.c               | 15 +++------------\n attr.h               |  3 +--\n builtin/check-attr.c |  2 +-\n unpack-trees.c       |  4 ++--\n 5 files changed, 8 insertions(+), 18 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 1b44503ebb..d1d0a0d6b3 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -273,7 +273,7 @@ int write_archive_entries(struct archiver_args *args,\n \t\tinit_tree_desc(&t, args->tree->buffer, args->tree->size);\n \t\tif (unpack_trees(1, &t, &opts))\n \t\t\treturn -1;\n-\t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n+\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n \t}\n \n \terr = read_tree_recursive(args->tree, \"\", 0, 0, &args->pathspec,\ndiff --git a/attr.c b/attr.c\nindex 863fad3bd1..98e4953f6e 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -708,10 +708,8 @@ static struct attr_stack *read_attr_from_array(const char **list)\n  * another thread could potentially be calling into the attribute system.\n  */\n static enum git_attr_direction direction;\n-static const struct index_state *use_index;\n \n-void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    const struct index_state *istate)\n+void git_attr_set_direction(enum git_attr_direction new_direction)\n {\n \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n@@ -720,7 +718,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction,\n \t\tdrop_all_attr_stacks();\n \n \tdirection = new_direction;\n-\tuse_index = istate;\n }\n \n static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n@@ -750,17 +747,11 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n \tstruct attr_stack *res;\n \tchar *buf, *sp;\n \tint lineno = 0;\n-\tconst struct index_state *to_read_from;\n \n-\t/*\n-\t * Temporary workaround for c24f3abace (apply: file commited\n-\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n-\t */\n-\tto_read_from = use_index ? use_index : istate;\n-\tif (!to_read_from)\n+\tif (!istate)\n \t\treturn NULL;\n \n-\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n+\tbuf = read_blob_data_from_index(istate, path, NULL);\n \tif (!buf)\n \t\treturn NULL;\n \ndiff --git a/attr.h b/attr.h\nindex 3daca3c0cb..01dab4a126 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -77,8 +77,7 @@ enum git_attr_direction {\n \tGIT_ATTR_CHECKOUT,\n \tGIT_ATTR_INDEX\n };\n-void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    const struct index_state *istate);\n+void git_attr_set_direction(enum git_attr_direction new_direction);\n \n void attr_start(void);\n \ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex f7b59993d3..c05573ff9c 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -120,7 +120,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (cached_attrs)\n-\t\tgit_attr_set_direction(GIT_ATTR_INDEX, NULL);\n+\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n \n \tdoubledash = -1;\n \tfor (i = 0; doubledash < 0 && i < argc; i++) {\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3ace82ca27..8cb407173e 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -361,7 +361,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tprogress = get_progress(o);\n \n \tif (o->update)\n-\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT, index);\n+\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\n \n \tif (should_update_submodules() && o->update && !o->dry_run)\n \t\tload_gitmodules_file(index, NULL);\n@@ -421,7 +421,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tstop_progress(&progress);\n \terrs |= finish_delayed_checkout(&state);\n \tif (o->update)\n-\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN, NULL);\n+\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN);\n \treturn errs != 0;\n }\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349458","messageId":"20180606073933.14755-9-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 08/20] convert.h: drop 'extern' from function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:21Z","receivedAt":"2018-06-06T07:40:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n convert.h | 56 ++++++++++++++++++++++++++++---------------------------\n 1 file changed, 29 insertions(+), 27 deletions(-)\n\ndiff --git a/convert.h b/convert.h\nindex 01385d9288..0a0fa15b58 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -57,35 +57,36 @@ struct delayed_checkout {\n \n extern enum eol core_eol;\n extern char *check_roundtrip_encoding;\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+const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t   const char *path);\n+const char *get_wt_convert_stats_ascii(const char *path);\n+const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\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, int conv_flags);\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 async_convert_to_working_tree(const char *path, const char *src,\n-\t\t\t\t\t size_t len, struct strbuf *dst,\n-\t\t\t\t\t void *dco);\n-extern int async_query_available_blobs(const char *cmd, struct string_list *available_paths);\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+int convert_to_git(const struct index_state *istate,\n+\t\t   const char *path, const char *src, size_t len,\n+\t\t   struct strbuf *dst, int conv_flags);\n+int convert_to_working_tree(const char *path, const char *src,\n+\t\t\t    size_t len, struct strbuf *dst);\n+int async_convert_to_working_tree(const char *path, const char *src,\n+\t\t\t\t  size_t len, struct strbuf *dst,\n+\t\t\t\t  void *dco);\n+int async_query_available_blobs(const char *cmd,\n+\t\t\t\tstruct string_list *available_paths);\n+int renormalize_buffer(const struct index_state *istate,\n+\t\t       const char *path, const char *src, size_t len,\n+\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)\n {\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,\n-\t\t\t\t     const char *path, int fd,\n-\t\t\t\t     struct strbuf *dst,\n-\t\t\t\t     int conv_flags);\n-extern int would_convert_to_git_filter_fd(const char *path);\n+void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t      const char *path, int fd,\n+\t\t\t      struct strbuf *dst,\n+\t\t\t      int conv_flags);\n+int would_convert_to_git_filter_fd(const char *path);\n \n /*****************************************************************\n  *\n@@ -95,9 +96,10 @@ extern int would_convert_to_git_filter_fd(const char *path);\n \n struct stream_filter; /* opaque */\n \n-extern struct stream_filter *get_stream_filter(const char *path, const struct object_id *);\n-extern void free_stream_filter(struct stream_filter *);\n-extern int is_null_stream_filter(struct stream_filter *);\n+struct stream_filter *get_stream_filter(const char *path,\n+\t\t\t\t\tconst struct object_id *);\n+void free_stream_filter(struct stream_filter *);\n+int is_null_stream_filter(struct stream_filter *);\n \n /*\n  * Use as much input up to *isize_p and fill output up to *osize_p;\n@@ -111,8 +113,8 @@ extern int is_null_stream_filter(struct stream_filter *);\n  * such filters know there is no more input coming and it is time for\n  * them to produce the remaining output based on the buffered input.\n  */\n-extern int stream_filter(struct stream_filter *,\n-\t\t\t const char *input, size_t *isize_p,\n-\t\t\t char *output, size_t *osize_p);\n+int stream_filter(struct stream_filter *,\n+\t\t  const char *input, size_t *isize_p,\n+\t\t  char *output, size_t *osize_p);\n \n #endif /* CONVERT_H */\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349459","messageId":"20180606073933.14755-14-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 13/20] submodule.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:26Z","receivedAt":"2018-06-06T07:40:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n submodule.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 955560bdbb..3aed76e3ee 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -93,7 +93,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)\n \tif (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */\n \t\treturn -1;\n \n-\tif (is_gitmodules_unmerged(&the_index))\n+\tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n \tsubmodule = submodule_from_path(the_repository, &null_oid, oldpath);\n@@ -127,7 +127,7 @@ int remove_path_from_gitmodules(const char *path)\n \tif (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */\n \t\treturn -1;\n \n-\tif (is_gitmodules_unmerged(&the_index))\n+\tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n \tsubmodule = submodule_from_path(the_repository, &null_oid, path);\n@@ -188,7 +188,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \n \t\tif (ignore)\n \t\t\thandle_ignore_submodules_arg(diffopt, ignore);\n-\t\telse if (is_gitmodules_unmerged(&the_index))\n+\t\telse if (is_gitmodules_unmerged(the_repository->index))\n \t\t\tdiffopt->flags.ignore_submodules = 1;\n \t}\n }\n@@ -258,7 +258,7 @@ int is_submodule_active(struct repository *repo, const char *path)\n \t\t}\n \n \t\tparse_pathspec(&ps, 0, 0, NULL, args.argv);\n-\t\tret = match_pathspec(&the_index, &ps, path, strlen(path), 0, NULL, 1);\n+\t\tret = match_pathspec(repo->index, &ps, path, strlen(path), 0, NULL, 1);\n \n \t\targv_array_clear(&args);\n \t\tclear_pathspec(&ps);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349460","messageId":"20180606073933.14755-7-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 06/20] attr.h: drop extern from function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:19Z","receivedAt":"2018-06-06T07:40:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n attr.h | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/attr.h b/attr.h\nindex 442d464db6..46340010bb 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -42,31 +42,31 @@ struct attr_check {\n \tstruct attr_stack *stack;\n };\n \n-extern struct attr_check *attr_check_alloc(void);\n-extern struct attr_check *attr_check_initl(const char *, ...);\n-extern struct attr_check *attr_check_dup(const struct attr_check *check);\n+struct attr_check *attr_check_alloc(void);\n+struct attr_check *attr_check_initl(const char *, ...);\n+struct attr_check *attr_check_dup(const struct attr_check *check);\n \n-extern struct attr_check_item *attr_check_append(struct attr_check *check,\n-\t\t\t\t\t\t const struct git_attr *attr);\n+struct attr_check_item *attr_check_append(struct attr_check *check,\n+\t\t\t\t\t  const struct git_attr *attr);\n \n-extern void attr_check_reset(struct attr_check *check);\n-extern void attr_check_clear(struct attr_check *check);\n-extern void attr_check_free(struct attr_check *check);\n+void attr_check_reset(struct attr_check *check);\n+void attr_check_clear(struct attr_check *check);\n+void attr_check_free(struct attr_check *check);\n \n /*\n  * Return the name of the attribute represented by the argument.  The\n  * return value is a pointer to a null-delimited string that is part\n  * of the internal data structure; it should not be modified or freed.\n  */\n-extern const char *git_attr_name(const struct git_attr *);\n+const char *git_attr_name(const struct git_attr *);\n \n-extern int git_check_attr(const char *path, struct attr_check *check);\n+int git_check_attr(const char *path, struct attr_check *check);\n \n /*\n  * Retrieve all attributes that apply to the specified path.\n  * check holds the attributes and their values.\n  */\n-extern void git_all_attrs(const char *path, struct attr_check *check);\n+void git_all_attrs(const char *path, struct attr_check *check);\n \n enum git_attr_direction {\n \tGIT_ATTR_CHECKIN,\n@@ -76,6 +76,6 @@ enum git_attr_direction {\n void git_attr_set_direction(enum git_attr_direction new_direction,\n \t\t\t    struct index_state *istate);\n \n-extern void attr_start(void);\n+void attr_start(void);\n \n #endif /* ATTR_H */\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349461","messageId":"20180606073933.14755-8-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v3 07/20] attr: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T07:39:20Z","receivedAt":"2018-06-06T07:40:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the attr API take an index_state instead of assuming the_index in\nattr code. All call sites are converted blindly to keep the patch\nsimple and retain current behavior. Individual call sites may receive\nfurther updates to use the right index instead of the_index.\n\nThere is one ugly temporary workaround added in attr.c that needs some\nmore explanation.\n\nCommit c24f3abace (apply: file commited * with CRLF should roundtrip\ndiff and apply - 2017-08-19) forces one convert_to_git() call to NOT\nread the index at all. But what do you know, we read it anyway by\nfalling back to the_index. When \"istate\" from convert_to_git is now\npropagated down to read_attr_from_array() we will hit segfault\nsomewhere inside read_blob_data_from_index.\n\nThe right way of dealing with this is to kill \"use_index\" variable and\nonly follow \"istate\" but at this stage we are not ready for that:\nwhile most git_attr_set_direction() calls just passes the_index to be\nassigned to use_index, unpack-trees passes a different one which is\nused by entry.c code, which has no way to know what index to use if we\ndelete use_index. So this has to be done later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c              |  2 +-\n attr.c                 | 57 ++++++++++++++++++++++++++++--------------\n attr.h                 | 10 +++++---\n builtin/check-attr.c   |  4 +--\n builtin/pack-objects.c |  2 +-\n convert.c              |  2 +-\n dir.c                  |  2 +-\n ll-merge.c             |  4 +--\n userdiff.c             |  2 +-\n ws.c                   |  2 +-\n 10 files changed, 55 insertions(+), 32 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 4fe7bec60c..3b4db8956a 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -108,7 +108,7 @@ static const struct attr_check *get_archive_attrs(const char *path)\n \tstatic struct attr_check *check;\n \tif (!check)\n \t\tcheck = attr_check_initl(\"export-ignore\", \"export-subst\", NULL);\n-\treturn git_check_attr(path, check) ? NULL : check;\n+\treturn git_check_attr(&the_index, path, check) ? NULL : check;\n }\n \n static int check_attr_export_ignore(const struct attr_check *check)\ndiff --git a/attr.c b/attr.c\nindex 067fb9e0c0..863fad3bd1 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -708,10 +708,10 @@ static struct attr_stack *read_attr_from_array(const char **list)\n  * another thread could potentially be calling into the attribute system.\n  */\n static enum git_attr_direction direction;\n-static struct index_state *use_index;\n+static const struct index_state *use_index;\n \n void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    struct index_state *istate)\n+\t\t\t    const struct index_state *istate)\n {\n \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n@@ -743,13 +743,24 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n \treturn res;\n }\n \n-static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n+static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n+\t\t\t\t\t       const char *path,\n+\t\t\t\t\t       int macro_ok)\n {\n \tstruct attr_stack *res;\n \tchar *buf, *sp;\n \tint lineno = 0;\n+\tconst struct index_state *to_read_from;\n \n-\tbuf = read_blob_data_from_index(use_index ? use_index : &the_index, path, NULL);\n+\t/*\n+\t * Temporary workaround for c24f3abace (apply: file commited\n+\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n+\t */\n+\tto_read_from = use_index ? use_index : istate;\n+\tif (!to_read_from)\n+\t\treturn NULL;\n+\n+\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n \tif (!buf)\n \t\treturn NULL;\n \n@@ -768,15 +779,16 @@ static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n \treturn res;\n }\n \n-static struct attr_stack *read_attr(const char *path, int macro_ok)\n+static struct attr_stack *read_attr(const struct index_state *istate,\n+\t\t\t\t    const char *path, int macro_ok)\n {\n \tstruct attr_stack *res = NULL;\n \n \tif (direction == GIT_ATTR_INDEX) {\n-\t\tres = read_attr_from_index(path, macro_ok);\n+\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t} else if (!is_bare_repository()) {\n \t\tif (direction == GIT_ATTR_CHECKOUT) {\n-\t\t\tres = read_attr_from_index(path, macro_ok);\n+\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t\t\tif (!res)\n \t\t\t\tres = read_attr_from_file(path, macro_ok);\n \t\t} else if (direction == GIT_ATTR_CHECKIN) {\n@@ -788,7 +800,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)\n \t\t\t\t * We allow operation in a sparsely checked out\n \t\t\t\t * work tree, so read from it.\n \t\t\t\t */\n-\t\t\t\tres = read_attr_from_index(path, macro_ok);\n+\t\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t\t}\n \t}\n \n@@ -859,7 +871,8 @@ static void push_stack(struct attr_stack **attr_stack_p,\n \t}\n }\n \n-static void bootstrap_attr_stack(struct attr_stack **stack)\n+static void bootstrap_attr_stack(const struct index_state *istate,\n+\t\t\t\t struct attr_stack **stack)\n {\n \tstruct attr_stack *e;\n \n@@ -883,7 +896,7 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n \t}\n \n \t/* root directory */\n-\te = read_attr(GITATTRIBUTES_FILE, 1);\n+\te = read_attr(istate, GITATTRIBUTES_FILE, 1);\n \tpush_stack(stack, e, xstrdup(\"\"), 0);\n \n \t/* info frame */\n@@ -896,7 +909,8 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n \tpush_stack(stack, e, NULL, 0);\n }\n \n-static void prepare_attr_stack(const char *path, int dirlen,\n+static void prepare_attr_stack(const struct index_state *istate,\n+\t\t\t       const char *path, int dirlen,\n \t\t\t       struct attr_stack **stack)\n {\n \tstruct attr_stack *info;\n@@ -917,7 +931,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n \t * .gitattributes in deeper directories to shallower ones,\n \t * and finally use the built-in set as the default.\n \t */\n-\tbootstrap_attr_stack(stack);\n+\tbootstrap_attr_stack(istate, stack);\n \n \t/*\n \t * Pop the \"info\" one that is always at the top of the stack.\n@@ -973,7 +987,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n \t\tstrbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));\n \t\tstrbuf_addf(&pathbuf, \"/%s\", GITATTRIBUTES_FILE);\n \n-\t\tnext = read_attr(pathbuf.buf, 0);\n+\t\tnext = read_attr(istate, pathbuf.buf, 0);\n \n \t\t/* reset the pathbuf to not include \"/.gitattributes\" */\n \t\tstrbuf_setlen(&pathbuf, len);\n@@ -1095,7 +1109,9 @@ static void determine_macros(struct all_attrs_item *all_attrs,\n  * If check->check_nr is non-zero, only attributes in check[] are collected.\n  * Otherwise all attributes are collected.\n  */\n-static void collect_some_attrs(const char *path, struct attr_check *check)\n+static void collect_some_attrs(const struct index_state *istate,\n+\t\t\t       const char *path,\n+\t\t\t       struct attr_check *check)\n {\n \tint i, pathlen, rem, dirlen;\n \tconst char *cp, *last_slash = NULL;\n@@ -1114,7 +1130,7 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n \t\tdirlen = 0;\n \t}\n \n-\tprepare_attr_stack(path, dirlen, &check->stack);\n+\tprepare_attr_stack(istate, path, dirlen, &check->stack);\n \tall_attrs_init(&g_attr_hashmap, check);\n \tdetermine_macros(check->all_attrs, check->stack);\n \n@@ -1136,11 +1152,13 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n \tfill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);\n }\n \n-int git_check_attr(const char *path, struct attr_check *check)\n+int git_check_attr(const struct index_state *istate,\n+\t\t   const char *path,\n+\t\t   struct attr_check *check)\n {\n \tint i;\n \n-\tcollect_some_attrs(path, check);\n+\tcollect_some_attrs(istate, path, check);\n \n \tfor (i = 0; i < check->nr; i++) {\n \t\tsize_t n = check->items[i].attr->attr_nr;\n@@ -1153,12 +1171,13 @@ int git_check_attr(const char *path, struct attr_check *check)\n \treturn 0;\n }\n \n-void git_all_attrs(const char *path, struct attr_check *check)\n+void git_all_attrs(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check)\n {\n \tint i;\n \n \tattr_check_reset(check);\n-\tcollect_some_attrs(path, check);\n+\tcollect_some_attrs(istate, path, check);\n \n \tfor (i = 0; i < check->all_attrs_nr; i++) {\n \t\tconst char *name = check->all_attrs[i].attr->name;\ndiff --git a/attr.h b/attr.h\nindex 46340010bb..3daca3c0cb 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -1,6 +1,8 @@\n #ifndef ATTR_H\n #define ATTR_H\n \n+struct index_state;\n+\n /* An attribute is a pointer to this opaque structure */\n struct git_attr;\n \n@@ -60,13 +62,15 @@ void attr_check_free(struct attr_check *check);\n  */\n const char *git_attr_name(const struct git_attr *);\n \n-int git_check_attr(const char *path, struct attr_check *check);\n+int git_check_attr(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check);\n \n /*\n  * Retrieve all attributes that apply to the specified path.\n  * check holds the attributes and their values.\n  */\n-void git_all_attrs(const char *path, struct attr_check *check);\n+void git_all_attrs(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check);\n \n enum git_attr_direction {\n \tGIT_ATTR_CHECKIN,\n@@ -74,7 +78,7 @@ enum git_attr_direction {\n \tGIT_ATTR_INDEX\n };\n void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    struct index_state *istate);\n+\t\t\t    const struct index_state *istate);\n \n void attr_start(void);\n \ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 91444dc044..f7b59993d3 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -63,9 +63,9 @@ static void check_attr(const char *prefix,\n \t\tprefix_path(prefix, prefix ? strlen(prefix) : 0, file);\n \n \tif (collect_all) {\n-\t\tgit_all_attrs(full_path, check);\n+\t\tgit_all_attrs(&the_index, full_path, check);\n \t} else {\n-\t\tif (git_check_attr(full_path, check))\n+\t\tif (git_check_attr(&the_index, full_path, check))\n \t\t\tdie(\"git_check_attr died\");\n \t}\n \toutput_attr(check, file);\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 71056d8294..0a2e801549 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -945,7 +945,7 @@ static int no_try_delta(const char *path)\n \n \tif (!check)\n \t\tcheck = attr_check_initl(\"delta\", NULL);\n-\tif (git_check_attr(path, check))\n+\tif (git_check_attr(&the_index, path, check))\n \t\treturn 0;\n \tif (ATTR_FALSE(check->items[0].value))\n \t\treturn 1;\ndiff --git a/convert.c b/convert.c\nindex 64d0d30e08..9d5dc32564 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1302,7 +1302,7 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tgit_config(read_convert_config, NULL);\n \t}\n \n-\tif (!git_check_attr(path, check)) {\n+\tif (!git_check_attr(&the_index, path, check)) {\n \t\tstruct attr_check_item *ccheck = check->items;\n \t\tca->crlf_action = git_path_check_crlf(ccheck + 4);\n \t\tif (ca->crlf_action == CRLF_UNDEFINED)\ndiff --git a/dir.c b/dir.c\nindex ccf8b4975e..a541be3032 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -280,7 +280,7 @@ static int match_attrs(const char *name, int namelen,\n {\n \tint i;\n \n-\tgit_check_attr(name, item->attr_check);\n+\tgit_check_attr(&the_index, name, item->attr_check);\n \tfor (i = 0; i < item->attr_match_nr; i++) {\n \t\tconst char *value;\n \t\tint matched;\ndiff --git a/ll-merge.c b/ll-merge.c\nindex a6ad2ec12d..0e2800f7bb 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -371,7 +371,7 @@ int ll_merge(mmbuffer_t *result_buf,\n \tif (!check)\n \t\tcheck = attr_check_initl(\"merge\", \"conflict-marker-size\", NULL);\n \n-\tif (!git_check_attr(path, check)) {\n+\tif (!git_check_attr(&the_index, path, check)) {\n \t\tll_driver_name = check->items[0].value;\n \t\tif (check->items[1].value) {\n \t\t\tmarker_size = atoi(check->items[1].value);\n@@ -398,7 +398,7 @@ int ll_merge_marker_size(const char *path)\n \n \tif (!check)\n \t\tcheck = attr_check_initl(\"conflict-marker-size\", NULL);\n-\tif (!git_check_attr(path, check) && check->items[0].value) {\n+\tif (!git_check_attr(&the_index, path, check) && check->items[0].value) {\n \t\tmarker_size = atoi(check->items[0].value);\n \t\tif (marker_size <= 0)\n \t\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\ndiff --git a/userdiff.c b/userdiff.c\nindex a69241b25d..e835e78dd5 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -278,7 +278,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path)\n \t\tcheck = attr_check_initl(\"diff\", NULL);\n \tif (!path)\n \t\treturn NULL;\n-\tif (git_check_attr(path, check))\n+\tif (git_check_attr(&the_index, path, check))\n \t\treturn NULL;\n \n \tif (ATTR_TRUE(check->items[0].value))\ndiff --git a/ws.c b/ws.c\nindex a07caedd5a..5b67b426e7 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -78,7 +78,7 @@ unsigned whitespace_rule(const char *pathname)\n \tif (!attr_whitespace_rule)\n \t\tattr_whitespace_rule = attr_check_initl(\"whitespace\", NULL);\n \n-\tif (!git_check_attr(pathname, attr_whitespace_rule)) {\n+\tif (!git_check_attr(&the_index, pathname, attr_whitespace_rule)) {\n \t\tconst char *value;\n \n \t\tvalue = attr_whitespace_rule->items[0].value;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349504","messageId":"62c2ef14-03c4-4602-0e50-242c9edd513f@ramsayjones.plus.com","threadId":"48624","inReplyTo":"20180606073933.14755-8-pclouds@gmail.com","subject":"Re: [PATCH v3 07/20] attr: remove an implicit dependency on the_index","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-06-06T13:35:01Z","receivedAt":"2018-06-06T13:35:07Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 06/06/18 08:39, Nguyễn Thái Ngọc Duy wrote:\n> Make the attr API take an index_state instead of assuming the_index in\n> attr code. All call sites are converted blindly to keep the patch\n> simple and retain current behavior. Individual call sites may receive\n> further updates to use the right index instead of the_index.\n> \n> There is one ugly temporary workaround added in attr.c that needs some\n> more explanation.\n> \n> Commit c24f3abace (apply: file commited * with CRLF should roundtrip\n\ns/commited * with/commited with/\n\nATB,\nRamsay Jones\n\n"},{"id":"349507","messageId":"20180606165016.3285-1-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606073933.14755-1-pclouds@gmail.com","subject":"[PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:53Z","receivedAt":"2018-06-06T16:50:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v4 fixes some commit messages and killed a couple more the_index\nreferences after I tried to merge this with 'pu'\n\ndiff --git a/apply.c b/apply.c\nindex 811ff2ad5e..82f681972f 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4090,9 +4090,9 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n \t\t\treturn error(_(\"sha1 information is lacking or useless \"\n \t\t\t\t       \"(%s).\"), name);\n \n-\t\tce = make_cache_entry(&the_index, patch->old_mode, oid.hash, name, 0, 0);\n+\t\tce = make_index_entry(&result, patch->old_mode, oid.hash, name, 0, 0);\n \t\tif (!ce)\n-\t\t\treturn error(_(\"make_cache_entry failed for path '%s'\"),\n+\t\t\treturn error(_(\"make_index_entry failed for path '%s'\"),\n \t\t\t\t     name);\n \t\tif (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {\n \t\t\tfree(ce);\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 3c8218304e..4dbcab3727 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -230,9 +230,9 @@ static int checkout_merged(int pos, const struct checkout *state)\n \tif (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n \tfree(result_buf.ptr);\n-\tce = make_cache_entry(&the_index, mode, oid.hash, path, 2, 0);\n+\tce = make_index_entry(state->istate, mode, oid.hash, path, 2, 0);\n \tif (!ce)\n-\t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n+\t\tdie(_(\"make_index_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\n \tfree(ce);\n \treturn status;\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex e34e75a42d..c7d6296762 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -321,7 +321,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(&the_index, mode, oid->hash, path, 0, 0);\n+\tce = make_index_entry(state->istate, mode, oid->hash, path, 0, 0);\n \tret = checkout_entry(ce, state, NULL);\n \n \tfree(ce);\n@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\t * index.\n \t\t\t\t */\n \t\t\t\tstruct cache_entry *ce2 =\n-\t\t\t\t\tmake_cache_entry(&the_index, rmode, roid.hash,\n+\t\t\t\t\tmake_index_entry(&wtindex, rmode, roid.hash,\n \t\t\t\t\t\t\t dst_path, 0, 0);\n \n \t\t\t\tadd_index_entry(&wtindex, ce2,\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 0ea0a19d5e..067f535031 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -134,10 +134,10 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tce = make_cache_entry(&the_index, one->mode, one->oid.hash, one->path,\n+\t\tce = make_index_entry(&the_index, one->mode, one->oid.hash, one->path,\n \t\t\t\t      0, 0);\n \t\tif (!ce)\n-\t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\n+\t\t\tdie(_(\"make_index_entry failed for path '%s'\"),\n \t\t\t    one->path);\n \t\tif (is_missing) {\n \t\t\tce->ce_flags |= CE_INTENT_TO_ADD;\ndiff --git a/cache.h b/cache.h\nindex 242aaa5498..eb8c79b8a1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -699,7 +699,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n \n-extern struct cache_entry *make_cache_entry(struct index_state *istate,unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n+extern struct cache_entry *make_index_entry(struct index_state *istate, unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 9280deb6a1..4f054d6dbb 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n+\tce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n \tif (!ce)\n \t\treturn err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex c083318aa7..4352aac521 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -745,7 +745,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \treturn add_to_index(istate, path, &st, flags);\n }\n \n-struct cache_entry *make_cache_entry(struct index_state *istate,\n+struct cache_entry *make_index_entry(struct index_state *istate,\n \t\t\t\t     unsigned int mode,\n \t\t\t\t     const unsigned char *sha1,\n \t\t\t\t     const char *path, int stage,\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex a4918546c3..2377995d6d 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -147,7 +147,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tstruct cache_entry *nce;\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n-\t\tnce = make_cache_entry(istate, ru->mode[i], ru->oid[i].hash,\n+\t\tnce = make_index_entry(istate, ru->mode[i], ru->oid[i].hash,\n \t\t\t\t       name, i + 1, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n\nNguyễn Thái Ngọc Duy (23):\n  unpack-trees: remove 'extern' on function declaration\n  unpack-trees: add a note about path invalidation\n  unpack-trees: don't shadow global var the_index\n  unpack-tress: convert clear_ce_flags* to avoid the_index\n  unpack-trees: avoid the_index in verify_absent()\n  attr.h: drop extern from function declaration\n  attr: remove an implicit dependency on the_index\n  convert.h: drop 'extern' from function declaration\n  convert.c: remove an implicit dependency on the_index\n  dir.c: remove an implicit dependency on the_index in pathspec code\n  ls-files: correct index argument to get_convert_attr_ascii()\n  pathspec.c: use the right index instead of the_index\n  submodule.c: use the right index instead of the_index\n  entry.c: use the right index instead of the_index\n  attr: remove index from git_attr_set_direction()\n  preload-index.c: use the right index instead of the_index\n  read-cache.c: remove an implicit dependency on the_index\n  apply.c: use the right index instead of the_index\n  difftool: use the right index instead of the_index\n  checkout: avoid the_index when possible\n  resolve-undo.c: use the right index instead of the_index\n  grep: use the right index instead of the_index\n  cache.h: make the_index part of \"compatibility macros\"\n\n apply.c                     |  6 ++--\n archive.c                   |  8 ++---\n attr.c                      | 52 ++++++++++++++++++-------------\n attr.h                      | 31 ++++++++++---------\n builtin/add.c               |  6 ++--\n builtin/cat-file.c          |  2 +-\n builtin/check-attr.c        |  6 ++--\n builtin/checkout-index.c    |  1 +\n builtin/checkout.c          |  6 ++--\n builtin/clean.c             |  2 +-\n builtin/commit.c            |  2 +-\n builtin/difftool.c          |  4 +--\n builtin/grep.c              |  6 ++--\n builtin/ls-files.c          | 17 ++++++-----\n builtin/pack-objects.c      |  2 +-\n builtin/reset.c             |  4 +--\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c |  2 +-\n builtin/update-index.c      |  2 +-\n cache.h                     |  9 +++---\n convert.c                   | 41 ++++++++++++++-----------\n convert.h                   | 61 +++++++++++++++++++++----------------\n diff-lib.c                  |  4 +--\n diff.c                      |  2 +-\n dir.c                       | 27 +++++++++-------\n dir.h                       | 16 ++++++----\n entry.c                     | 10 +++---\n ll-merge.c                  |  4 +--\n merge-recursive.c           |  4 +--\n pathspec.c                  |  2 +-\n preload-index.c             |  3 +-\n read-cache.c                | 19 +++++++-----\n rerere.c                    |  2 +-\n resolve-undo.c              |  5 +--\n revision.c                  |  2 +-\n sha1-file.c                 |  4 +--\n submodule.c                 |  8 ++---\n unpack-trees.c              | 57 +++++++++++++++++++++-------------\n unpack-trees.h              |  4 +--\n userdiff.c                  |  2 +-\n ws.c                        |  2 +-\n wt-status.c                 |  6 ++--\n 42 files changed, 258 insertions(+), 197 deletions(-)\n\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349508","messageId":"20180606165016.3285-2-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 01/23] unpack-trees: remove 'extern' on function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:54Z","receivedAt":"2018-06-06T16:50:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex c2b434c606..534358fcc5 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -82,8 +82,8 @@ struct unpack_trees_options {\n \tstruct exclude_list *el; /* for internal use */\n };\n \n-extern int unpack_trees(unsigned n, struct tree_desc *t,\n-\t\tstruct unpack_trees_options *options);\n+int unpack_trees(unsigned n, struct tree_desc *t,\n+\t\t struct unpack_trees_options *options);\n \n int verify_uptodate(const struct cache_entry *ce,\n \t\t    struct unpack_trees_options *o);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349509","messageId":"20180606165016.3285-3-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 02/23] unpack-trees: add a note about path invalidation","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:55Z","receivedAt":"2018-06-06T16:50:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3a85a02a77..5d06aa9c98 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1545,6 +1545,17 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);\n }\n \n+/*\n+ * TODO: We should actually invalidate o->result, not src_index [1].\n+ * But since cache tree and untracked cache both are not copied to\n+ * o->result until unpacking is complete, we invalidate them on\n+ * src_index instead with the assumption that they will be copied to\n+ * dst_index at the end.\n+ *\n+ * [1] src_index->cache_tree is also used in unpack_callback() so if\n+ * we invalidate o->result, we need to update it to use\n+ * o->result.cache_tree as well.\n+ */\n static void invalidate_ce_path(const struct cache_entry *ce,\n \t\t\t       struct unpack_trees_options *o)\n {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349510","messageId":"20180606165016.3285-5-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 04/23] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:57Z","receivedAt":"2018-06-06T16:50:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\nthe_index when running the exclude machinery. fba92be8f7 helps show\nthis problem clearer because unpack-trees operation is supposed to\nwork on whatever index the caller specifies... not specifically\nthe_index.\n\nUpdate the code to use \"istate\" argument that's originally from\nmark_new_skip_worktree(). From the call sites, both in unpack_trees(),\nyou can see that this function works on two separate indexes:\no->src_index and o->result. The second mark_new_skip_worktree() so far\nhas incorecctly applied exclude rules on o->src_index instead of\no->result. It's unclear what is the consequences of this, but it's\ndefinitely wrong.\n\n[1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n    2017-05-05)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 31 ++++++++++++++++++-------------\n 1 file changed, 18 insertions(+), 13 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 45fcda3169..5268de7af5 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1085,13 +1085,15 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str\n \treturn mask;\n }\n \n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval);\n \n /* Whole directory matching */\n-static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_dir(struct index_state *istate,\n+\t\t\t      struct cache_entry **cache, int nr,\n \t\t\t      struct strbuf *prefix,\n \t\t\t      char *basename,\n \t\t\t      int select_mask, int clear_mask,\n@@ -1100,7 +1102,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \tstruct cache_entry **cache_end;\n \tint dtype = DT_DIR;\n \tint ret = is_excluded_from_list(prefix->buf, prefix->len,\n-\t\t\t\t\tbasename, &dtype, el, &the_index);\n+\t\t\t\t\tbasename, &dtype, el, istate);\n \tint rc;\n \n \tstrbuf_addch(prefix, '/');\n@@ -1122,7 +1124,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n \t * calling clear_ce_flags_1(). That function will call\n \t * the expensive is_excluded_from_list() on every entry.\n \t */\n-\trc = clear_ce_flags_1(cache, cache_end - cache,\n+\trc = clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t      prefix,\n \t\t\t      select_mask, clear_mask,\n \t\t\t      el, ret);\n@@ -1145,7 +1147,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,\n  *   cache[0]->name[0..(prefix_len-1)]\n  * Top level path has prefix_len zero.\n  */\n-static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n+static int clear_ce_flags_1(struct index_state *istate,\n+\t\t\t    struct cache_entry **cache, int nr,\n \t\t\t    struct strbuf *prefix,\n \t\t\t    int select_mask, int clear_mask,\n \t\t\t    struct exclude_list *el, int defval)\n@@ -1179,7 +1182,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\tlen = slash - name;\n \t\t\tstrbuf_add(prefix, name, len);\n \n-\t\t\tprocessed = clear_ce_flags_dir(cache, cache_end - cache,\n+\t\t\tprocessed = clear_ce_flags_dir(istate, cache, cache_end - cache,\n \t\t\t\t\t\t       prefix,\n \t\t\t\t\t\t       prefix->buf + prefix->len - len,\n \t\t\t\t\t\t       select_mask, clear_mask,\n@@ -1193,7 +1196,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t\t}\n \n \t\t\tstrbuf_addch(prefix, '/');\n-\t\t\tcache += clear_ce_flags_1(cache, cache_end - cache,\n+\t\t\tcache += clear_ce_flags_1(istate, cache, cache_end - cache,\n \t\t\t\t\t\t  prefix,\n \t\t\t\t\t\t  select_mask, clear_mask, el, defval);\n \t\t\tstrbuf_setlen(prefix, prefix->len - len - 1);\n@@ -1203,7 +1206,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \t\t/* Non-directory */\n \t\tdtype = ce_to_dtype(ce);\n \t\tret = is_excluded_from_list(ce->name, ce_namelen(ce),\n-\t\t\t\t\t    name, &dtype, el, &the_index);\n+\t\t\t\t\t    name, &dtype, el, istate);\n \t\tif (ret < 0)\n \t\t\tret = defval;\n \t\tif (ret > 0)\n@@ -1213,15 +1216,17 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,\n \treturn nr - (cache_end - cache);\n }\n \n-static int clear_ce_flags(struct cache_entry **cache, int nr,\n-\t\t\t    int select_mask, int clear_mask,\n-\t\t\t    struct exclude_list *el)\n+static int clear_ce_flags(struct index_state *istate,\n+\t\t\t  int select_mask, int clear_mask,\n+\t\t\t  struct exclude_list *el)\n {\n \tstatic struct strbuf prefix = STRBUF_INIT;\n \n \tstrbuf_reset(&prefix);\n \n-\treturn clear_ce_flags_1(cache, nr,\n+\treturn clear_ce_flags_1(istate,\n+\t\t\t\tistate->cache,\n+\t\t\t\tistate->cache_nr,\n \t\t\t\t&prefix,\n \t\t\t\tselect_mask, clear_mask,\n \t\t\t\tel, 0);\n@@ -1256,7 +1261,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349511","messageId":"20180606165016.3285-4-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 03/23] unpack-trees: don't shadow global var the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:56Z","receivedAt":"2018-06-06T16:50:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function mark_new_skip_worktree() has an argument named the_index\nwhich is also the name of a global variable. While they have different\ntypes (the global the_index is not a pointer) mistakes can easily\nhappen and it's also confusing for readers. Rename the function\nargument to something other than the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5d06aa9c98..45fcda3169 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1231,7 +1231,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,\n  * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout\n  */\n static void mark_new_skip_worktree(struct exclude_list *el,\n-\t\t\t\t   struct index_state *the_index,\n+\t\t\t\t   struct index_state *istate,\n \t\t\t\t   int select_flag, int skip_wt_flag)\n {\n \tint i;\n@@ -1240,8 +1240,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 1. Pretend the narrowest worktree: only unmerged entries\n \t * are checked out\n \t */\n-\tfor (i = 0; i < the_index->cache_nr; i++) {\n-\t\tstruct cache_entry *ce = the_index->cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \n \t\tif (select_flag && !(ce->ce_flags & select_flag))\n \t\t\tcontinue;\n@@ -1256,8 +1256,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,\n \t * 2. Widen worktree according to sparse-checkout file.\n \t * Matched entries will have skip_wt_flag cleared (i.e. \"in\")\n \t */\n-\tclear_ce_flags(the_index->cache, the_index->cache_nr,\n-\t\t       select_flag, skip_wt_flag, el);\n+\tclear_ce_flags(istate->cache, istate->cache_nr, select_flag, skip_wt_flag, el);\n }\n \n static int verify_absent(const struct cache_entry *,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349512","messageId":"20180606165051.GH158365@google.com","threadId":"48624","inReplyTo":"20180606073933.14755-8-pclouds@gmail.com","subject":"Re: [PATCH v3 07/20] attr: remove an implicit dependency on the_index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-06T16:50:51Z","receivedAt":"2018-06-06T16:50:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/06, Nguyễn Thái Ngọc Duy wrote:\n> Make the attr API take an index_state instead of assuming the_index in\n> attr code. All call sites are converted blindly to keep the patch\n> simple and retain current behavior. Individual call sites may receive\n> further updates to use the right index instead of the_index.\n> \n> There is one ugly temporary workaround added in attr.c that needs some\n> more explanation.\n> \n> Commit c24f3abace (apply: file commited * with CRLF should roundtrip\n> diff and apply - 2017-08-19) forces one convert_to_git() call to NOT\n> read the index at all. But what do you know, we read it anyway by\n> falling back to the_index. When \"istate\" from convert_to_git is now\n> propagated down to read_attr_from_array() we will hit segfault\n> somewhere inside read_blob_data_from_index.\n> \n> The right way of dealing with this is to kill \"use_index\" variable and\n> only follow \"istate\" but at this stage we are not ready for that:\n> while most git_attr_set_direction() calls just passes the_index to be\n> assigned to use_index, unpack-trees passes a different one which is\n> used by entry.c code, which has no way to know what index to use if we\n> delete use_index. So this has to be done later.\n\nUgh I remember this when I was doing some refactoring to the attr\nsubsystem a year or so ago.  I really wanted to get rid of the whole\n\"direction\" thing because if I remember correctly its one of the only\nremaining globals that affects the outcome of an attr check (everything\nelse was converted to use the attr check struct.  I always got way to\nfar into the weeds when trying to do that too.  I'm not expecting that\nfrom this series (since its way out of scope) but maybe it'll be easier\nafterwards.\n\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  archive.c              |  2 +-\n>  attr.c                 | 57 ++++++++++++++++++++++++++++--------------\n>  attr.h                 | 10 +++++---\n>  builtin/check-attr.c   |  4 +--\n>  builtin/pack-objects.c |  2 +-\n>  convert.c              |  2 +-\n>  dir.c                  |  2 +-\n>  ll-merge.c             |  4 +--\n>  userdiff.c             |  2 +-\n>  ws.c                   |  2 +-\n>  10 files changed, 55 insertions(+), 32 deletions(-)\n> \n> diff --git a/archive.c b/archive.c\n> index 4fe7bec60c..3b4db8956a 100644\n> --- a/archive.c\n> +++ b/archive.c\n> @@ -108,7 +108,7 @@ static const struct attr_check *get_archive_attrs(const char *path)\n>  \tstatic struct attr_check *check;\n>  \tif (!check)\n>  \t\tcheck = attr_check_initl(\"export-ignore\", \"export-subst\", NULL);\n> -\treturn git_check_attr(path, check) ? NULL : check;\n> +\treturn git_check_attr(&the_index, path, check) ? NULL : check;\n>  }\n>  \n>  static int check_attr_export_ignore(const struct attr_check *check)\n> diff --git a/attr.c b/attr.c\n> index 067fb9e0c0..863fad3bd1 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -708,10 +708,10 @@ static struct attr_stack *read_attr_from_array(const char **list)\n>   * another thread could potentially be calling into the attribute system.\n>   */\n>  static enum git_attr_direction direction;\n> -static struct index_state *use_index;\n> +static const struct index_state *use_index;\n>  \n>  void git_attr_set_direction(enum git_attr_direction new_direction,\n> -\t\t\t    struct index_state *istate)\n> +\t\t\t    const struct index_state *istate)\n>  {\n>  \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n>  \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n> @@ -743,13 +743,24 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n>  \treturn res;\n>  }\n>  \n> -static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n> +static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n> +\t\t\t\t\t       const char *path,\n> +\t\t\t\t\t       int macro_ok)\n>  {\n>  \tstruct attr_stack *res;\n>  \tchar *buf, *sp;\n>  \tint lineno = 0;\n> +\tconst struct index_state *to_read_from;\n>  \n> -\tbuf = read_blob_data_from_index(use_index ? use_index : &the_index, path, NULL);\n> +\t/*\n> +\t * Temporary workaround for c24f3abace (apply: file commited\n> +\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n> +\t */\n> +\tto_read_from = use_index ? use_index : istate;\n> +\tif (!to_read_from)\n> +\t\treturn NULL;\n> +\n> +\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n>  \tif (!buf)\n>  \t\treturn NULL;\n>  \n> @@ -768,15 +779,16 @@ static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n>  \treturn res;\n>  }\n>  \n> -static struct attr_stack *read_attr(const char *path, int macro_ok)\n> +static struct attr_stack *read_attr(const struct index_state *istate,\n> +\t\t\t\t    const char *path, int macro_ok)\n>  {\n>  \tstruct attr_stack *res = NULL;\n>  \n>  \tif (direction == GIT_ATTR_INDEX) {\n> -\t\tres = read_attr_from_index(path, macro_ok);\n> +\t\tres = read_attr_from_index(istate, path, macro_ok);\n>  \t} else if (!is_bare_repository()) {\n>  \t\tif (direction == GIT_ATTR_CHECKOUT) {\n> -\t\t\tres = read_attr_from_index(path, macro_ok);\n> +\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n>  \t\t\tif (!res)\n>  \t\t\t\tres = read_attr_from_file(path, macro_ok);\n>  \t\t} else if (direction == GIT_ATTR_CHECKIN) {\n> @@ -788,7 +800,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)\n>  \t\t\t\t * We allow operation in a sparsely checked out\n>  \t\t\t\t * work tree, so read from it.\n>  \t\t\t\t */\n> -\t\t\t\tres = read_attr_from_index(path, macro_ok);\n> +\t\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n>  \t\t}\n>  \t}\n>  \n> @@ -859,7 +871,8 @@ static void push_stack(struct attr_stack **attr_stack_p,\n>  \t}\n>  }\n>  \n> -static void bootstrap_attr_stack(struct attr_stack **stack)\n> +static void bootstrap_attr_stack(const struct index_state *istate,\n> +\t\t\t\t struct attr_stack **stack)\n>  {\n>  \tstruct attr_stack *e;\n>  \n> @@ -883,7 +896,7 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n>  \t}\n>  \n>  \t/* root directory */\n> -\te = read_attr(GITATTRIBUTES_FILE, 1);\n> +\te = read_attr(istate, GITATTRIBUTES_FILE, 1);\n>  \tpush_stack(stack, e, xstrdup(\"\"), 0);\n>  \n>  \t/* info frame */\n> @@ -896,7 +909,8 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n>  \tpush_stack(stack, e, NULL, 0);\n>  }\n>  \n> -static void prepare_attr_stack(const char *path, int dirlen,\n> +static void prepare_attr_stack(const struct index_state *istate,\n> +\t\t\t       const char *path, int dirlen,\n>  \t\t\t       struct attr_stack **stack)\n>  {\n>  \tstruct attr_stack *info;\n> @@ -917,7 +931,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n>  \t * .gitattributes in deeper directories to shallower ones,\n>  \t * and finally use the built-in set as the default.\n>  \t */\n> -\tbootstrap_attr_stack(stack);\n> +\tbootstrap_attr_stack(istate, stack);\n>  \n>  \t/*\n>  \t * Pop the \"info\" one that is always at the top of the stack.\n> @@ -973,7 +987,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n>  \t\tstrbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));\n>  \t\tstrbuf_addf(&pathbuf, \"/%s\", GITATTRIBUTES_FILE);\n>  \n> -\t\tnext = read_attr(pathbuf.buf, 0);\n> +\t\tnext = read_attr(istate, pathbuf.buf, 0);\n>  \n>  \t\t/* reset the pathbuf to not include \"/.gitattributes\" */\n>  \t\tstrbuf_setlen(&pathbuf, len);\n> @@ -1095,7 +1109,9 @@ static void determine_macros(struct all_attrs_item *all_attrs,\n>   * If check->check_nr is non-zero, only attributes in check[] are collected.\n>   * Otherwise all attributes are collected.\n>   */\n> -static void collect_some_attrs(const char *path, struct attr_check *check)\n> +static void collect_some_attrs(const struct index_state *istate,\n> +\t\t\t       const char *path,\n> +\t\t\t       struct attr_check *check)\n>  {\n>  \tint i, pathlen, rem, dirlen;\n>  \tconst char *cp, *last_slash = NULL;\n> @@ -1114,7 +1130,7 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n>  \t\tdirlen = 0;\n>  \t}\n>  \n> -\tprepare_attr_stack(path, dirlen, &check->stack);\n> +\tprepare_attr_stack(istate, path, dirlen, &check->stack);\n>  \tall_attrs_init(&g_attr_hashmap, check);\n>  \tdetermine_macros(check->all_attrs, check->stack);\n>  \n> @@ -1136,11 +1152,13 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n>  \tfill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);\n>  }\n>  \n> -int git_check_attr(const char *path, struct attr_check *check)\n> +int git_check_attr(const struct index_state *istate,\n> +\t\t   const char *path,\n> +\t\t   struct attr_check *check)\n>  {\n>  \tint i;\n>  \n> -\tcollect_some_attrs(path, check);\n> +\tcollect_some_attrs(istate, path, check);\n>  \n>  \tfor (i = 0; i < check->nr; i++) {\n>  \t\tsize_t n = check->items[i].attr->attr_nr;\n> @@ -1153,12 +1171,13 @@ int git_check_attr(const char *path, struct attr_check *check)\n>  \treturn 0;\n>  }\n>  \n> -void git_all_attrs(const char *path, struct attr_check *check)\n> +void git_all_attrs(const struct index_state *istate,\n> +\t\t   const char *path, struct attr_check *check)\n>  {\n>  \tint i;\n>  \n>  \tattr_check_reset(check);\n> -\tcollect_some_attrs(path, check);\n> +\tcollect_some_attrs(istate, path, check);\n>  \n>  \tfor (i = 0; i < check->all_attrs_nr; i++) {\n>  \t\tconst char *name = check->all_attrs[i].attr->name;\n> diff --git a/attr.h b/attr.h\n> index 46340010bb..3daca3c0cb 100644\n> --- a/attr.h\n> +++ b/attr.h\n> @@ -1,6 +1,8 @@\n>  #ifndef ATTR_H\n>  #define ATTR_H\n>  \n> +struct index_state;\n> +\n>  /* An attribute is a pointer to this opaque structure */\n>  struct git_attr;\n>  \n> @@ -60,13 +62,15 @@ void attr_check_free(struct attr_check *check);\n>   */\n>  const char *git_attr_name(const struct git_attr *);\n>  \n> -int git_check_attr(const char *path, struct attr_check *check);\n> +int git_check_attr(const struct index_state *istate,\n> +\t\t   const char *path, struct attr_check *check);\n>  \n>  /*\n>   * Retrieve all attributes that apply to the specified path.\n>   * check holds the attributes and their values.\n>   */\n> -void git_all_attrs(const char *path, struct attr_check *check);\n> +void git_all_attrs(const struct index_state *istate,\n> +\t\t   const char *path, struct attr_check *check);\n>  \n>  enum git_attr_direction {\n>  \tGIT_ATTR_CHECKIN,\n> @@ -74,7 +78,7 @@ enum git_attr_direction {\n>  \tGIT_ATTR_INDEX\n>  };\n>  void git_attr_set_direction(enum git_attr_direction new_direction,\n> -\t\t\t    struct index_state *istate);\n> +\t\t\t    const struct index_state *istate);\n>  \n>  void attr_start(void);\n>  \n> diff --git a/builtin/check-attr.c b/builtin/check-attr.c\n> index 91444dc044..f7b59993d3 100644\n> --- a/builtin/check-attr.c\n> +++ b/builtin/check-attr.c\n> @@ -63,9 +63,9 @@ static void check_attr(const char *prefix,\n>  \t\tprefix_path(prefix, prefix ? strlen(prefix) : 0, file);\n>  \n>  \tif (collect_all) {\n> -\t\tgit_all_attrs(full_path, check);\n> +\t\tgit_all_attrs(&the_index, full_path, check);\n>  \t} else {\n> -\t\tif (git_check_attr(full_path, check))\n> +\t\tif (git_check_attr(&the_index, full_path, check))\n>  \t\t\tdie(\"git_check_attr died\");\n>  \t}\n>  \toutput_attr(check, file);\n> diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n> index 71056d8294..0a2e801549 100644\n> --- a/builtin/pack-objects.c\n> +++ b/builtin/pack-objects.c\n> @@ -945,7 +945,7 @@ static int no_try_delta(const char *path)\n>  \n>  \tif (!check)\n>  \t\tcheck = attr_check_initl(\"delta\", NULL);\n> -\tif (git_check_attr(path, check))\n> +\tif (git_check_attr(&the_index, path, check))\n>  \t\treturn 0;\n>  \tif (ATTR_FALSE(check->items[0].value))\n>  \t\treturn 1;\n> diff --git a/convert.c b/convert.c\n> index 64d0d30e08..9d5dc32564 100644\n> --- a/convert.c\n> +++ b/convert.c\n> @@ -1302,7 +1302,7 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n>  \t\tgit_config(read_convert_config, NULL);\n>  \t}\n>  \n> -\tif (!git_check_attr(path, check)) {\n> +\tif (!git_check_attr(&the_index, path, check)) {\n>  \t\tstruct attr_check_item *ccheck = check->items;\n>  \t\tca->crlf_action = git_path_check_crlf(ccheck + 4);\n>  \t\tif (ca->crlf_action == CRLF_UNDEFINED)\n> diff --git a/dir.c b/dir.c\n> index ccf8b4975e..a541be3032 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -280,7 +280,7 @@ static int match_attrs(const char *name, int namelen,\n>  {\n>  \tint i;\n>  \n> -\tgit_check_attr(name, item->attr_check);\n> +\tgit_check_attr(&the_index, name, item->attr_check);\n>  \tfor (i = 0; i < item->attr_match_nr; i++) {\n>  \t\tconst char *value;\n>  \t\tint matched;\n> diff --git a/ll-merge.c b/ll-merge.c\n> index a6ad2ec12d..0e2800f7bb 100644\n> --- a/ll-merge.c\n> +++ b/ll-merge.c\n> @@ -371,7 +371,7 @@ int ll_merge(mmbuffer_t *result_buf,\n>  \tif (!check)\n>  \t\tcheck = attr_check_initl(\"merge\", \"conflict-marker-size\", NULL);\n>  \n> -\tif (!git_check_attr(path, check)) {\n> +\tif (!git_check_attr(&the_index, path, check)) {\n>  \t\tll_driver_name = check->items[0].value;\n>  \t\tif (check->items[1].value) {\n>  \t\t\tmarker_size = atoi(check->items[1].value);\n> @@ -398,7 +398,7 @@ int ll_merge_marker_size(const char *path)\n>  \n>  \tif (!check)\n>  \t\tcheck = attr_check_initl(\"conflict-marker-size\", NULL);\n> -\tif (!git_check_attr(path, check) && check->items[0].value) {\n> +\tif (!git_check_attr(&the_index, path, check) && check->items[0].value) {\n>  \t\tmarker_size = atoi(check->items[0].value);\n>  \t\tif (marker_size <= 0)\n>  \t\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n> diff --git a/userdiff.c b/userdiff.c\n> index a69241b25d..e835e78dd5 100644\n> --- a/userdiff.c\n> +++ b/userdiff.c\n> @@ -278,7 +278,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path)\n>  \t\tcheck = attr_check_initl(\"diff\", NULL);\n>  \tif (!path)\n>  \t\treturn NULL;\n> -\tif (git_check_attr(path, check))\n> +\tif (git_check_attr(&the_index, path, check))\n>  \t\treturn NULL;\n>  \n>  \tif (ATTR_TRUE(check->items[0].value))\n> diff --git a/ws.c b/ws.c\n> index a07caedd5a..5b67b426e7 100644\n> --- a/ws.c\n> +++ b/ws.c\n> @@ -78,7 +78,7 @@ unsigned whitespace_rule(const char *pathname)\n>  \tif (!attr_whitespace_rule)\n>  \t\tattr_whitespace_rule = attr_check_initl(\"whitespace\", NULL);\n>  \n> -\tif (!git_check_attr(pathname, attr_whitespace_rule)) {\n> +\tif (!git_check_attr(&the_index, pathname, attr_whitespace_rule)) {\n>  \t\tconst char *value;\n>  \n>  \t\tvalue = attr_whitespace_rule->items[0].value;\n> -- \n> 2.18.0.rc0.333.g22e6ee6cdf\n> \n\n-- \nBrandon Williams\n"},{"id":"349513","messageId":"20180606165016.3285-6-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 05/23] unpack-trees: avoid the_index in verify_absent()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:49:58Z","receivedAt":"2018-06-06T16:51:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Both functions that are updated in this commit are called by\nverify_absent(), which is part of the \"unpack-trees\" operation that is\nsupposed to work on any index file specified by the caller. Thanks to\nBrandon [1] [2], an implicit dependency on the_index is exposed. This\ncommit fixes it.\n\nIn both functions, it makes sense to use src_index to check for\nexclusion because it's almost unchanged and should give us the same\noutcome as if running the exclude check before the unpack.\n\nIt's \"almost unchanged\" because we do invalidate cache-tree and\nuntracked cache in the source index. But this should not affect how\nexclude machinery uses the index: to see if a file is tracked, and to\nread a blob from the index instead of worktree if it's marked\nskip-worktree (i.e. it's not available in worktree)\n\n[1] a0bba65b10 (dir: convert is_excluded to take an index - 2017-05-05\n[2] 2c1eb10454 (dir: convert read_directory to take an index - 2017-05-05)\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n unpack-trees.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 5268de7af5..3ace82ca27 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1651,7 +1651,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \tmemset(&d, 0, sizeof(d));\n \tif (o->dir)\n \t\td.exclude_per_dir = o->dir->exclude_per_dir;\n-\ti = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);\n+\ti = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);\n \tif (i)\n \t\treturn o->gently ? -1 :\n \t\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);\n@@ -1693,7 +1693,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\treturn 0;\n \n \tif (o->dir &&\n-\t    is_excluded(o->dir, &the_index, name, &dtype))\n+\t    is_excluded(o->dir, o->src_index, name, &dtype))\n \t\t/*\n \t\t * ce->name is explicitly excluded, so it is Ok to\n \t\t * overwrite it.\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349514","messageId":"20180606165830.GI158365@google.com","threadId":"48624","inReplyTo":"20180606073933.14755-16-pclouds@gmail.com","subject":"Re: [PATCH v3 15/20] attr: remove index from git_attr_set_direction()","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-06T16:58:30Z","receivedAt":"2018-06-06T16:58:36Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/06, Nguyễn Thái Ngọc Duy wrote:\n> Since attr checking API now take the index, there's no need to set an\n> index in advance with this call. Most call sites are straightforward\n> because they either pass the_index or NULL (which defaults back to\n> the_index previously). There's only one suspicious call site in\n> unpack-trees.c where it sets a different index.\n> \n> This code in unpack-trees is about to checking out entries from the\n> new/temporary index after merging is done in it. The attributes will\n> be used by entry.c code to do crlf conversion if needed. entry.c now\n> respects struct checkout's istate field, and this field is correctly\n> set in unpack-trees.c, there should be no regression from this change.\n\nNice! Much cleaner.\n\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  archive.c            |  2 +-\n>  attr.c               | 15 +++------------\n>  attr.h               |  3 +--\n>  builtin/check-attr.c |  2 +-\n>  unpack-trees.c       |  4 ++--\n>  5 files changed, 8 insertions(+), 18 deletions(-)\n> \n> diff --git a/archive.c b/archive.c\n> index 1b44503ebb..d1d0a0d6b3 100644\n> --- a/archive.c\n> +++ b/archive.c\n> @@ -273,7 +273,7 @@ int write_archive_entries(struct archiver_args *args,\n>  \t\tinit_tree_desc(&t, args->tree->buffer, args->tree->size);\n>  \t\tif (unpack_trees(1, &t, &opts))\n>  \t\t\treturn -1;\n> -\t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n> +\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n>  \t}\n>  \n>  \terr = read_tree_recursive(args->tree, \"\", 0, 0, &args->pathspec,\n> diff --git a/attr.c b/attr.c\n> index 863fad3bd1..98e4953f6e 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -708,10 +708,8 @@ static struct attr_stack *read_attr_from_array(const char **list)\n>   * another thread could potentially be calling into the attribute system.\n>   */\n>  static enum git_attr_direction direction;\n> -static const struct index_state *use_index;\n>  \n> -void git_attr_set_direction(enum git_attr_direction new_direction,\n> -\t\t\t    const struct index_state *istate)\n> +void git_attr_set_direction(enum git_attr_direction new_direction)\n>  {\n>  \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n>  \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n> @@ -720,7 +718,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction,\n>  \t\tdrop_all_attr_stacks();\n>  \n>  \tdirection = new_direction;\n> -\tuse_index = istate;\n>  }\n>  \n>  static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n> @@ -750,17 +747,11 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n>  \tstruct attr_stack *res;\n>  \tchar *buf, *sp;\n>  \tint lineno = 0;\n> -\tconst struct index_state *to_read_from;\n>  \n> -\t/*\n> -\t * Temporary workaround for c24f3abace (apply: file commited\n> -\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n> -\t */\n> -\tto_read_from = use_index ? use_index : istate;\n> -\tif (!to_read_from)\n> +\tif (!istate)\n>  \t\treturn NULL;\n>  \n> -\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n> +\tbuf = read_blob_data_from_index(istate, path, NULL);\n>  \tif (!buf)\n>  \t\treturn NULL;\n>  \n> diff --git a/attr.h b/attr.h\n> index 3daca3c0cb..01dab4a126 100644\n> --- a/attr.h\n> +++ b/attr.h\n> @@ -77,8 +77,7 @@ enum git_attr_direction {\n>  \tGIT_ATTR_CHECKOUT,\n>  \tGIT_ATTR_INDEX\n>  };\n> -void git_attr_set_direction(enum git_attr_direction new_direction,\n> -\t\t\t    const struct index_state *istate);\n> +void git_attr_set_direction(enum git_attr_direction new_direction);\n>  \n>  void attr_start(void);\n>  \n> diff --git a/builtin/check-attr.c b/builtin/check-attr.c\n> index f7b59993d3..c05573ff9c 100644\n> --- a/builtin/check-attr.c\n> +++ b/builtin/check-attr.c\n> @@ -120,7 +120,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)\n>  \t}\n>  \n>  \tif (cached_attrs)\n> -\t\tgit_attr_set_direction(GIT_ATTR_INDEX, NULL);\n> +\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n>  \n>  \tdoubledash = -1;\n>  \tfor (i = 0; doubledash < 0 && i < argc; i++) {\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 3ace82ca27..8cb407173e 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -361,7 +361,7 @@ static int check_updates(struct unpack_trees_options *o)\n>  \tprogress = get_progress(o);\n>  \n>  \tif (o->update)\n> -\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT, index);\n> +\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\n>  \n>  \tif (should_update_submodules() && o->update && !o->dry_run)\n>  \t\tload_gitmodules_file(index, NULL);\n> @@ -421,7 +421,7 @@ static int check_updates(struct unpack_trees_options *o)\n>  \tstop_progress(&progress);\n>  \terrs |= finish_delayed_checkout(&state);\n>  \tif (o->update)\n> -\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN, NULL);\n> +\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN);\n>  \treturn errs != 0;\n>  }\n>  \n> -- \n> 2.18.0.rc0.333.g22e6ee6cdf\n> \n\n-- \nBrandon Williams\n"},{"id":"349515","messageId":"CACsJy8AZdOQGimhg00ZGwv=ESquDaLae_poj1Au_hE5kaW8ksg@mail.gmail.com","threadId":"48624","inReplyTo":"20180606165051.GH158365@google.com","subject":"Re: [PATCH v3 07/20] attr: remove an implicit dependency on the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T16:58:52Z","receivedAt":"2018-06-06T16:59:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jun 6, 2018 at 6:50 PM, Brandon Williams <bmwill@google.com> wrote:\n> On 06/06, Nguyễn Thái Ngọc Duy wrote:\n>> Make the attr API take an index_state instead of assuming the_index in\n>> attr code. All call sites are converted blindly to keep the patch\n>> simple and retain current behavior. Individual call sites may receive\n>> further updates to use the right index instead of the_index.\n>>\n>> There is one ugly temporary workaround added in attr.c that needs some\n>> more explanation.\n>>\n>> Commit c24f3abace (apply: file commited * with CRLF should roundtrip\n>> diff and apply - 2017-08-19) forces one convert_to_git() call to NOT\n>> read the index at all. But what do you know, we read it anyway by\n>> falling back to the_index. When \"istate\" from convert_to_git is now\n>> propagated down to read_attr_from_array() we will hit segfault\n>> somewhere inside read_blob_data_from_index.\n>>\n>> The right way of dealing with this is to kill \"use_index\" variable and\n>> only follow \"istate\" but at this stage we are not ready for that:\n>> while most git_attr_set_direction() calls just passes the_index to be\n>> assigned to use_index, unpack-trees passes a different one which is\n>> used by entry.c code, which has no way to know what index to use if we\n>> delete use_index. So this has to be done later.\n>\n> Ugh I remember this when I was doing some refactoring to the attr\n> subsystem a year or so ago.  I really wanted to get rid of the whole\n> \"direction\" thing because if I remember correctly its one of the only\n> remaining globals that affects the outcome of an attr check (everything\n> else was converted to use the attr check struct.  I always got way to\n> far into the weeds when trying to do that too.  I'm not expecting that\n> from this series (since its way out of scope) but maybe it'll be easier\n> afterwards.\n\nIt's not that much easier. This direction thing is still global by\ndesign. It would be great if we have something like Scheme's parameter\n(aka. dynamic scoping iirc) then we can still scope this nicely. Git\ndoes not live in such worlds.\n-- \nDuy\n"},{"id":"349516","messageId":"20180606170254.GK158365@google.com","threadId":"48624","inReplyTo":"CACsJy8AZdOQGimhg00ZGwv=ESquDaLae_poj1Au_hE5kaW8ksg@mail.gmail.com","subject":"Re: [PATCH v3 07/20] attr: remove an implicit dependency on the_index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-06T17:02:54Z","receivedAt":"2018-06-06T17:03:00Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/06, Duy Nguyen wrote:\n> On Wed, Jun 6, 2018 at 6:50 PM, Brandon Williams <bmwill@google.com> wrote:\n> > On 06/06, Nguyễn Thái Ngọc Duy wrote:\n> >> Make the attr API take an index_state instead of assuming the_index in\n> >> attr code. All call sites are converted blindly to keep the patch\n> >> simple and retain current behavior. Individual call sites may receive\n> >> further updates to use the right index instead of the_index.\n> >>\n> >> There is one ugly temporary workaround added in attr.c that needs some\n> >> more explanation.\n> >>\n> >> Commit c24f3abace (apply: file commited * with CRLF should roundtrip\n> >> diff and apply - 2017-08-19) forces one convert_to_git() call to NOT\n> >> read the index at all. But what do you know, we read it anyway by\n> >> falling back to the_index. When \"istate\" from convert_to_git is now\n> >> propagated down to read_attr_from_array() we will hit segfault\n> >> somewhere inside read_blob_data_from_index.\n> >>\n> >> The right way of dealing with this is to kill \"use_index\" variable and\n> >> only follow \"istate\" but at this stage we are not ready for that:\n> >> while most git_attr_set_direction() calls just passes the_index to be\n> >> assigned to use_index, unpack-trees passes a different one which is\n> >> used by entry.c code, which has no way to know what index to use if we\n> >> delete use_index. So this has to be done later.\n> >\n> > Ugh I remember this when I was doing some refactoring to the attr\n> > subsystem a year or so ago.  I really wanted to get rid of the whole\n> > \"direction\" thing because if I remember correctly its one of the only\n> > remaining globals that affects the outcome of an attr check (everything\n> > else was converted to use the attr check struct.  I always got way to\n> > far into the weeds when trying to do that too.  I'm not expecting that\n> > from this series (since its way out of scope) but maybe it'll be easier\n> > afterwards.\n> \n> It's not that much easier. This direction thing is still global by\n> design. It would be great if we have something like Scheme's parameter\n> (aka. dynamic scoping iirc) then we can still scope this nicely. Git\n> does not live in such worlds.\n\nYeah i realized this after sending.  Either way thanks for simplifying\nthe global state by getting ride of the index global.\n\n> -- \n> Duy\n\n-- \nBrandon Williams\n"},{"id":"349517","messageId":"20180606170243.4169-1-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"[PATCH v4 06/23] attr.h: drop extern from function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:26Z","receivedAt":"2018-06-06T17:03:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n attr.h | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/attr.h b/attr.h\nindex 442d464db6..46340010bb 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -42,31 +42,31 @@ struct attr_check {\n \tstruct attr_stack *stack;\n };\n \n-extern struct attr_check *attr_check_alloc(void);\n-extern struct attr_check *attr_check_initl(const char *, ...);\n-extern struct attr_check *attr_check_dup(const struct attr_check *check);\n+struct attr_check *attr_check_alloc(void);\n+struct attr_check *attr_check_initl(const char *, ...);\n+struct attr_check *attr_check_dup(const struct attr_check *check);\n \n-extern struct attr_check_item *attr_check_append(struct attr_check *check,\n-\t\t\t\t\t\t const struct git_attr *attr);\n+struct attr_check_item *attr_check_append(struct attr_check *check,\n+\t\t\t\t\t  const struct git_attr *attr);\n \n-extern void attr_check_reset(struct attr_check *check);\n-extern void attr_check_clear(struct attr_check *check);\n-extern void attr_check_free(struct attr_check *check);\n+void attr_check_reset(struct attr_check *check);\n+void attr_check_clear(struct attr_check *check);\n+void attr_check_free(struct attr_check *check);\n \n /*\n  * Return the name of the attribute represented by the argument.  The\n  * return value is a pointer to a null-delimited string that is part\n  * of the internal data structure; it should not be modified or freed.\n  */\n-extern const char *git_attr_name(const struct git_attr *);\n+const char *git_attr_name(const struct git_attr *);\n \n-extern int git_check_attr(const char *path, struct attr_check *check);\n+int git_check_attr(const char *path, struct attr_check *check);\n \n /*\n  * Retrieve all attributes that apply to the specified path.\n  * check holds the attributes and their values.\n  */\n-extern void git_all_attrs(const char *path, struct attr_check *check);\n+void git_all_attrs(const char *path, struct attr_check *check);\n \n enum git_attr_direction {\n \tGIT_ATTR_CHECKIN,\n@@ -76,6 +76,6 @@ enum git_attr_direction {\n void git_attr_set_direction(enum git_attr_direction new_direction,\n \t\t\t    struct index_state *istate);\n \n-extern void attr_start(void);\n+void attr_start(void);\n \n #endif /* ATTR_H */\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349518","messageId":"20180606170243.4169-3-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 08/23] convert.h: drop 'extern' from function declaration","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:28Z","receivedAt":"2018-06-06T17:03:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n convert.h | 56 ++++++++++++++++++++++++++++---------------------------\n 1 file changed, 29 insertions(+), 27 deletions(-)\n\ndiff --git a/convert.h b/convert.h\nindex 01385d9288..0a0fa15b58 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -57,35 +57,36 @@ struct delayed_checkout {\n \n extern enum eol core_eol;\n extern char *check_roundtrip_encoding;\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+const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n+\t\t\t\t\t   const char *path);\n+const char *get_wt_convert_stats_ascii(const char *path);\n+const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\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, int conv_flags);\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 async_convert_to_working_tree(const char *path, const char *src,\n-\t\t\t\t\t size_t len, struct strbuf *dst,\n-\t\t\t\t\t void *dco);\n-extern int async_query_available_blobs(const char *cmd, struct string_list *available_paths);\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+int convert_to_git(const struct index_state *istate,\n+\t\t   const char *path, const char *src, size_t len,\n+\t\t   struct strbuf *dst, int conv_flags);\n+int convert_to_working_tree(const char *path, const char *src,\n+\t\t\t    size_t len, struct strbuf *dst);\n+int async_convert_to_working_tree(const char *path, const char *src,\n+\t\t\t\t  size_t len, struct strbuf *dst,\n+\t\t\t\t  void *dco);\n+int async_query_available_blobs(const char *cmd,\n+\t\t\t\tstruct string_list *available_paths);\n+int renormalize_buffer(const struct index_state *istate,\n+\t\t       const char *path, const char *src, size_t len,\n+\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)\n {\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,\n-\t\t\t\t     const char *path, int fd,\n-\t\t\t\t     struct strbuf *dst,\n-\t\t\t\t     int conv_flags);\n-extern int would_convert_to_git_filter_fd(const char *path);\n+void convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t      const char *path, int fd,\n+\t\t\t      struct strbuf *dst,\n+\t\t\t      int conv_flags);\n+int would_convert_to_git_filter_fd(const char *path);\n \n /*****************************************************************\n  *\n@@ -95,9 +96,10 @@ extern int would_convert_to_git_filter_fd(const char *path);\n \n struct stream_filter; /* opaque */\n \n-extern struct stream_filter *get_stream_filter(const char *path, const struct object_id *);\n-extern void free_stream_filter(struct stream_filter *);\n-extern int is_null_stream_filter(struct stream_filter *);\n+struct stream_filter *get_stream_filter(const char *path,\n+\t\t\t\t\tconst struct object_id *);\n+void free_stream_filter(struct stream_filter *);\n+int is_null_stream_filter(struct stream_filter *);\n \n /*\n  * Use as much input up to *isize_p and fill output up to *osize_p;\n@@ -111,8 +113,8 @@ extern int is_null_stream_filter(struct stream_filter *);\n  * such filters know there is no more input coming and it is time for\n  * them to produce the remaining output based on the buffered input.\n  */\n-extern int stream_filter(struct stream_filter *,\n-\t\t\t const char *input, size_t *isize_p,\n-\t\t\t char *output, size_t *osize_p);\n+int stream_filter(struct stream_filter *,\n+\t\t  const char *input, size_t *isize_p,\n+\t\t  char *output, size_t *osize_p);\n \n #endif /* CONVERT_H */\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349519","messageId":"20180606170243.4169-4-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 09/23] convert.c: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:29Z","receivedAt":"2018-06-06T17:03:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the convert API take an index_state instead of assuming the_index\nin convert.c. All external call sites are converted blindly to keep\nthe patch simple and retain current behavior. Individual call sites\nmay receive further updates to use the right index instead of\nthe_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n apply.c            |  2 +-\n archive.c          |  2 +-\n builtin/cat-file.c |  2 +-\n builtin/ls-files.c |  2 +-\n convert.c          | 41 ++++++++++++++++++++++++-----------------\n convert.h          | 15 ++++++++++-----\n diff.c             |  2 +-\n entry.c            |  6 +++---\n merge-recursive.c  |  2 +-\n sha1-file.c        |  4 ++--\n 10 files changed, 45 insertions(+), 33 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex d79e61591b..9720855590 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4333,7 +4333,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,\n \tif (fd < 0)\n \t\treturn 1;\n \n-\tif (convert_to_working_tree(path, buf, size, &nbuf)) {\n+\tif (convert_to_working_tree(&the_index, path, buf, size, &nbuf)) {\n \t\tsize = nbuf.len;\n \t\tbuf  = nbuf.buf;\n \t}\ndiff --git a/archive.c b/archive.c\nindex 3b4db8956a..f3631a4fb5 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -78,7 +78,7 @@ void *object_file_to_archive(const struct archiver_args *args,\n \t\tsize_t size = 0;\n \n \t\tstrbuf_attach(&buf, buffer, *sizep, *sizep + 1);\n-\t\tconvert_to_working_tree(path, buf.buf, buf.len, &buf);\n+\t\tconvert_to_working_tree(&the_index, path, buf.buf, buf.len, &buf);\n \t\tif (commit)\n \t\t\tformat_subst(commit, buf.buf, buf.len, &buf);\n \t\tbuffer = strbuf_detach(&buf, &size);\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 665b581949..a615a0048b 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -38,7 +38,7 @@ static int filter_object(const char *path, unsigned mode,\n \t\t\t     oid_to_hex(oid), path);\n \tif ((type == OBJ_BLOB) && S_ISREG(mode)) {\n \t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n+\t\tif (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) {\n \t\t\tfree(*buf);\n \t\t\t*size = strbuf.len;\n \t\t\t*buf = strbuf_detach(&strbuf, NULL);\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 88bb2019ad..d996734b45 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate,\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\tconst char *a_txt = get_convert_attr_ascii(&the_index, path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n \t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\ndiff --git a/convert.c b/convert.c\nindex 9d5dc32564..2b1a87a104 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1290,7 +1290,8 @@ struct conv_attrs {\n \tconst char *working_tree_encoding; /* Supported encoding or default encoding if NULL */\n };\n \n-static void convert_attrs(struct conv_attrs *ca, const char *path)\n+static void convert_attrs(const struct index_state *istate,\n+\t\t\t  struct conv_attrs *ca, const char *path)\n {\n \tstatic struct attr_check *check;\n \n@@ -1302,7 +1303,7 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tgit_config(read_convert_config, NULL);\n \t}\n \n-\tif (!git_check_attr(&the_index, path, check)) {\n+\tif (!git_check_attr(istate, path, check)) {\n \t\tstruct attr_check_item *ccheck = check->items;\n \t\tca->crlf_action = git_path_check_crlf(ccheck + 4);\n \t\tif (ca->crlf_action == CRLF_UNDEFINED)\n@@ -1339,11 +1340,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->crlf_action = CRLF_AUTO_INPUT;\n }\n \n-int would_convert_to_git_filter_fd(const char *path)\n+int would_convert_to_git_filter_fd(const struct index_state *istate, const char *path)\n {\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tif (!ca.drv)\n \t\treturn 0;\n \n@@ -1358,11 +1359,11 @@ int would_convert_to_git_filter_fd(const char *path)\n \treturn apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL);\n }\n \n-const char *get_convert_attr_ascii(const char *path)\n+const char *get_convert_attr_ascii(const struct index_state *istate, const char *path)\n {\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tswitch (ca.attr_action) {\n \tcase CRLF_UNDEFINED:\n \t\treturn \"\";\n@@ -1391,7 +1392,7 @@ int convert_to_git(const struct index_state *istate,\n \tint ret = 0;\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);\n \tif (!ret && ca.drv && ca.drv->required)\n@@ -1423,7 +1424,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \t\t\t      int conv_flags)\n {\n \tstruct conv_attrs ca;\n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tassert(ca.drv);\n \tassert(ca.drv->clean || ca.drv->process);\n@@ -1436,14 +1437,15 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-static int convert_to_working_tree_internal(const char *path, const char *src,\n+static int convert_to_working_tree_internal(const struct index_state *istate,\n+\t\t\t\t\t    const char *path, const char *src,\n \t\t\t\t\t    size_t len, struct strbuf *dst,\n \t\t\t\t\t    int normalizing, struct delayed_checkout *dco)\n {\n \tint ret = 0, ret_filter = 0;\n \tstruct conv_attrs ca;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \n \tret |= ident_to_worktree(path, src, len, dst, ca.ident);\n \tif (ret) {\n@@ -1477,22 +1479,25 @@ static int convert_to_working_tree_internal(const char *path, const char *src,\n \treturn ret | ret_filter;\n }\n \n-int async_convert_to_working_tree(const char *path, const char *src,\n+int async_convert_to_working_tree(const struct index_state *istate,\n+\t\t\t\t  const char *path, const char *src,\n \t\t\t\t  size_t len, struct strbuf *dst,\n \t\t\t\t  void *dco)\n {\n-\treturn convert_to_working_tree_internal(path, src, len, dst, 0, dco);\n+\treturn convert_to_working_tree_internal(istate, path, src, len, dst, 0, dco);\n }\n \n-int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)\n+int convert_to_working_tree(const struct index_state *istate,\n+\t\t\t    const char *path, const char *src,\n+\t\t\t    size_t len, struct strbuf *dst)\n {\n-\treturn convert_to_working_tree_internal(path, src, len, dst, 0, NULL);\n+\treturn convert_to_working_tree_internal(istate, path, src, len, dst, 0, NULL);\n }\n \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, NULL);\n+\tint ret = convert_to_working_tree_internal(istate, path, src, len, dst, 1, NULL);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -1926,12 +1931,14 @@ static struct stream_filter *ident_filter(const struct object_id *oid)\n  * Note that you would be crazy to set CRLF, smuge/clean or ident to a\n  * large binary blob you would want us not to slurp into the memory!\n  */\n-struct stream_filter *get_stream_filter(const char *path, const struct object_id *oid)\n+struct stream_filter *get_stream_filter(const struct index_state *istate,\n+\t\t\t\t\tconst char *path,\n+\t\t\t\t\tconst struct object_id *oid)\n {\n \tstruct conv_attrs ca;\n \tstruct stream_filter *filter = NULL;\n \n-\tconvert_attrs(&ca, path);\n+\tconvert_attrs(istate, &ca, path);\n \tif (ca.drv && (ca.drv->process || ca.drv->smudge || ca.drv->clean))\n \t\treturn NULL;\n \ndiff --git a/convert.h b/convert.h\nindex 0a0fa15b58..6d0ee887ed 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -60,15 +60,18 @@ extern char *check_roundtrip_encoding;\n const char *get_cached_convert_stats_ascii(const struct index_state *istate,\n \t\t\t\t\t   const char *path);\n const char *get_wt_convert_stats_ascii(const char *path);\n-const char *get_convert_attr_ascii(const char *path);\n+const char *get_convert_attr_ascii(const struct index_state *istate,\n+\t\t\t\t   const char *path);\n \n /* returns 1 if *dst was used */\n int convert_to_git(const struct index_state *istate,\n \t\t   const char *path, const char *src, size_t len,\n \t\t   struct strbuf *dst, int conv_flags);\n-int convert_to_working_tree(const char *path, const char *src,\n+int convert_to_working_tree(const struct index_state *istate,\n+\t\t\t    const char *path, const char *src,\n \t\t\t    size_t len, struct strbuf *dst);\n-int async_convert_to_working_tree(const char *path, const char *src,\n+int async_convert_to_working_tree(const struct index_state *istate,\n+\t\t\t\t  const char *path, const char *src,\n \t\t\t\t  size_t len, struct strbuf *dst,\n \t\t\t\t  void *dco);\n int async_query_available_blobs(const char *cmd,\n@@ -86,7 +89,8 @@ void convert_to_git_filter_fd(const struct index_state *istate,\n \t\t\t      const char *path, int fd,\n \t\t\t      struct strbuf *dst,\n \t\t\t      int conv_flags);\n-int would_convert_to_git_filter_fd(const char *path);\n+int would_convert_to_git_filter_fd(const struct index_state *istate,\n+\t\t\t\t   const char *path);\n \n /*****************************************************************\n  *\n@@ -96,7 +100,8 @@ int would_convert_to_git_filter_fd(const char *path);\n \n struct stream_filter; /* opaque */\n \n-struct stream_filter *get_stream_filter(const char *path,\n+struct stream_filter *get_stream_filter(const struct index_state *istate,\n+\t\t\t\t\tconst char *path,\n \t\t\t\t\tconst struct object_id *);\n void free_stream_filter(struct stream_filter *);\n int is_null_stream_filter(struct stream_filter *);\ndiff --git a/diff.c b/diff.c\nindex 136d44b455..526ee2e911 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3695,7 +3695,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,\n \ttemp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1);\n \tif (!temp->tempfile)\n \t\tdie_errno(\"unable to create temp-file\");\n-\tif (convert_to_working_tree(path,\n+\tif (convert_to_working_tree(&the_index, path,\n \t\t\t(const char *)blob, (size_t)size, &buf)) {\n \t\tblob = buf.buf;\n \t\tsize = buf.len;\ndiff --git a/entry.c b/entry.c\nindex 2101201a11..12d9191051 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -265,7 +265,7 @@ static int write_entry(struct cache_entry *ce,\n \tconst struct submodule *sub;\n \n \tif (ce_mode_s_ifmt == S_IFREG) {\n-\t\tstruct stream_filter *filter = get_stream_filter(ce->name,\n+\t\tstruct stream_filter *filter = get_stream_filter(&the_index, ce->name,\n \t\t\t\t\t\t\t\t &ce->oid);\n \t\tif (filter &&\n \t\t    !streaming_write_entry(ce, path, filter,\n@@ -313,14 +313,14 @@ static int write_entry(struct cache_entry *ce,\n \t\t * Convert from git internal format to working tree format\n \t\t */\n \t\tif (dco && dco->state != CE_NO_DELAY) {\n-\t\t\tret = async_convert_to_working_tree(ce->name, new_blob,\n+\t\t\tret = async_convert_to_working_tree(&the_index, ce->name, new_blob,\n \t\t\t\t\t\t\t    size, &buf, dco);\n \t\t\tif (ret && string_list_has_string(&dco->paths, ce->name)) {\n \t\t\t\tfree(new_blob);\n \t\t\t\tgoto delayed;\n \t\t\t}\n \t\t} else\n-\t\t\tret = convert_to_working_tree(ce->name, new_blob, size, &buf);\n+\t\t\tret = convert_to_working_tree(&the_index, ce->name, new_blob, size, &buf);\n \n \t\tif (ret) {\n \t\t\tfree(new_blob);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ac27abbd4c..b404ebac7c 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -961,7 +961,7 @@ static int update_file_flags(struct merge_options *o,\n \t\t}\n \t\tif (S_ISREG(mode)) {\n \t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(path, buf, size, &strbuf)) {\n+\t\t\tif (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {\n \t\t\t\tfree(buf);\n \t\t\t\tsize = strbuf.len;\n \t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\ndiff --git a/sha1-file.c b/sha1-file.c\nindex 555e780f4b..0b0834452d 100644\n--- a/sha1-file.c\n+++ b/sha1-file.c\n@@ -1860,7 +1860,7 @@ static int index_stream_convert_blob(struct object_id *oid, int fd,\n \tstruct strbuf sbuf = STRBUF_INIT;\n \n \tassert(path);\n-\tassert(would_convert_to_git_filter_fd(path));\n+\tassert(would_convert_to_git_filter_fd(&the_index, path));\n \n \tconvert_to_git_filter_fd(&the_index, path, fd, &sbuf,\n \t\t\t\t get_conv_flags(flags));\n@@ -1950,7 +1950,7 @@ int index_fd(struct object_id *oid, int fd, struct stat *st,\n \t * Call xsize_t() only when needed to avoid potentially unnecessary\n \t * die() for large files.\n \t */\n-\tif (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(path))\n+\tif (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(&the_index, path))\n \t\tret = index_stream_convert_blob(oid, fd, path, flags);\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(oid, fd, type, path, flags);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349520","messageId":"20180606170243.4169-6-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 11/23] ls-files: correct index argument to get_convert_attr_ascii()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:31Z","receivedAt":"2018-06-06T17:03:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"write_eolinfo() does take an istate as function argument and it should\nbe used instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 17 +++++++++--------\n 1 file changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 7233b92794..7f9919a362 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate,\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(&the_index, path);\n+\t\tconst char *a_txt = get_convert_attr_ascii(istate, path);\n \t\tif (ce && S_ISREG(ce->ce_mode))\n \t\t\ti_txt = get_cached_convert_stats_ascii(istate,\n \t\t\t\t\t\t\t       ce->name);\n@@ -121,18 +121,19 @@ static void print_debug(const struct cache_entry *ce)\n \t}\n }\n \n-static void show_dir_entry(const char *tag, struct dir_entry *ent)\n+static void show_dir_entry(const struct index_state *istate,\n+\t\t\t   const char *tag, struct dir_entry *ent)\n {\n \tint len = max_prefix_len;\n \n \tif (len > ent->len)\n \t\tdie(\"git ls-files: internal error - directory entry not superset of prefix\");\n \n-\tif (!dir_path_match(&the_index, ent, &pathspec, len, ps_matched))\n+\tif (!dir_path_match(istate, ent, &pathspec, len, ps_matched))\n \t\treturn;\n \n \tfputs(tag, stdout);\n-\twrite_eolinfo(NULL, NULL, ent->name);\n+\twrite_eolinfo(istate, NULL, ent->name);\n \twrite_name(ent->name);\n }\n \n@@ -145,7 +146,7 @@ static void show_other_files(const struct index_state *istate,\n \t\tstruct dir_entry *ent = dir->entries[i];\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\tshow_dir_entry(istate, tag_other, ent);\n \t}\n }\n \n@@ -196,7 +197,7 @@ static void show_killed_files(const struct index_state *istate,\n \t\t\t}\n \t\t}\n \t\tif (killed)\n-\t\t\tshow_dir_entry(tag_killed, dir->entries[i]);\n+\t\t\tshow_dir_entry(istate, tag_killed, dir->entries[i]);\n \t}\n }\n \n@@ -228,7 +229,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,\n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n \t    is_submodule_active(repo, ce->name)) {\n \t\tshow_submodule(repo, dir, ce->name);\n-\t} else if (match_pathspec(&the_index, &pathspec, fullname, strlen(fullname),\n+\t} else if (match_pathspec(repo->index, &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@@ -264,7 +265,7 @@ static void show_ru_info(const struct index_state *istate)\n \t\tlen = strlen(path);\n \t\tif (len < max_prefix_len)\n \t\t\tcontinue; /* outside of the prefix */\n-\t\tif (!match_pathspec(&the_index, &pathspec, path, len,\n+\t\tif (!match_pathspec(istate, &pathspec, path, len,\n \t\t\t\t    max_prefix_len, ps_matched, 0))\n \t\t\tcontinue; /* uninterested */\n \t\tfor (i = 0; i < 3; i++) {\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349521","messageId":"20180606170243.4169-5-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 10/23] dir.c: remove an implicit dependency on the_index in pathspec code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:30Z","receivedAt":"2018-06-06T17:03:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the match_patchspec API and friends take an index_state instead\nof assuming the_index in dir.c. All external call sites are converted\nblindly to keep the patch simple and retain current behavior.\nIndividual call sites may receive further updates to use the right\nindex instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c                   |  2 +-\n builtin/add.c               |  6 +++---\n builtin/checkout.c          |  2 +-\n builtin/clean.c             |  2 +-\n builtin/commit.c            |  2 +-\n builtin/grep.c              |  6 +++---\n builtin/ls-files.c          |  6 +++---\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c |  2 +-\n builtin/update-index.c      |  2 +-\n diff-lib.c                  |  4 ++--\n dir.c                       | 27 ++++++++++++++++-----------\n dir.h                       | 16 ++++++++++------\n pathspec.c                  |  2 +-\n preload-index.c             |  2 +-\n read-cache.c                |  2 +-\n rerere.c                    |  2 +-\n resolve-undo.c              |  2 +-\n revision.c                  |  2 +-\n submodule.c                 |  2 +-\n wt-status.c                 |  6 +++---\n 21 files changed, 54 insertions(+), 45 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex f3631a4fb5..1b44503ebb 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -312,7 +312,7 @@ static int reject_entry(const struct object_id *oid, struct strbuf *base,\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstrbuf_addbuf(&sb, base);\n \t\tstrbuf_addstr(&sb, filename);\n-\t\tif (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))\n+\t\tif (!match_pathspec(&the_index, context, sb.buf, sb.len, 0, NULL, 1))\n \t\t\tret = READ_TREE_RECURSIVE;\n \t\tstrbuf_release(&sb);\n \t}\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 8a155dd41e..066623a195 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -40,7 +40,7 @@ static void chmod_pathspec(struct pathspec *pathspec, char flip)\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n \n-\t\tif (pathspec && !ce_path_match(ce, pathspec, NULL))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \n \t\tif (chmod_cache_entry(ce, flip) < 0)\n@@ -135,7 +135,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)\n \t\t\tcontinue; /* do not touch unmerged paths */\n \t\tif (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))\n \t\t\tcontinue; /* do not touch non blobs */\n-\t\tif (pathspec && !ce_path_match(ce, pathspec, NULL))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\tretval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE);\n \t}\n@@ -155,7 +155,7 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,\n \ti = dir->nr;\n \twhile (--i >= 0) {\n \t\tstruct dir_entry *entry = *src++;\n-\t\tif (dir_path_match(entry, pathspec, prefix, seen))\n+\t\tif (dir_path_match(&the_index, entry, pathspec, prefix, seen))\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2e1d2376d2..f8c208cea1 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -316,7 +316,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t * match_pathspec() for _all_ entries when\n \t\t * opts->source_tree != NULL.\n \t\t */\n-\t\tif (ce_path_match(ce, &opts->pathspec, ps_matched))\n+\t\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n \t\t\tce->ce_flags |= CE_MATCHED;\n \t}\n \ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex fad533a0a7..d4ca64904f 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -981,7 +981,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \n \t\tif (pathspec.nr)\n-\t\t\tmatches = dir_path_match(ent, &pathspec, 0, NULL);\n+\t\t\tmatches = dir_path_match(&the_index, ent, &pathspec, 0, NULL);\n \n \t\tif (pathspec.nr && !matches)\n \t\t\tcontinue;\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex a842fea666..f593ec1bbc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -238,7 +238,7 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, pattern, m))\n+\t\tif (!ce_path_match(&the_index, ce, pattern, m))\n \t\t\tcontinue;\n \t\titem = string_list_insert(list, ce->name);\n \t\tif (ce_skip_worktree(ce))\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex ee753a403e..2eae397e92 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\tstrbuf_addstr(&name, ce->name);\n \n \t\tif (S_ISREG(ce->ce_mode) &&\n-\t\t    match_pathspec(pathspec, name.buf, name.len, 0, NULL,\n+\t\t    match_pathspec(&the_index, pathspec, name.buf, name.len, 0, NULL,\n \t\t\t\t   S_ISDIR(ce->ce_mode) ||\n \t\t\t\t   S_ISGITLINK(ce->ce_mode))) {\n \t\t\t/*\n@@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\t\t\thit |= grep_file(opt, name.buf);\n \t\t\t}\n \t\t} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t\t\t   submodule_path_match(pathspec, name.buf, NULL)) {\n+\t\t\t   submodule_path_match(&the_index, pathspec, name.buf, NULL)) {\n \t\t\thit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);\n \t\t} else {\n \t\t\tcontinue;\n@@ -678,7 +678,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,\n \n \tfill_directory(&dir, &the_index, pathspec);\n \tfor (i = 0; i < dir.nr; i++) {\n-\t\tif (!dir_path_match(dir.entries[i], pathspec, 0, NULL))\n+\t\tif (!dir_path_match(&the_index, dir.entries[i], pathspec, 0, NULL))\n \t\t\tcontinue;\n \t\thit |= grep_file(opt, dir.entries[i]->name);\n \t\tif (hit && opt->status_only)\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex d996734b45..7233b92794 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -128,7 +128,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \tif (len > ent->len)\n \t\tdie(\"git ls-files: internal error - directory entry not superset of prefix\");\n \n-\tif (!dir_path_match(ent, &pathspec, len, ps_matched))\n+\tif (!dir_path_match(&the_index, ent, &pathspec, len, ps_matched))\n \t\treturn;\n \n \tfputs(tag, stdout);\n@@ -228,7 +228,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,\n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\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} else if (match_pathspec(&the_index, &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@@ -264,7 +264,7 @@ static void show_ru_info(const struct index_state *istate)\n \t\tlen = strlen(path);\n \t\tif (len < max_prefix_len)\n \t\t\tcontinue; /* outside of the prefix */\n-\t\tif (!match_pathspec(&pathspec, path, len,\n+\t\tif (!match_pathspec(&the_index, &pathspec, path, len,\n \t\t\t\t    max_prefix_len, ps_matched, 0))\n \t\t\tcontinue; /* uninterested */\n \t\tfor (i = 0; i < 3; i++) {\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 65b448ef8e..eebdc4aab1 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -278,7 +278,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \n \tfor (i = 0; i < active_nr; i++) {\n \t\tconst struct cache_entry *ce = active_cache[i];\n-\t\tif (!ce_path_match(ce, &pathspec, seen))\n+\t\tif (!ce_path_match(&the_index, ce, &pathspec, seen))\n \t\t\tcontinue;\n \t\tALLOC_GROW(list.entry, list.nr + 1, list.alloc);\n \t\tlist.entry[list.nr].name = xstrdup(ce->name);\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bd250ca216..d59c6a988e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -330,7 +330,7 @@ static int module_list_compute(int argc, const char **argv,\n \tfor (i = 0; i < active_nr; i++) {\n \t\tconst struct cache_entry *ce = active_cache[i];\n \n-\t\tif (!match_pathspec(pathspec, ce->name, ce_namelen(ce),\n+\t\tif (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),\n \t\t\t\t    0, ps_matched, 1) ||\n \t\t    !S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex a8709a26ec..a181b5c14c 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -751,7 +751,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tint save_nr;\n \t\tchar *path;\n \n-\t\tif (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))\n+\t\tif (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (has_head)\n \t\t\told = read_one_ent(NULL, &head_oid,\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 104f954a25..068d00705e 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -109,7 +109,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\tif (diff_can_quit_early(&revs->diffopt))\n \t\t\tbreak;\n \n-\t\tif (!ce_path_match(ce, &revs->prune_data, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &revs->prune_data, NULL))\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n@@ -470,7 +470,7 @@ static int oneway_diff(const struct cache_entry * const *src,\n \tif (tree == o->df_conflict_entry)\n \t\ttree = NULL;\n \n-\tif (ce_path_match(idx ? idx : tree, &revs->prune_data, NULL)) {\n+\tif (ce_path_match(&the_index, idx ? idx : tree, &revs->prune_data, NULL)) {\n \t\tdo_oneway_diff(o, idx, tree);\n \t\tif (diff_can_quit_early(&revs->diffopt)) {\n \t\t\to->exiting_early = 1;\ndiff --git a/dir.c b/dir.c\nindex a541be3032..1f50559548 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -275,12 +275,13 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,\n #define DO_MATCH_DIRECTORY (1<<1)\n #define DO_MATCH_SUBMODULE (1<<2)\n \n-static int match_attrs(const char *name, int namelen,\n+static int match_attrs(const struct index_state *istate,\n+\t\t       const char *name, int namelen,\n \t\t       const struct pathspec_item *item)\n {\n \tint i;\n \n-\tgit_check_attr(&the_index, name, item->attr_check);\n+\tgit_check_attr(istate, name, item->attr_check);\n \tfor (i = 0; i < item->attr_match_nr; i++) {\n \t\tconst char *value;\n \t\tint matched;\n@@ -317,7 +318,8 @@ static int match_attrs(const char *name, int namelen,\n  *\n  * It returns 0 when there is no match.\n  */\n-static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n+static int match_pathspec_item(const struct index_state *istate,\n+\t\t\t       const struct pathspec_item *item, int prefix,\n \t\t\t       const char *name, int namelen, unsigned flags)\n {\n \t/* name/namelen has prefix cut off by caller */\n@@ -357,7 +359,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n \t    strncmp(item->match, name - prefix, item->prefix))\n \t\treturn 0;\n \n-\tif (item->attr_match_nr && !match_attrs(name, namelen, item))\n+\tif (item->attr_match_nr && !match_attrs(istate, name, namelen, item))\n \t\treturn 0;\n \n \t/* If the match was just the prefix, we matched */\n@@ -425,7 +427,8 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n  * pathspec did not match any names, which could indicate that the\n  * user mistyped the nth pathspec.\n  */\n-static int do_match_pathspec(const struct pathspec *ps,\n+static int do_match_pathspec(const struct index_state *istate,\n+\t\t\t     const struct pathspec *ps,\n \t\t\t     const char *name, int namelen,\n \t\t\t     int prefix, char *seen,\n \t\t\t     unsigned flags)\n@@ -471,7 +474,7 @@ static int do_match_pathspec(const struct pathspec *ps,\n \t\t */\n \t\tif (seen && ps->items[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tseen[i] = MATCHED_FNMATCH;\n-\t\thow = match_pathspec_item(ps->items+i, prefix, name,\n+\t\thow = match_pathspec_item(istate, ps->items+i, prefix, name,\n \t\t\t\t\t  namelen, flags);\n \t\tif (ps->recursive &&\n \t\t    (ps->magic & PATHSPEC_MAXDEPTH) &&\n@@ -495,17 +498,18 @@ static int do_match_pathspec(const struct pathspec *ps,\n \treturn retval;\n }\n \n-int match_pathspec(const struct pathspec *ps,\n+int match_pathspec(const struct index_state *istate,\n+\t\t   const struct pathspec *ps,\n \t\t   const char *name, int namelen,\n \t\t   int prefix, char *seen, int is_dir)\n {\n \tint positive, negative;\n \tunsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;\n-\tpositive = do_match_pathspec(ps, name, namelen,\n+\tpositive = do_match_pathspec(istate, ps, name, namelen,\n \t\t\t\t     prefix, seen, flags);\n \tif (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)\n \t\treturn positive;\n-\tnegative = do_match_pathspec(ps, name, namelen,\n+\tnegative = do_match_pathspec(istate, ps, name, namelen,\n \t\t\t\t     prefix, seen,\n \t\t\t\t     flags | DO_MATCH_EXCLUDE);\n \treturn negative ? 0 : positive;\n@@ -514,11 +518,12 @@ int match_pathspec(const struct pathspec *ps,\n /**\n  * Check if a submodule is a superset of the pathspec\n  */\n-int submodule_path_match(const struct pathspec *ps,\n+int submodule_path_match(const struct index_state *istate,\n+\t\t\t const struct pathspec *ps,\n \t\t\t const char *submodule_name,\n \t\t\t char *seen)\n {\n-\tint matched = do_match_pathspec(ps, submodule_name,\n+\tint matched = do_match_pathspec(istate, ps, submodule_name,\n \t\t\t\t\tstrlen(submodule_name),\n \t\t\t\t\t0, seen,\n \t\t\t\t\tDO_MATCH_DIRECTORY |\ndiff --git a/dir.h b/dir.h\nindex f5fdedbab2..e3ec26143d 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -216,7 +216,8 @@ extern int count_slashes(const char *s);\n extern int simple_length(const char *match);\n extern int no_wildcard(const char *string);\n extern char *common_prefix(const struct pathspec *pathspec);\n-extern int match_pathspec(const struct pathspec *pathspec,\n+extern int match_pathspec(const struct index_state *istate,\n+\t\t\t  const struct pathspec *pathspec,\n \t\t\t  const char *name, int namelen,\n \t\t\t  int prefix, char *seen, int is_dir);\n extern int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);\n@@ -326,25 +327,28 @@ extern int git_fnmatch(const struct pathspec_item *item,\n \t\t       const char *pattern, const char *string,\n \t\t       int prefix);\n \n-extern int submodule_path_match(const struct pathspec *ps,\n+extern int submodule_path_match(const struct index_state *istate,\n+\t\t\t\tconst struct pathspec *ps,\n \t\t\t\tconst char *submodule_name,\n \t\t\t\tchar *seen);\n \n-static inline int ce_path_match(const struct cache_entry *ce,\n+static inline int ce_path_match(const struct index_state *istate,\n+\t\t\t\tconst struct cache_entry *ce,\n \t\t\t\tconst struct pathspec *pathspec,\n \t\t\t\tchar *seen)\n {\n-\treturn match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen,\n+\treturn match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,\n \t\t\t      S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));\n }\n \n-static inline int dir_path_match(const struct dir_entry *ent,\n+static inline int dir_path_match(const struct index_state *istate,\n+\t\t\t\t const struct dir_entry *ent,\n \t\t\t\t const struct pathspec *pathspec,\n \t\t\t\t int prefix, char *seen)\n {\n \tint has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/';\n \tint len = has_trailing_dir ? ent->len - 1 : ent->len;\n-\treturn match_pathspec(pathspec, ent->name, len, prefix, seen,\n+\treturn match_pathspec(istate, pathspec, ent->name, len, prefix, seen,\n \t\t\t      has_trailing_dir);\n }\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 27cd606786..897cb9cbbe 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -37,7 +37,7 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,\n \t\treturn;\n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tce_path_match(ce, pathspec, seen);\n+\t\tce_path_match(&the_index, ce, pathspec, seen);\n \t}\n }\n \ndiff --git a/preload-index.c b/preload-index.c\nindex 4d08d44874..d61d7662d5 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -58,7 +58,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce->ce_flags & CE_FSMONITOR_VALID)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, &p->pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &p->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\ndiff --git a/read-cache.c b/read-cache.c\nindex 372588260e..12cc22d157 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1415,7 +1415,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \t\tif (ignore_submodules && S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (pathspec && !ce_path_match(ce, pathspec, seen))\n+\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))\n \t\t\tfiltered = 1;\n \n \t\tif (ce_stage(ce)) {\ndiff --git a/rerere.c b/rerere.c\nindex e0862e2778..e3b572296d 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -1118,7 +1118,7 @@ int rerere_forget(struct pathspec *pathspec)\n \tfind_conflict(&conflict);\n \tfor (i = 0; i < conflict.nr; i++) {\n \t\tstruct string_list_item *it = &conflict.items[i];\n-\t\tif (!match_pathspec(pathspec, it->string,\n+\t\tif (!match_pathspec(&the_index, pathspec, it->string,\n \t\t\t\t    strlen(it->string), 0, NULL, 0))\n \t\t\tcontinue;\n \t\trerere_forget_one_path(it->string, &merge_rr);\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex fc5b3b83d9..5e4c8c5f75 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -186,7 +186,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)\n \n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_path_match(ce, pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\ti = unmerge_index_entry_at(istate, i);\n \t}\ndiff --git a/revision.c b/revision.c\nindex 40fd91ff2b..cf6aa1f443 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1501,7 +1501,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\tconst struct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (ce_path_match(ce, &revs->prune_data, NULL)) {\n+\t\tif (ce_path_match(&the_index, ce, &revs->prune_data, NULL)) {\n \t\t\tprune_num++;\n \t\t\tREALLOC_ARRAY(prune, prune_num);\n \t\t\tprune[prune_num-2] = ce->name;\ndiff --git a/submodule.c b/submodule.c\nindex 939d6870ec..955560bdbb 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -258,7 +258,7 @@ int is_submodule_active(struct repository *repo, const char *path)\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+\t\tret = match_pathspec(&the_index, &ps, path, strlen(path), 0, NULL, 1);\n \n \t\targv_array_clear(&args);\n \t\tclear_pathspec(&ps);\ndiff --git a/wt-status.c b/wt-status.c\nindex d1c05145a4..d384294c12 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -647,7 +647,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\tstruct wt_status_change_data *d;\n \t\tconst struct cache_entry *ce = active_cache[i];\n \n-\t\tif (!ce_path_match(ce, &s->pathspec, NULL))\n+\t\tif (!ce_path_match(&the_index, ce, &s->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (ce_intent_to_add(ce))\n \t\t\tcontinue;\n@@ -703,7 +703,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\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\t    dir_path_match(ent, &s->pathspec, 0, NULL))\n+\t\t    dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))\n \t\t\tstring_list_insert(&s->untracked, ent->name);\n \t\tfree(ent);\n \t}\n@@ -711,7 +711,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \tfor (i = 0; i < dir.ignored_nr; i++) {\n \t\tstruct dir_entry *ent = dir.ignored[i];\n \t\tif (cache_name_is_other(ent->name, ent->len) &&\n-\t\t    dir_path_match(ent, &s->pathspec, 0, NULL))\n+\t\t    dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))\n \t\t\tstring_list_insert(&s->ignored, ent->name);\n \t\tfree(ent);\n \t}\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349522","messageId":"20180606170243.4169-9-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 14/23] entry.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:34Z","receivedAt":"2018-06-06T17:03:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"checkout-index.c needs update because if checkout->istate is NULL,\nie_match_stat() will crash. Previously this is ie_match_stat(&the_index, ..)\nso it will not crash, but it is not technically correct either.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout-index.c |  1 +\n entry.c                  | 10 ++++++----\n 2 files changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex a730f6a1aa..d92db62fbd 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -190,6 +190,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, builtin_checkout_index_options,\n \t\t\tbuiltin_checkout_index_usage, 0);\n+\tstate.istate = &the_index;\n \tstate.force = force;\n \tstate.quiet = quiet;\n \tstate.not_new = not_new;\ndiff --git a/entry.c b/entry.c\nindex 12d9191051..02752f7b53 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"blob.h\"\n #include \"dir.h\"\n@@ -265,7 +266,7 @@ static int write_entry(struct cache_entry *ce,\n \tconst struct submodule *sub;\n \n \tif (ce_mode_s_ifmt == S_IFREG) {\n-\t\tstruct stream_filter *filter = get_stream_filter(&the_index, ce->name,\n+\t\tstruct stream_filter *filter = get_stream_filter(state->istate, ce->name,\n \t\t\t\t\t\t\t\t &ce->oid);\n \t\tif (filter &&\n \t\t    !streaming_write_entry(ce, path, filter,\n@@ -313,14 +314,14 @@ static int write_entry(struct cache_entry *ce,\n \t\t * Convert from git internal format to working tree format\n \t\t */\n \t\tif (dco && dco->state != CE_NO_DELAY) {\n-\t\t\tret = async_convert_to_working_tree(&the_index, ce->name, new_blob,\n+\t\t\tret = async_convert_to_working_tree(state->istate, ce->name, new_blob,\n \t\t\t\t\t\t\t    size, &buf, dco);\n \t\t\tif (ret && string_list_has_string(&dco->paths, ce->name)) {\n \t\t\t\tfree(new_blob);\n \t\t\t\tgoto delayed;\n \t\t\t}\n \t\t} else\n-\t\t\tret = convert_to_working_tree(&the_index, ce->name, new_blob, size, &buf);\n+\t\t\tret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf);\n \n \t\tif (ret) {\n \t\t\tfree(new_blob);\n@@ -421,7 +422,8 @@ int checkout_entry(struct cache_entry *ce,\n \n \tif (!check_path(path.buf, path.len, &st, state->base_dir_len)) {\n \t\tconst struct submodule *sub;\n-\t\tunsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n+\t\tunsigned changed = ie_match_stat(state->istate, ce, &st,\n+\t\t\t\t\t\t CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n \t\t/*\n \t\t * Needs to be checked before !changed returns early,\n \t\t * as the possibly empty directory was not changed\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349523","messageId":"20180606170243.4169-8-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 13/23] submodule.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:33Z","receivedAt":"2018-06-06T17:03:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n submodule.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 955560bdbb..3aed76e3ee 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -93,7 +93,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)\n \tif (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */\n \t\treturn -1;\n \n-\tif (is_gitmodules_unmerged(&the_index))\n+\tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n \tsubmodule = submodule_from_path(the_repository, &null_oid, oldpath);\n@@ -127,7 +127,7 @@ int remove_path_from_gitmodules(const char *path)\n \tif (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */\n \t\treturn -1;\n \n-\tif (is_gitmodules_unmerged(&the_index))\n+\tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n \tsubmodule = submodule_from_path(the_repository, &null_oid, path);\n@@ -188,7 +188,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \n \t\tif (ignore)\n \t\t\thandle_ignore_submodules_arg(diffopt, ignore);\n-\t\telse if (is_gitmodules_unmerged(&the_index))\n+\t\telse if (is_gitmodules_unmerged(the_repository->index))\n \t\t\tdiffopt->flags.ignore_submodules = 1;\n \t}\n }\n@@ -258,7 +258,7 @@ int is_submodule_active(struct repository *repo, const char *path)\n \t\t}\n \n \t\tparse_pathspec(&ps, 0, 0, NULL, args.argv);\n-\t\tret = match_pathspec(&the_index, &ps, path, strlen(path), 0, NULL, 1);\n+\t\tret = match_pathspec(repo->index, &ps, path, strlen(path), 0, NULL, 1);\n \n \t\targv_array_clear(&args);\n \t\tclear_pathspec(&ps);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349524","messageId":"20180606170243.4169-11-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 16/23] preload-index.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:36Z","receivedAt":"2018-06-06T17:03:21Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n preload-index.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/preload-index.c b/preload-index.c\nindex d61d7662d5..cc2b579791 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -1,6 +1,7 @@\n /*\n  * Copyright (C) 2008 Linus Torvalds\n  */\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"pathspec.h\"\n #include \"dir.h\"\n@@ -58,7 +59,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce->ce_flags & CE_FSMONITOR_VALID)\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(&the_index, ce, &p->pathspec, NULL))\n+\t\tif (!ce_path_match(index, ce, &p->pathspec, NULL))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349525","messageId":"20180606170243.4169-15-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 20/23] checkout: avoid the_index when possible","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:40Z","receivedAt":"2018-06-06T17:03:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex d2257e0d82..4dbcab3727 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -230,7 +230,7 @@ static int checkout_merged(int pos, const struct checkout *state)\n \tif (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n \tfree(result_buf.ptr);\n-\tce = make_index_entry(&the_index, mode, oid.hash, path, 2, 0);\n+\tce = make_index_entry(state->istate, mode, oid.hash, path, 2, 0);\n \tif (!ce)\n \t\tdie(_(\"make_index_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349526","messageId":"20180606170243.4169-18-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 23/23] cache.h: make the_index part of \"compatibility macros\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:43Z","receivedAt":"2018-06-06T17:03:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"While the_index is not actually a macro, its use throughout the code\nbase is dangerous because developers sometimes may not see that some\nfunction is using the_index (instead of some other index that the devs\nare interested in).\n\nBy keeping the_index part of this NO_ macro, we try to reduce its use\nmore and more until it's completely gone.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 64abd3e55c..eb8c79b8a1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -330,8 +330,6 @@ struct index_state {\n \tstruct ewah_bitmap *fsmonitor_dirty;\n };\n \n-extern struct index_state the_index;\n-\n /* Name hashing */\n extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);\n extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);\n@@ -340,6 +338,8 @@ extern void free_name_hash(struct index_state *istate);\n \n \n #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS\n+extern struct index_state the_index;\n+\n #define active_cache (the_index.cache)\n #define active_nr (the_index.cache_nr)\n #define active_alloc (the_index.cache_alloc)\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349527","messageId":"20180606170243.4169-17-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 22/23] grep: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:42Z","receivedAt":"2018-06-06T17:03:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 2eae397e92..a8cef2b159 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\tstrbuf_addstr(&name, ce->name);\n \n \t\tif (S_ISREG(ce->ce_mode) &&\n-\t\t    match_pathspec(&the_index, pathspec, name.buf, name.len, 0, NULL,\n+\t\t    match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,\n \t\t\t\t   S_ISDIR(ce->ce_mode) ||\n \t\t\t\t   S_ISGITLINK(ce->ce_mode))) {\n \t\t\t/*\n@@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,\n \t\t\t\thit |= grep_file(opt, name.buf);\n \t\t\t}\n \t\t} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n-\t\t\t   submodule_path_match(&the_index, pathspec, name.buf, NULL)) {\n+\t\t\t   submodule_path_match(repo->index, pathspec, name.buf, NULL)) {\n \t\t\thit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);\n \t\t} else {\n \t\t\tcontinue;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349528","messageId":"20180606170243.4169-14-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 19/23] difftool: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:39Z","receivedAt":"2018-06-06T17:03:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/difftool.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex fb2ccfe6f0..c7d6296762 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -321,7 +321,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_index_entry(&the_index, mode, oid->hash, path, 0, 0);\n+\tce = make_index_entry(state->istate, mode, oid->hash, path, 0, 0);\n \tret = checkout_entry(ce, state, NULL);\n \n \tfree(ce);\n@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\t * index.\n \t\t\t\t */\n \t\t\t\tstruct cache_entry *ce2 =\n-\t\t\t\t\tmake_index_entry(&the_index, rmode, roid.hash,\n+\t\t\t\t\tmake_index_entry(&wtindex, rmode, roid.hash,\n \t\t\t\t\t\t\t dst_path, 0, 0);\n \n \t\t\t\tadd_index_entry(&wtindex, ce2,\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349529","messageId":"20180606170243.4169-16-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 21/23] resolve-undo.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:41Z","receivedAt":"2018-06-06T17:03:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n resolve-undo.c | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex 383231b011..2377995d6d 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -1,3 +1,4 @@\n+#define NO_THE_INDEX_COMPATIBILITY_MACROS\n #include \"cache.h\"\n #include \"dir.h\"\n #include \"resolve-undo.h\"\n@@ -146,7 +147,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tstruct cache_entry *nce;\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n-\t\tnce = make_index_entry(&the_index, ru->mode[i], ru->oid[i].hash,\n+\t\tnce = make_index_entry(istate, ru->mode[i], ru->oid[i].hash,\n \t\t\t\t       name, i + 1, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n@@ -186,7 +187,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)\n \n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tif (!ce_path_match(&the_index, ce, pathspec, NULL))\n+\t\tif (!ce_path_match(istate, ce, pathspec, NULL))\n \t\t\tcontinue;\n \t\ti = unmerge_index_entry_at(istate, i);\n \t}\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349530","messageId":"20180606170243.4169-13-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 18/23] apply.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:38Z","receivedAt":"2018-06-06T17:03:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex fc42a0eadf..82f681972f 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4090,7 +4090,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n \t\t\treturn error(_(\"sha1 information is lacking or useless \"\n \t\t\t\t       \"(%s).\"), name);\n \n-\t\tce = make_index_entry(&the_index, patch->old_mode, oid.hash, name, 0, 0);\n+\t\tce = make_index_entry(&result, patch->old_mode, oid.hash, name, 0, 0);\n \t\tif (!ce)\n \t\t\treturn error(_(\"make_index_entry failed for path '%s'\"),\n \t\t\t\t     name);\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349531","messageId":"20180606170243.4169-10-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 15/23] attr: remove index from git_attr_set_direction()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:35Z","receivedAt":"2018-06-06T17:03:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Since attr checking API now take the index, there's no need to set an\nindex in advance with this call. Most call sites are straightforward\nbecause they either pass the_index or NULL (which defaults back to\nthe_index previously). There's only one suspicious call site in\nunpack-trees.c where it sets a different index.\n\nThis code in unpack-trees is about to checking out entries from the\nnew/temporary index after merging is done in it. The attributes will\nbe used by entry.c code to do crlf conversion if needed. entry.c now\nrespects struct checkout's istate field, and this field is correctly\nset in unpack-trees.c, there should be no regression from this change.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c            |  2 +-\n attr.c               | 15 +++------------\n attr.h               |  3 +--\n builtin/check-attr.c |  2 +-\n unpack-trees.c       |  4 ++--\n 5 files changed, 8 insertions(+), 18 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 1b44503ebb..d1d0a0d6b3 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -273,7 +273,7 @@ int write_archive_entries(struct archiver_args *args,\n \t\tinit_tree_desc(&t, args->tree->buffer, args->tree->size);\n \t\tif (unpack_trees(1, &t, &opts))\n \t\t\treturn -1;\n-\t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n+\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n \t}\n \n \terr = read_tree_recursive(args->tree, \"\", 0, 0, &args->pathspec,\ndiff --git a/attr.c b/attr.c\nindex 863fad3bd1..98e4953f6e 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -708,10 +708,8 @@ static struct attr_stack *read_attr_from_array(const char **list)\n  * another thread could potentially be calling into the attribute system.\n  */\n static enum git_attr_direction direction;\n-static const struct index_state *use_index;\n \n-void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    const struct index_state *istate)\n+void git_attr_set_direction(enum git_attr_direction new_direction)\n {\n \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n@@ -720,7 +718,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction,\n \t\tdrop_all_attr_stacks();\n \n \tdirection = new_direction;\n-\tuse_index = istate;\n }\n \n static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n@@ -750,17 +747,11 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n \tstruct attr_stack *res;\n \tchar *buf, *sp;\n \tint lineno = 0;\n-\tconst struct index_state *to_read_from;\n \n-\t/*\n-\t * Temporary workaround for c24f3abace (apply: file commited\n-\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n-\t */\n-\tto_read_from = use_index ? use_index : istate;\n-\tif (!to_read_from)\n+\tif (!istate)\n \t\treturn NULL;\n \n-\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n+\tbuf = read_blob_data_from_index(istate, path, NULL);\n \tif (!buf)\n \t\treturn NULL;\n \ndiff --git a/attr.h b/attr.h\nindex 3daca3c0cb..01dab4a126 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -77,8 +77,7 @@ enum git_attr_direction {\n \tGIT_ATTR_CHECKOUT,\n \tGIT_ATTR_INDEX\n };\n-void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    const struct index_state *istate);\n+void git_attr_set_direction(enum git_attr_direction new_direction);\n \n void attr_start(void);\n \ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex f7b59993d3..c05573ff9c 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -120,7 +120,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (cached_attrs)\n-\t\tgit_attr_set_direction(GIT_ATTR_INDEX, NULL);\n+\t\tgit_attr_set_direction(GIT_ATTR_INDEX);\n \n \tdoubledash = -1;\n \tfor (i = 0; doubledash < 0 && i < argc; i++) {\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 3ace82ca27..8cb407173e 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -361,7 +361,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tprogress = get_progress(o);\n \n \tif (o->update)\n-\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT, index);\n+\t\tgit_attr_set_direction(GIT_ATTR_CHECKOUT);\n \n \tif (should_update_submodules() && o->update && !o->dry_run)\n \t\tload_gitmodules_file(index, NULL);\n@@ -421,7 +421,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tstop_progress(&progress);\n \terrs |= finish_delayed_checkout(&state);\n \tif (o->update)\n-\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN, NULL);\n+\t\tgit_attr_set_direction(GIT_ATTR_CHECKIN);\n \treturn errs != 0;\n }\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349532","messageId":"20180606170243.4169-12-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 17/23] read-cache.c: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:37Z","receivedAt":"2018-06-06T17:03:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make some index API take an index_state instead of assuming the_index\nin read-cache.c. All external call sites are converted blindly to keep\nthe patch simple and retain current behavior.  Individual call sites\nmay receive further updates to use the right index instead of the_index.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n apply.c            |  4 ++--\n builtin/checkout.c |  4 ++--\n builtin/difftool.c |  4 ++--\n builtin/reset.c    |  4 ++--\n cache.h            |  5 +++--\n merge-recursive.c  |  2 +-\n read-cache.c       | 19 +++++++++++--------\n resolve-undo.c     |  2 +-\n 8 files changed, 24 insertions(+), 20 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 9720855590..fc42a0eadf 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4090,9 +4090,9 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n \t\t\treturn error(_(\"sha1 information is lacking or useless \"\n \t\t\t\t       \"(%s).\"), name);\n \n-\t\tce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);\n+\t\tce = make_index_entry(&the_index, patch->old_mode, oid.hash, name, 0, 0);\n \t\tif (!ce)\n-\t\t\treturn error(_(\"make_cache_entry failed for path '%s'\"),\n+\t\t\treturn error(_(\"make_index_entry failed for path '%s'\"),\n \t\t\t\t     name);\n \t\tif (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {\n \t\t\tfree(ce);\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex f8c208cea1..d2257e0d82 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -230,9 +230,9 @@ static int checkout_merged(int pos, const struct checkout *state)\n \tif (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n \tfree(result_buf.ptr);\n-\tce = make_cache_entry(mode, oid.hash, path, 2, 0);\n+\tce = make_index_entry(&the_index, mode, oid.hash, path, 2, 0);\n \tif (!ce)\n-\t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n+\t\tdie(_(\"make_index_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\n \tfree(ce);\n \treturn status;\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex bc97d4aef2..fb2ccfe6f0 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -321,7 +321,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(mode, oid->hash, path, 0, 0);\n+\tce = make_index_entry(&the_index, mode, oid->hash, path, 0, 0);\n \tret = checkout_entry(ce, state, NULL);\n \n \tfree(ce);\n@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\t\t * index.\n \t\t\t\t */\n \t\t\t\tstruct cache_entry *ce2 =\n-\t\t\t\t\tmake_cache_entry(rmode, roid.hash,\n+\t\t\t\t\tmake_index_entry(&the_index, rmode, roid.hash,\n \t\t\t\t\t\t\t dst_path, 0, 0);\n \n \t\t\t\tadd_index_entry(&wtindex, ce2,\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex a862c70fab..067f535031 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -134,10 +134,10 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tce = make_cache_entry(one->mode, one->oid.hash, one->path,\n+\t\tce = make_index_entry(&the_index, one->mode, one->oid.hash, one->path,\n \t\t\t\t      0, 0);\n \t\tif (!ce)\n-\t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\n+\t\t\tdie(_(\"make_index_entry failed for path '%s'\"),\n \t\t\t    one->path);\n \t\tif (is_missing) {\n \t\t\tce->ce_flags |= CE_INTENT_TO_ADD;\ndiff --git a/cache.h b/cache.h\nindex 89a107a7f7..64abd3e55c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -355,6 +355,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerged_cache() unmerged_index(&the_index)\n #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))\n #define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))\n+#define refresh_cache_entry(ce, flags) refresh_index_entry(&the_index, ce, flags)\n #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))\n #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))\n #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))\n@@ -698,7 +699,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n \n-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n+extern struct cache_entry *make_index_entry(struct index_state *istate, unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);\n@@ -751,7 +752,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n #define REFRESH_IGNORE_SUBMODULES\t0x0010\t/* ignore submodules */\n #define REFRESH_IN_PORCELAIN\t0x0020\t/* user friendly output, not \"needs update\" */\n extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);\n-extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);\n+extern struct cache_entry *refresh_index_entry(struct index_state *istate, struct cache_entry *, unsigned int);\n \n /*\n  * Opportunistically update the index but do not complain if we can't.\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex b404ebac7c..4f054d6dbb 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n+\tce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n \tif (!ce)\n \t\treturn err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 12cc22d157..4352aac521 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -745,9 +745,11 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \treturn add_to_index(istate, path, &st, flags);\n }\n \n-struct cache_entry *make_cache_entry(unsigned int mode,\n-\t\tconst unsigned char *sha1, const char *path, int stage,\n-\t\tunsigned int refresh_options)\n+struct cache_entry *make_index_entry(struct index_state *istate,\n+\t\t\t\t     unsigned int mode,\n+\t\t\t\t     const unsigned char *sha1,\n+\t\t\t\t     const char *path, int stage,\n+\t\t\t\t     unsigned int refresh_options)\n {\n \tint size, len;\n \tstruct cache_entry *ce, *ret;\n@@ -767,7 +769,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n \tce->ce_namelen = len;\n \tce->ce_mode = create_ce_mode(mode);\n \n-\tret = refresh_cache_entry(ce, refresh_options);\n+\tret = refresh_index_entry(istate, ce, refresh_options);\n \tif (ret != ce)\n \t\tfree(ce);\n \treturn ret;\n@@ -1415,7 +1417,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \t\tif (ignore_submodules && S_ISGITLINK(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))\n+\t\tif (pathspec && !ce_path_match(istate, ce, pathspec, seen))\n \t\t\tfiltered = 1;\n \n \t\tif (ce_stage(ce)) {\n@@ -1473,10 +1475,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \treturn has_errors;\n }\n \n-struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n-\t\t\t\t\t       unsigned int options)\n+struct cache_entry *refresh_index_entry(struct index_state *istate,\n+\t\t\t\t\tstruct cache_entry *ce,\n+\t\t\t\t\tunsigned int options)\n {\n-\treturn refresh_cache_ent(&the_index, ce, options, NULL, NULL);\n+\treturn refresh_cache_ent(istate, ce, options, NULL, NULL);\n }\n \n \ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex 5e4c8c5f75..383231b011 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -146,7 +146,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tstruct cache_entry *nce;\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n-\t\tnce = make_cache_entry(ru->mode[i], ru->oid[i].hash,\n+\t\tnce = make_index_entry(&the_index, ru->mode[i], ru->oid[i].hash,\n \t\t\t\t       name, i + 1, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349533","messageId":"20180606170243.4169-7-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 12/23] pathspec.c: use the right index instead of the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:32Z","receivedAt":"2018-06-06T17:03:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 897cb9cbbe..6f005996fd 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -37,7 +37,7 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,\n \t\treturn;\n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tconst struct cache_entry *ce = istate->cache[i];\n-\t\tce_path_match(&the_index, ce, pathspec, seen);\n+\t\tce_path_match(istate, ce, pathspec, seen);\n \t}\n }\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349534","messageId":"20180606170243.4169-2-pclouds@gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-1-pclouds@gmail.com","subject":"[PATCH v4 07/23] attr: remove an implicit dependency on the_index","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T17:02:27Z","receivedAt":"2018-06-06T17:03:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make the attr API take an index_state instead of assuming the_index in\nattr code. All call sites are converted blindly to keep the patch\nsimple and retain current behavior. Individual call sites may receive\nfurther updates to use the right index instead of the_index.\n\nThere is one ugly temporary workaround added in attr.c that needs some\nmore explanation.\n\nCommit c24f3abace (apply: file commited with CRLF should roundtrip\ndiff and apply - 2017-08-19) forces one convert_to_git() call to NOT\nread the index at all. But what do you know, we read it anyway by\nfalling back to the_index. When \"istate\" from convert_to_git is now\npropagated down to read_attr_from_array() we will hit segfault\nsomewhere inside read_blob_data_from_index.\n\nThe right way of dealing with this is to kill \"use_index\" variable and\nonly follow \"istate\" but at this stage we are not ready for that:\nwhile most git_attr_set_direction() calls just passes the_index to be\nassigned to use_index, unpack-trees passes a different one which is\nused by entry.c code, which has no way to know what index to use if we\ndelete use_index. So this has to be done later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c              |  2 +-\n attr.c                 | 57 ++++++++++++++++++++++++++++--------------\n attr.h                 | 10 +++++---\n builtin/check-attr.c   |  4 +--\n builtin/pack-objects.c |  2 +-\n convert.c              |  2 +-\n dir.c                  |  2 +-\n ll-merge.c             |  4 +--\n userdiff.c             |  2 +-\n ws.c                   |  2 +-\n 10 files changed, 55 insertions(+), 32 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 4fe7bec60c..3b4db8956a 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -108,7 +108,7 @@ static const struct attr_check *get_archive_attrs(const char *path)\n \tstatic struct attr_check *check;\n \tif (!check)\n \t\tcheck = attr_check_initl(\"export-ignore\", \"export-subst\", NULL);\n-\treturn git_check_attr(path, check) ? NULL : check;\n+\treturn git_check_attr(&the_index, path, check) ? NULL : check;\n }\n \n static int check_attr_export_ignore(const struct attr_check *check)\ndiff --git a/attr.c b/attr.c\nindex 067fb9e0c0..863fad3bd1 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -708,10 +708,10 @@ static struct attr_stack *read_attr_from_array(const char **list)\n  * another thread could potentially be calling into the attribute system.\n  */\n static enum git_attr_direction direction;\n-static struct index_state *use_index;\n+static const struct index_state *use_index;\n \n void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    struct index_state *istate)\n+\t\t\t    const struct index_state *istate)\n {\n \tif (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n \t\tBUG(\"non-INDEX attr direction in a bare repo\");\n@@ -743,13 +743,24 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n \treturn res;\n }\n \n-static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n+static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n+\t\t\t\t\t       const char *path,\n+\t\t\t\t\t       int macro_ok)\n {\n \tstruct attr_stack *res;\n \tchar *buf, *sp;\n \tint lineno = 0;\n+\tconst struct index_state *to_read_from;\n \n-\tbuf = read_blob_data_from_index(use_index ? use_index : &the_index, path, NULL);\n+\t/*\n+\t * Temporary workaround for c24f3abace (apply: file commited\n+\t * with CRLF should roundtrip diff and apply - 2017-08-19)\n+\t */\n+\tto_read_from = use_index ? use_index : istate;\n+\tif (!to_read_from)\n+\t\treturn NULL;\n+\n+\tbuf = read_blob_data_from_index(to_read_from, path, NULL);\n \tif (!buf)\n \t\treturn NULL;\n \n@@ -768,15 +779,16 @@ static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)\n \treturn res;\n }\n \n-static struct attr_stack *read_attr(const char *path, int macro_ok)\n+static struct attr_stack *read_attr(const struct index_state *istate,\n+\t\t\t\t    const char *path, int macro_ok)\n {\n \tstruct attr_stack *res = NULL;\n \n \tif (direction == GIT_ATTR_INDEX) {\n-\t\tres = read_attr_from_index(path, macro_ok);\n+\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t} else if (!is_bare_repository()) {\n \t\tif (direction == GIT_ATTR_CHECKOUT) {\n-\t\t\tres = read_attr_from_index(path, macro_ok);\n+\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t\t\tif (!res)\n \t\t\t\tres = read_attr_from_file(path, macro_ok);\n \t\t} else if (direction == GIT_ATTR_CHECKIN) {\n@@ -788,7 +800,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)\n \t\t\t\t * We allow operation in a sparsely checked out\n \t\t\t\t * work tree, so read from it.\n \t\t\t\t */\n-\t\t\t\tres = read_attr_from_index(path, macro_ok);\n+\t\t\t\tres = read_attr_from_index(istate, path, macro_ok);\n \t\t}\n \t}\n \n@@ -859,7 +871,8 @@ static void push_stack(struct attr_stack **attr_stack_p,\n \t}\n }\n \n-static void bootstrap_attr_stack(struct attr_stack **stack)\n+static void bootstrap_attr_stack(const struct index_state *istate,\n+\t\t\t\t struct attr_stack **stack)\n {\n \tstruct attr_stack *e;\n \n@@ -883,7 +896,7 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n \t}\n \n \t/* root directory */\n-\te = read_attr(GITATTRIBUTES_FILE, 1);\n+\te = read_attr(istate, GITATTRIBUTES_FILE, 1);\n \tpush_stack(stack, e, xstrdup(\"\"), 0);\n \n \t/* info frame */\n@@ -896,7 +909,8 @@ static void bootstrap_attr_stack(struct attr_stack **stack)\n \tpush_stack(stack, e, NULL, 0);\n }\n \n-static void prepare_attr_stack(const char *path, int dirlen,\n+static void prepare_attr_stack(const struct index_state *istate,\n+\t\t\t       const char *path, int dirlen,\n \t\t\t       struct attr_stack **stack)\n {\n \tstruct attr_stack *info;\n@@ -917,7 +931,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n \t * .gitattributes in deeper directories to shallower ones,\n \t * and finally use the built-in set as the default.\n \t */\n-\tbootstrap_attr_stack(stack);\n+\tbootstrap_attr_stack(istate, stack);\n \n \t/*\n \t * Pop the \"info\" one that is always at the top of the stack.\n@@ -973,7 +987,7 @@ static void prepare_attr_stack(const char *path, int dirlen,\n \t\tstrbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));\n \t\tstrbuf_addf(&pathbuf, \"/%s\", GITATTRIBUTES_FILE);\n \n-\t\tnext = read_attr(pathbuf.buf, 0);\n+\t\tnext = read_attr(istate, pathbuf.buf, 0);\n \n \t\t/* reset the pathbuf to not include \"/.gitattributes\" */\n \t\tstrbuf_setlen(&pathbuf, len);\n@@ -1095,7 +1109,9 @@ static void determine_macros(struct all_attrs_item *all_attrs,\n  * If check->check_nr is non-zero, only attributes in check[] are collected.\n  * Otherwise all attributes are collected.\n  */\n-static void collect_some_attrs(const char *path, struct attr_check *check)\n+static void collect_some_attrs(const struct index_state *istate,\n+\t\t\t       const char *path,\n+\t\t\t       struct attr_check *check)\n {\n \tint i, pathlen, rem, dirlen;\n \tconst char *cp, *last_slash = NULL;\n@@ -1114,7 +1130,7 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n \t\tdirlen = 0;\n \t}\n \n-\tprepare_attr_stack(path, dirlen, &check->stack);\n+\tprepare_attr_stack(istate, path, dirlen, &check->stack);\n \tall_attrs_init(&g_attr_hashmap, check);\n \tdetermine_macros(check->all_attrs, check->stack);\n \n@@ -1136,11 +1152,13 @@ static void collect_some_attrs(const char *path, struct attr_check *check)\n \tfill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);\n }\n \n-int git_check_attr(const char *path, struct attr_check *check)\n+int git_check_attr(const struct index_state *istate,\n+\t\t   const char *path,\n+\t\t   struct attr_check *check)\n {\n \tint i;\n \n-\tcollect_some_attrs(path, check);\n+\tcollect_some_attrs(istate, path, check);\n \n \tfor (i = 0; i < check->nr; i++) {\n \t\tsize_t n = check->items[i].attr->attr_nr;\n@@ -1153,12 +1171,13 @@ int git_check_attr(const char *path, struct attr_check *check)\n \treturn 0;\n }\n \n-void git_all_attrs(const char *path, struct attr_check *check)\n+void git_all_attrs(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check)\n {\n \tint i;\n \n \tattr_check_reset(check);\n-\tcollect_some_attrs(path, check);\n+\tcollect_some_attrs(istate, path, check);\n \n \tfor (i = 0; i < check->all_attrs_nr; i++) {\n \t\tconst char *name = check->all_attrs[i].attr->name;\ndiff --git a/attr.h b/attr.h\nindex 46340010bb..3daca3c0cb 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -1,6 +1,8 @@\n #ifndef ATTR_H\n #define ATTR_H\n \n+struct index_state;\n+\n /* An attribute is a pointer to this opaque structure */\n struct git_attr;\n \n@@ -60,13 +62,15 @@ void attr_check_free(struct attr_check *check);\n  */\n const char *git_attr_name(const struct git_attr *);\n \n-int git_check_attr(const char *path, struct attr_check *check);\n+int git_check_attr(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check);\n \n /*\n  * Retrieve all attributes that apply to the specified path.\n  * check holds the attributes and their values.\n  */\n-void git_all_attrs(const char *path, struct attr_check *check);\n+void git_all_attrs(const struct index_state *istate,\n+\t\t   const char *path, struct attr_check *check);\n \n enum git_attr_direction {\n \tGIT_ATTR_CHECKIN,\n@@ -74,7 +78,7 @@ enum git_attr_direction {\n \tGIT_ATTR_INDEX\n };\n void git_attr_set_direction(enum git_attr_direction new_direction,\n-\t\t\t    struct index_state *istate);\n+\t\t\t    const struct index_state *istate);\n \n void attr_start(void);\n \ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 91444dc044..f7b59993d3 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -63,9 +63,9 @@ static void check_attr(const char *prefix,\n \t\tprefix_path(prefix, prefix ? strlen(prefix) : 0, file);\n \n \tif (collect_all) {\n-\t\tgit_all_attrs(full_path, check);\n+\t\tgit_all_attrs(&the_index, full_path, check);\n \t} else {\n-\t\tif (git_check_attr(full_path, check))\n+\t\tif (git_check_attr(&the_index, full_path, check))\n \t\t\tdie(\"git_check_attr died\");\n \t}\n \toutput_attr(check, file);\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 71056d8294..0a2e801549 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -945,7 +945,7 @@ static int no_try_delta(const char *path)\n \n \tif (!check)\n \t\tcheck = attr_check_initl(\"delta\", NULL);\n-\tif (git_check_attr(path, check))\n+\tif (git_check_attr(&the_index, path, check))\n \t\treturn 0;\n \tif (ATTR_FALSE(check->items[0].value))\n \t\treturn 1;\ndiff --git a/convert.c b/convert.c\nindex 64d0d30e08..9d5dc32564 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1302,7 +1302,7 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tgit_config(read_convert_config, NULL);\n \t}\n \n-\tif (!git_check_attr(path, check)) {\n+\tif (!git_check_attr(&the_index, path, check)) {\n \t\tstruct attr_check_item *ccheck = check->items;\n \t\tca->crlf_action = git_path_check_crlf(ccheck + 4);\n \t\tif (ca->crlf_action == CRLF_UNDEFINED)\ndiff --git a/dir.c b/dir.c\nindex ccf8b4975e..a541be3032 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -280,7 +280,7 @@ static int match_attrs(const char *name, int namelen,\n {\n \tint i;\n \n-\tgit_check_attr(name, item->attr_check);\n+\tgit_check_attr(&the_index, name, item->attr_check);\n \tfor (i = 0; i < item->attr_match_nr; i++) {\n \t\tconst char *value;\n \t\tint matched;\ndiff --git a/ll-merge.c b/ll-merge.c\nindex a6ad2ec12d..0e2800f7bb 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -371,7 +371,7 @@ int ll_merge(mmbuffer_t *result_buf,\n \tif (!check)\n \t\tcheck = attr_check_initl(\"merge\", \"conflict-marker-size\", NULL);\n \n-\tif (!git_check_attr(path, check)) {\n+\tif (!git_check_attr(&the_index, path, check)) {\n \t\tll_driver_name = check->items[0].value;\n \t\tif (check->items[1].value) {\n \t\t\tmarker_size = atoi(check->items[1].value);\n@@ -398,7 +398,7 @@ int ll_merge_marker_size(const char *path)\n \n \tif (!check)\n \t\tcheck = attr_check_initl(\"conflict-marker-size\", NULL);\n-\tif (!git_check_attr(path, check) && check->items[0].value) {\n+\tif (!git_check_attr(&the_index, path, check) && check->items[0].value) {\n \t\tmarker_size = atoi(check->items[0].value);\n \t\tif (marker_size <= 0)\n \t\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\ndiff --git a/userdiff.c b/userdiff.c\nindex a69241b25d..e835e78dd5 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -278,7 +278,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path)\n \t\tcheck = attr_check_initl(\"diff\", NULL);\n \tif (!path)\n \t\treturn NULL;\n-\tif (git_check_attr(path, check))\n+\tif (git_check_attr(&the_index, path, check))\n \t\treturn NULL;\n \n \tif (ATTR_TRUE(check->items[0].value))\ndiff --git a/ws.c b/ws.c\nindex a07caedd5a..5b67b426e7 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -78,7 +78,7 @@ unsigned whitespace_rule(const char *pathname)\n \tif (!attr_whitespace_rule)\n \t\tattr_whitespace_rule = attr_check_initl(\"whitespace\", NULL);\n \n-\tif (!git_check_attr(pathname, attr_whitespace_rule)) {\n+\tif (!git_check_attr(&the_index, pathname, attr_whitespace_rule)) {\n \t\tconst char *value;\n \n \t\tvalue = attr_whitespace_rule->items[0].value;\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349535","messageId":"20180606170042.GJ158365@google.com","threadId":"48624","inReplyTo":"20180606073933.14755-18-pclouds@gmail.com","subject":"Re: [PATCH v3 17/20] cache.c: remove an implicit dependency on the_index","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2018-06-06T17:00:42Z","receivedAt":"2018-06-06T17:05:49Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 06/06, Nguyễn Thái Ngọc Duy wrote:\n> Make some index API take an index_state instead of assuming the_index\n> in read-cache.c. All external call sites are converted blindly to keep\n> the patch simple and retain current behavior.  Individual call sites\n> may receive further updates to use the right index instead of the_index.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  apply.c            |  2 +-\n>  builtin/checkout.c |  2 +-\n>  builtin/difftool.c |  4 ++--\n>  builtin/reset.c    |  2 +-\n>  cache.h            |  5 +++--\n>  merge-recursive.c  |  2 +-\n>  read-cache.c       | 19 +++++++++++--------\n>  resolve-undo.c     |  2 +-\n>  8 files changed, 21 insertions(+), 17 deletions(-)\n> \n> diff --git a/apply.c b/apply.c\n> index 9720855590..811ff2ad5e 100644\n> --- a/apply.c\n> +++ b/apply.c\n> @@ -4090,7 +4090,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n>  \t\t\treturn error(_(\"sha1 information is lacking or useless \"\n>  \t\t\t\t       \"(%s).\"), name);\n>  \n> -\t\tce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);\n> +\t\tce = make_cache_entry(&the_index, patch->old_mode, oid.hash, name, 0, 0);\n>  \t\tif (!ce)\n>  \t\t\treturn error(_(\"make_cache_entry failed for path '%s'\"),\n>  \t\t\t\t     name);\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index f8c208cea1..3c8218304e 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -230,7 +230,7 @@ static int checkout_merged(int pos, const struct checkout *state)\n>  \tif (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))\n>  \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n>  \tfree(result_buf.ptr);\n> -\tce = make_cache_entry(mode, oid.hash, path, 2, 0);\n> +\tce = make_cache_entry(&the_index, mode, oid.hash, path, 2, 0);\n>  \tif (!ce)\n>  \t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n>  \tstatus = checkout_entry(ce, state, NULL);\n> diff --git a/builtin/difftool.c b/builtin/difftool.c\n> index bc97d4aef2..e34e75a42d 100644\n> --- a/builtin/difftool.c\n> +++ b/builtin/difftool.c\n> @@ -321,7 +321,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n>  \tstruct cache_entry *ce;\n>  \tint ret;\n>  \n> -\tce = make_cache_entry(mode, oid->hash, path, 0, 0);\n> +\tce = make_cache_entry(&the_index, mode, oid->hash, path, 0, 0);\n>  \tret = checkout_entry(ce, state, NULL);\n>  \n>  \tfree(ce);\n> @@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n>  \t\t\t\t * index.\n>  \t\t\t\t */\n>  \t\t\t\tstruct cache_entry *ce2 =\n> -\t\t\t\t\tmake_cache_entry(rmode, roid.hash,\n> +\t\t\t\t\tmake_cache_entry(&the_index, rmode, roid.hash,\n>  \t\t\t\t\t\t\t dst_path, 0, 0);\n>  \n>  \t\t\t\tadd_index_entry(&wtindex, ce2,\n> diff --git a/builtin/reset.c b/builtin/reset.c\n> index a862c70fab..0ea0a19d5e 100644\n> --- a/builtin/reset.c\n> +++ b/builtin/reset.c\n> @@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n>  \t\t\tcontinue;\n>  \t\t}\n>  \n> -\t\tce = make_cache_entry(one->mode, one->oid.hash, one->path,\n> +\t\tce = make_cache_entry(&the_index, one->mode, one->oid.hash, one->path,\n>  \t\t\t\t      0, 0);\n>  \t\tif (!ce)\n>  \t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\n> diff --git a/cache.h b/cache.h\n> index 89a107a7f7..5939233eb7 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -355,6 +355,7 @@ extern void free_name_hash(struct index_state *istate);\n>  #define unmerged_cache() unmerged_index(&the_index)\n>  #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))\n>  #define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))\n> +#define refresh_cache_entry(ce, flags) refresh_index_entry(&the_index, ce, flags)\n>  #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))\n>  #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))\n>  #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))\n> @@ -698,7 +699,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n>  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n>  extern int add_file_to_index(struct index_state *, const char *path, int flags);\n>  \n> -extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n> +extern struct cache_entry *make_cache_entry(struct index_state *istate,unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n\nminor nit: s/istate,unsigned/istate, unsigned/\n\n>  extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);\n>  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n>  extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);\n> @@ -751,7 +752,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n>  #define REFRESH_IGNORE_SUBMODULES\t0x0010\t/* ignore submodules */\n>  #define REFRESH_IN_PORCELAIN\t0x0020\t/* user friendly output, not \"needs update\" */\n>  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);\n> -extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);\n> +extern struct cache_entry *refresh_index_entry(struct index_state *istate, struct cache_entry *, unsigned int);\n>  \n>  /*\n>   * Opportunistically update the index but do not complain if we can't.\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index b404ebac7c..9280deb6a1 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n>  \tstruct cache_entry *ce;\n>  \tint ret;\n>  \n> -\tce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n> +\tce = make_cache_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n>  \tif (!ce)\n>  \t\treturn err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n>  \n> diff --git a/read-cache.c b/read-cache.c\n> index 12cc22d157..c083318aa7 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -745,9 +745,11 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n>  \treturn add_to_index(istate, path, &st, flags);\n>  }\n>  \n> -struct cache_entry *make_cache_entry(unsigned int mode,\n> -\t\tconst unsigned char *sha1, const char *path, int stage,\n> -\t\tunsigned int refresh_options)\n> +struct cache_entry *make_cache_entry(struct index_state *istate,\n> +\t\t\t\t     unsigned int mode,\n> +\t\t\t\t     const unsigned char *sha1,\n> +\t\t\t\t     const char *path, int stage,\n> +\t\t\t\t     unsigned int refresh_options)\n>  {\n>  \tint size, len;\n>  \tstruct cache_entry *ce, *ret;\n> @@ -767,7 +769,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n>  \tce->ce_namelen = len;\n>  \tce->ce_mode = create_ce_mode(mode);\n>  \n> -\tret = refresh_cache_entry(ce, refresh_options);\n> +\tret = refresh_index_entry(istate, ce, refresh_options);\n>  \tif (ret != ce)\n>  \t\tfree(ce);\n>  \treturn ret;\n> @@ -1415,7 +1417,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n>  \t\tif (ignore_submodules && S_ISGITLINK(ce->ce_mode))\n>  \t\t\tcontinue;\n>  \n> -\t\tif (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))\n> +\t\tif (pathspec && !ce_path_match(istate, ce, pathspec, seen))\n>  \t\t\tfiltered = 1;\n>  \n>  \t\tif (ce_stage(ce)) {\n> @@ -1473,10 +1475,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n>  \treturn has_errors;\n>  }\n>  \n> -struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n> -\t\t\t\t\t       unsigned int options)\n> +struct cache_entry *refresh_index_entry(struct index_state *istate,\n> +\t\t\t\t\tstruct cache_entry *ce,\n> +\t\t\t\t\tunsigned int options)\n>  {\n> -\treturn refresh_cache_ent(&the_index, ce, options, NULL, NULL);\n> +\treturn refresh_cache_ent(istate, ce, options, NULL, NULL);\n>  }\n>  \n>  \n> diff --git a/resolve-undo.c b/resolve-undo.c\n> index 5e4c8c5f75..9c45fe5d1d 100644\n> --- a/resolve-undo.c\n> +++ b/resolve-undo.c\n> @@ -146,7 +146,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n>  \t\tstruct cache_entry *nce;\n>  \t\tif (!ru->mode[i])\n>  \t\t\tcontinue;\n> -\t\tnce = make_cache_entry(ru->mode[i], ru->oid[i].hash,\n> +\t\tnce = make_cache_entry(&the_index, ru->mode[i], ru->oid[i].hash,\n>  \t\t\t\t       name, i + 1, 0);\n>  \t\tif (matched)\n>  \t\t\tnce->ce_flags |= CE_MATCHED;\n> -- \n> 2.18.0.rc0.333.g22e6ee6cdf\n> \n\n-- \nBrandon Williams\n"},{"id":"349602","messageId":"CABPp-BFzOkX_uSyiVH-S8mqxeOin0xcYR-EzXUtvcdN7dGhidQ@mail.gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-5-pclouds@gmail.com","subject":"Re: [PATCH v4 04/23] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T07:41:49Z","receivedAt":"2018-06-07T07:41:53Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Subject line: unpack-trees rather than unpack-tress.\n\n\n\nOn Wed, Jun 6, 2018 at 9:49 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\n> the_index when running the exclude machinery. fba92be8f7 helps show\n> this problem clearer because unpack-trees operation is supposed to\n> work on whatever index the caller specifies... not specifically\n> the_index.\n>\n> Update the code to use \"istate\" argument that's originally from\n> mark_new_skip_worktree(). From the call sites, both in unpack_trees(),\n> you can see that this function works on two separate indexes:\n> o->src_index and o->result. The second mark_new_skip_worktree() so far\n> has incorecctly applied exclude rules on o->src_index instead of\n> o->result. It's unclear what is the consequences of this, but it's\n> definitely wrong.\n>\n> [1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n>     2017-05-05)\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n\nA somewhat curious finding: when I was rebuilding and re-testing all\n23 patches, I got a failure on this patch in test 31 of\nt7063-status-untracked-cache.sh. I did not get any test failures with\nany of the other patches.  However, after re-running that test or the\nwhole suite half a dozen times with just up to this patch applied, I\nwas not able to trigger the failure again.  Is there a rare race in\nthat testcase?  I certainly don't see anything in this patch that\nappears problematic, and the fact that I couldn't readily reproduce\nsuggests it could well have been there before any of these patches.\n\nEverything else in the patch looks fine to me.\n"},{"id":"349603","messageId":"CABPp-BEngspJMEpwoiTq7SCdsQt7fOT_uePS3c6nRxTVqOnNeQ@mail.gmail.com","threadId":"48624","inReplyTo":"20180606165016.3285-1-pclouds@gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T07:44:27Z","receivedAt":"2018-06-07T07:44:31Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 6, 2018 at 9:49 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> v4 fixes some commit messages and killed a couple more the_index\n> references after I tried to merge this with 'pu'\n\nThanks for tackling this.  The first 8 patches look good to me other\nthan the typo I pointed out on patch 4.  However, my eyes glazed over\na bit on the attr.c stuff in patch 7 that you specifically mentioned\nin the commit message, so my \"looks good\" doesn't count for as much on\nthat one.\n\nI'm getting sleepy, but I'll try to circle back and look over the rest\nof the patches in the next few days.\n"},{"id":"349644","messageId":"CACsJy8AwjMsCR=gbT1ZLbEwve7hzuPBF7tT7m+P1DJ4rRx_jrw@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BFzOkX_uSyiVH-S8mqxeOin0xcYR-EzXUtvcdN7dGhidQ@mail.gmail.com","subject":"Re: [PATCH v4 04/23] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-07T15:11:08Z","receivedAt":"2018-06-07T15:11:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 7, 2018 at 9:41 AM, Elijah Newren <newren@gmail.com> wrote:\n> Subject line: unpack-trees rather than unpack-tress.\n>\n>\n>\n> On Wed, Jun 6, 2018 at 9:49 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\n>> the_index when running the exclude machinery. fba92be8f7 helps show\n>> this problem clearer because unpack-trees operation is supposed to\n>> work on whatever index the caller specifies... not specifically\n>> the_index.\n>>\n>> Update the code to use \"istate\" argument that's originally from\n>> mark_new_skip_worktree(). From the call sites, both in unpack_trees(),\n>> you can see that this function works on two separate indexes:\n>> o->src_index and o->result. The second mark_new_skip_worktree() so far\n>> has incorecctly applied exclude rules on o->src_index instead of\n>> o->result. It's unclear what is the consequences of this, but it's\n>> definitely wrong.\n>>\n>> [1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n>>     2017-05-05)\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>\n> A somewhat curious finding: when I was rebuilding and re-testing all\n> 23 patches, I got a failure on this patch in test 31 of\n> t7063-status-untracked-cache.sh. I did not get any test failures with\n> any of the other patches.  However, after re-running that test or the\n> whole suite half a dozen times with just up to this patch applied, I\n> was not able to trigger the failure again.  Is there a rare race in\n> that testcase?\n\nUntracked cache tests are very time-sensitive. I'll try to run and\nre-run them a couple times to understand more. Thanks for pointing it\nout.\n-- \nDuy\n"},{"id":"349721","messageId":"CACsJy8Dk8jS-m9vPdHY3r8iGV0DA7v_V8uOFn7+7WqTev-ajdg@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8AwjMsCR=gbT1ZLbEwve7hzuPBF7tT7m+P1DJ4rRx_jrw@mail.gmail.com","subject":"Re: [PATCH v4 04/23] unpack-tress: convert clear_ce_flags* to avoid the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-08T15:58:01Z","receivedAt":"2018-06-08T15:58:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 7, 2018 at 5:11 PM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Thu, Jun 7, 2018 at 9:41 AM, Elijah Newren <newren@gmail.com> wrote:\n> > Subject line: unpack-trees rather than unpack-tress.\n> >\n> >\n> >\n> > On Wed, Jun 6, 2018 at 9:49 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> >> Prior to fba92be8f7, this code implicitly (and incorrectly) assumes\n> >> the_index when running the exclude machinery. fba92be8f7 helps show\n> >> this problem clearer because unpack-trees operation is supposed to\n> >> work on whatever index the caller specifies... not specifically\n> >> the_index.\n> >>\n> >> Update the code to use \"istate\" argument that's originally from\n> >> mark_new_skip_worktree(). From the call sites, both in unpack_trees(),\n> >> you can see that this function works on two separate indexes:\n> >> o->src_index and o->result. The second mark_new_skip_worktree() so far\n> >> has incorecctly applied exclude rules on o->src_index instead of\n> >> o->result. It's unclear what is the consequences of this, but it's\n> >> definitely wrong.\n> >>\n> >> [1] fba92be8f7 (dir: convert is_excluded_from_list to take an index -\n> >>     2017-05-05)\n> >>\n> >> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> >\n> > A somewhat curious finding: when I was rebuilding and re-testing all\n> > 23 patches, I got a failure on this patch in test 31 of\n> > t7063-status-untracked-cache.sh. I did not get any test failures with\n> > any of the other patches.  However, after re-running that test or the\n> > whole suite half a dozen times with just up to this patch applied, I\n> > was not able to trigger the failure again.  Is there a rare race in\n> > that testcase?\n>\n> Untracked cache tests are very time-sensitive. I'll try to run and\n> re-run them a couple times to understand more. Thanks for pointing it\n> out.\n\nafter hours of running tests, either with full 23 patches or just the\nfirst 4, and failing to catch the failure, i declare (or more like,\npray) that you ran into a crack of time that led to a race. I'll take\nno action on this, but I'll remember this and watch out for untracked\ncache related mails for some time.\n-- \nDuy\n"},{"id":"349813","messageId":"CABPp-BGuXuyKstVY-sid5tFiVykpkYLGnjuYZU2nv2Sg3zZSSw@mail.gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-10-pclouds@gmail.com","subject":"Re: [PATCH v4 15/23] attr: remove index from git_attr_set_direction()","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-09T17:57:35Z","receivedAt":"2018-06-09T17:57:39Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 6, 2018 at 10:02 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Since attr checking API now take the index, there's no need to set an\n> index in advance with this call. Most call sites are straightforward\n> because they either pass the_index or NULL (which defaults back to\n> the_index previously). There's only one suspicious call site in\n> unpack-trees.c where it sets a different index.\n>\n> This code in unpack-trees is about to checking out entries from the\n\nminor nit: s/checking/check/ ?\n\n...\n\n> diff --git a/attr.c b/attr.c\n> index 863fad3bd1..98e4953f6e 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -708,10 +708,8 @@ static struct attr_stack *read_attr_from_array(const char **list)\n>   * another thread could potentially be calling into the attribute system.\n>   */\n>  static enum git_attr_direction direction;\n> -static const struct index_state *use_index;\n>\n> -void git_attr_set_direction(enum git_attr_direction new_direction,\n> -                           const struct index_state *istate)\n> +void git_attr_set_direction(enum git_attr_direction new_direction)\n>  {\n>         if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)\n>                 BUG(\"non-INDEX attr direction in a bare repo\");\n> @@ -720,7 +718,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction,\n>                 drop_all_attr_stacks();\n>\n>         direction = new_direction;\n> -       use_index = istate;\n>  }\n>\n>  static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)\n> @@ -750,17 +747,11 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,\n>         struct attr_stack *res;\n>         char *buf, *sp;\n>         int lineno = 0;\n> -       const struct index_state *to_read_from;\n>\n> -       /*\n> -        * Temporary workaround for c24f3abace (apply: file commited\n> -        * with CRLF should roundtrip diff and apply - 2017-08-19)\n> -        */\n> -       to_read_from = use_index ? use_index : istate;\n> -       if (!to_read_from)\n> +       if (!istate)\n>                 return NULL;\n>\n> -       buf = read_blob_data_from_index(to_read_from, path, NULL);\n> +       buf = read_blob_data_from_index(istate, path, NULL);\n\nThis code is much clearer and easier to reason about than stashing off\nuse_index.  I had to dig for a bit through history to try to\nunderstand the old code and why it was written that way, but the new\ncode just makes sense.\n"},{"id":"349817","messageId":"CABPp-BGn8mz5tPrVk6fX3JKcaSuz4_XQSsSmvEMT_H5i4mF2Lg@mail.gmail.com","threadId":"48624","inReplyTo":"20180606170243.4169-12-pclouds@gmail.com","subject":"Re: [PATCH v4 17/23] read-cache.c: remove an implicit dependency on the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-09T18:10:23Z","receivedAt":"2018-06-09T18:10:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 6, 2018 at 10:02 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index b404ebac7c..4f054d6dbb 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n>         struct cache_entry *ce;\n>         int ret;\n>\n> -       ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n> +       ce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n>         if (!ce)\n>                 return err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n\nThere's also a refresh_cache_entry() call about ten lines after this;\nsince you converted all other make_cache_entry() and\nrefresh_cache_entry() calls in this patch, I'm curious if that one was\nleft out for a reason or was just an oversight.\n\nThere are also a lot of add_cache_entry() calls in this function.  I'm\nguessing we should either convert all of those too, or just change\nback this particular make_index_entry to make_cache_entry() as it was;\nit seems weird to have a mix of explicit the_index and implicit\nthe_index usages in the same function.  If we convert them all,\nperhaps we should consider having merge_options store the index we're\nworking on?  If you want to punt this until later or leave it for me\nwhile I make all my ongoing merge-recursive changes, that's fine.\nJust thought I'd point it out.\n"},{"id":"349819","messageId":"CACsJy8DoU_qkghnNWKPy9+z=Lktg6jSbBFk6xEUFwAUos4Gu5A@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BGn8mz5tPrVk6fX3JKcaSuz4_XQSsSmvEMT_H5i4mF2Lg@mail.gmail.com","subject":"Re: [PATCH v4 17/23] read-cache.c: remove an implicit dependency on the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-09T18:45:38Z","receivedAt":"2018-06-09T18:46:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Jun 9, 2018 at 8:10 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> On Wed, Jun 6, 2018 at 10:02 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> > diff --git a/merge-recursive.c b/merge-recursive.c\n> > index b404ebac7c..4f054d6dbb 100644\n> > --- a/merge-recursive.c\n> > +++ b/merge-recursive.c\n> > @@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n> >         struct cache_entry *ce;\n> >         int ret;\n> >\n> > -       ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n> > +       ce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n> >         if (!ce)\n> >                 return err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n>\n> There's also a refresh_cache_entry() call about ten lines after this;\n> since you converted all other make_cache_entry() and\n> refresh_cache_entry() calls in this patch, I'm curious if that one was\n> left out for a reason or was just an oversight.\n\nAh I didn't mean to convert or kill refresh_cache_entry(), not outside\nread-cache.c. I rely on NO_THE_INDEX_COMPATIBILITY_MACROS to catch\n*cache* functions and if we set it in this file, we're going to have a\nlot more work to do and plenty of the_index will show up.\n\n> There are also a lot of add_cache_entry() calls in this function.  I'm\n> guessing we should either convert all of those too, or just change\n> back this particular make_index_entry to make_cache_entry() as it was;\n> it seems weird to have a mix of explicit the_index and implicit\n> the_index usages in the same function.\n\nYes some files still have the mix of the_index and *cache*(). This one\nand apply.c come to mind. There's more work to do to kill all\nthe_index outside builtin/\n\n> If we convert them all,\n> perhaps we should consider having merge_options store the index we're\n> working on?  If you want to punt this until later or leave it for me\n> while I make all my ongoing merge-recursive changes, that's fine.\n> Just thought I'd point it out.\n\nRight you're updating merge-recursive.c, I'd love it if you could\ndefine NO_THE_INDEX_COMPATIBILITY_MACROS here. Yes merge_options\nsounds like a good place to tell merge-recursive where to get a struct\nindex_state.\n-- \nDuy\n"},{"id":"349821","messageId":"CABPp-BGhS1_4dh=sMb56qaunQXkX=hu4foPV49Np-P8eZeCR5w@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8DoU_qkghnNWKPy9+z=Lktg6jSbBFk6xEUFwAUos4Gu5A@mail.gmail.com","subject":"Re: [PATCH v4 17/23] read-cache.c: remove an implicit dependency on the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-09T19:48:20Z","receivedAt":"2018-06-09T19:50:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sat, Jun 9, 2018 at 11:45 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Sat, Jun 9, 2018 at 8:10 PM Elijah Newren <newren@gmail.com> wrote:\n>>\n>> On Wed, Jun 6, 2018 at 10:02 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> > diff --git a/merge-recursive.c b/merge-recursive.c\n>> > index b404ebac7c..4f054d6dbb 100644\n>> > --- a/merge-recursive.c\n>> > +++ b/merge-recursive.c\n>> > @@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,\n>> >         struct cache_entry *ce;\n>> >         int ret;\n>> >\n>> > -       ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);\n>> > +       ce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n>> >         if (!ce)\n>> >                 return err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n>>\n>> There's also a refresh_cache_entry() call about ten lines after this;\n>> since you converted all other make_cache_entry() and\n>> refresh_cache_entry() calls in this patch, I'm curious if that one was\n>> left out for a reason or was just an oversight.\n>\n> Ah I didn't mean to convert or kill refresh_cache_entry(), not outside\n> read-cache.c. I rely on NO_THE_INDEX_COMPATIBILITY_MACROS to catch\n> *cache* functions and if we set it in this file, we're going to have a\n> lot more work to do and plenty of the_index will show up.\n>\n>> There are also a lot of add_cache_entry() calls in this function.  I'm\n>> guessing we should either convert all of those too, or just change\n>> back this particular make_index_entry to make_cache_entry() as it was;\n>> it seems weird to have a mix of explicit the_index and implicit\n>> the_index usages in the same function.\n>\n> Yes some files still have the mix of the_index and *cache*(). This one\n> and apply.c come to mind. There's more work to do to kill all\n> the_index outside builtin/\n\nYeah, there's also low-level common files like sha1-file.c or\nll-merge.c which now have &the_index in them (or more references to\nit).  Clearly those need to be propagated up, but as you say, there's\nmore work to do.  Your patch series just moves things in the right\ndirection.\n\n>> If we convert them all,\n>> perhaps we should consider having merge_options store the index we're\n>> working on?  If you want to punt this until later or leave it for me\n>> while I make all my ongoing merge-recursive changes, that's fine.\n>> Just thought I'd point it out.\n>\n> Right you're updating merge-recursive.c, I'd love it if you could\n> define NO_THE_INDEX_COMPATIBILITY_MACROS here. Yes merge_options\n> sounds like a good place to tell merge-recursive where to get a struct\n> index_state.\n\nSure, I can tackle that.\n"},{"id":"349822","messageId":"CABPp-BGa+v2x1oeitVDMkQf3qFWx6kUT4wdWhCxjWwPyaW=3bg@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BEngspJMEpwoiTq7SCdsQt7fOT_uePS3c6nRxTVqOnNeQ@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-09T19:58:40Z","receivedAt":"2018-06-09T19:58:44Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 7, 2018 at 12:44 AM, Elijah Newren <newren@gmail.com> wrote:\n> On Wed, Jun 6, 2018 at 9:49 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> v4 fixes some commit messages and killed a couple more the_index\n>> references after I tried to merge this with 'pu'\n>\n> Thanks for tackling this.  The first 8 patches look good to me other\n> than the typo I pointed out on patch 4.  However, my eyes glazed over\n> a bit on the attr.c stuff in patch 7 that you specifically mentioned\n> in the commit message, so my \"looks good\" doesn't count for as much on\n> that one.\n\nI re-read the attr.c stuff in patch 7; looks good to me and the new\nseries makes the code much more readable in the end.\n\n> I'm getting sleepy, but I'll try to circle back and look over the rest\n> of the patches in the next few days.\n\nI read over the rest.  Found a small grammatical error in a commit\nmessage.  Found multiple places that still need conversion, from\npushing up &the_index usages to callers of ll-merge.c and sha1-file.c\ninstead of having them in those files, to mixes of _cache_ and _index_\nfunctions as in apply.c and merge-recursive.c.  However, Duy pointed\nout there was more work to do, and this series is a step in the right\ndirection and a good start.\n"},{"id":"349906","messageId":"CACsJy8Ba74iSPf4_zFxuV=_uNJgL6Z2QunOvAvi3qab-6EWi5g@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BGa+v2x1oeitVDMkQf3qFWx6kUT4wdWhCxjWwPyaW=3bg@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-11T16:05:55Z","receivedAt":"2018-06-11T16:06:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Jun 9, 2018 at 9:58 PM Elijah Newren <newren@gmail.com> wrote:\n> I read over the rest.  Found a small grammatical error in a commit\n> message.  Found multiple places that still need conversion, from\n> pushing up &the_index usages to callers of ll-merge.c and sha1-file.c\n> instead of having them in those files, to mixes of _cache_ and _index_\n> functions as in apply.c and merge-recursive.c.  However, Duy pointed\n> out there was more work to do,\n\nYes. This is just fyi, 40 patches later, i'm down to leaving the_index\nin three files outside builtin/: merge-recursive, notes-merge.c and\ntransport.c. Even after the conversion we may need some more follow-up\npatches because it now shows places where we should _not_ touch the\nindex at all, which may involve not simply passing NULL index_state to\nsome functions, but fixing them up to tolerate NULL index_state. So\nit's going to be a few patch series until the_index is gone for good\n[1].\n\n[1] but like cheap horror movies, there's always a sequel:\nthe_repository is still spread in many places and hides dependencies\nin the same way. We can't do anything about it though until struct\nrepository conversion is more or less complete.\n-- \nDuy\n"},{"id":"349908","messageId":"CABPp-BHYm57n=ufg_SqmA-UnOEMivWJZytnPPSU3WSYNeEph0g@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8Ba74iSPf4_zFxuV=_uNJgL6Z2QunOvAvi3qab-6EWi5g@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T16:11:24Z","receivedAt":"2018-06-11T16:11:29Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Duy,\n\nOn Mon, Jun 11, 2018 at 9:05 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Sat, Jun 9, 2018 at 9:58 PM Elijah Newren <newren@gmail.com> wrote:\n>> I read over the rest.  Found a small grammatical error in a commit\n>> message.  Found multiple places that still need conversion, from\n>> pushing up &the_index usages to callers of ll-merge.c and sha1-file.c\n>> instead of having them in those files, to mixes of _cache_ and _index_\n>> functions as in apply.c and merge-recursive.c.  However, Duy pointed\n>> out there was more work to do,\n>\n> Yes. This is just fyi, 40 patches later, i'm down to leaving the_index\n> in three files outside builtin/: merge-recursive, notes-merge.c and\n> transport.c. Even after the conversion we may need some more follow-up\n> patches because it now shows places where we should _not_ touch the\n> index at all, which may involve not simply passing NULL index_state to\n> some functions, but fixing them up to tolerate NULL index_state. So\n> it's going to be a few patch series until the_index is gone for good\n> [1].\n>\n> [1] but like cheap horror movies, there's always a sequel:\n> the_repository is still spread in many places and hides dependencies\n> in the same way. We can't do anything about it though until struct\n> repository conversion is more or less complete.\n\nI was just about to send you an email to ask if you were continuing on\nwith the series.  I need diff-lib.c converted in order to make the\nchanges Junio suggested to index_has_changes at\nhttps://public-inbox.org/git/xmqqvaaz5jcv.fsf@gitster-ct.c.googlers.com/.\nSince you're already working on that, I won't duplicate your effort.\nThanks for tackling all of this.  :-)\n"},{"id":"349912","messageId":"CACsJy8AOzwu+GJLTsGtN0dCnwxoRBQYpM6gzVebN++zjpXNu7w@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BHYm57n=ufg_SqmA-UnOEMivWJZytnPPSU3WSYNeEph0g@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-11T16:24:50Z","receivedAt":"2018-06-11T16:25:21Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jun 11, 2018 at 6:11 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> Hi Duy,\n>\n> On Mon, Jun 11, 2018 at 9:05 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> > On Sat, Jun 9, 2018 at 9:58 PM Elijah Newren <newren@gmail.com> wrote:\n> >> I read over the rest.  Found a small grammatical error in a commit\n> >> message.  Found multiple places that still need conversion, from\n> >> pushing up &the_index usages to callers of ll-merge.c and sha1-file.c\n> >> instead of having them in those files, to mixes of _cache_ and _index_\n> >> functions as in apply.c and merge-recursive.c.  However, Duy pointed\n> >> out there was more work to do,\n> >\n> > Yes. This is just fyi, 40 patches later, i'm down to leaving the_index\n> > in three files outside builtin/: merge-recursive, notes-merge.c and\n> > transport.c. Even after the conversion we may need some more follow-up\n> > patches because it now shows places where we should _not_ touch the\n> > index at all, which may involve not simply passing NULL index_state to\n> > some functions, but fixing them up to tolerate NULL index_state. So\n> > it's going to be a few patch series until the_index is gone for good\n> > [1].\n\nAnd I forgot one thing. There are other hidden dependencies as well.\nLike hold_locked_index() will assume $GIT_DIR/index, but when you take\nan arbitrary 'struct index_state *' I don't think you can make that\nkind of assumption. This is mostly a note to myself in case I forget\nit again.\n\n> >\n> > [1] but like cheap horror movies, there's always a sequel:\n> > the_repository is still spread in many places and hides dependencies\n> > in the same way. We can't do anything about it though until struct\n> > repository conversion is more or less complete.\n>\n> I was just about to send you an email to ask if you were continuing on\n> with the series.  I need diff-lib.c converted in order to make the\n> changes Junio suggested to index_has_changes at\n> https://public-inbox.org/git/xmqqvaaz5jcv.fsf@gitster-ct.c.googlers.com/.\n> Since you're already working on that, I won't duplicate your effort.\n> Thanks for tackling all of this.  :-)\n\nI'm not sure if it's possible to cherry pick this patch to continue\nyour work (because of dependencies between patches) but it's\nhttps://gitlab.com/pclouds/git/commits/really-kill-the-index, commit\n\"merge.c: remove...\".\n\nOr you just leave it to me, update has_index_changes() to always take\n'struct index_state *' and just pass &the_index in all uninteresting\nplaces. (Or not update at all if it's really not needed for your work)\n\nWhat about merge-recursive.c? Given that this whole thing will take\nmany release cycles to finish, your work may get merged before mine\nand I could do the conversion now (and resolve conflicts and resubmit\nlater). Of course if you like to keep merge-recursive.c the_index-free\nnow, I will not stop you ;-)\n-- \nDuy\n"},{"id":"349913","messageId":"CABPp-BES3XFmM16TTqRxnCkO=sbqkSuWf6gBsbLYya8MzogMgQ@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8AOzwu+GJLTsGtN0dCnwxoRBQYpM6gzVebN++zjpXNu7w@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T16:44:50Z","receivedAt":"2018-06-11T16:44:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Jun 11, 2018 at 9:24 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> I was just about to send you an email to ask if you were continuing on\n>> with the series.  I need diff-lib.c converted in order to make the\n>> changes Junio suggested to index_has_changes at\n>> https://public-inbox.org/git/xmqqvaaz5jcv.fsf@gitster-ct.c.googlers.com/.\n>> Since you're already working on that, I won't duplicate your effort.\n>> Thanks for tackling all of this.  :-)\n>\n> I'm not sure if it's possible to cherry pick this patch to continue\n> your work (because of dependencies between patches) but it's\n> https://gitlab.com/pclouds/git/commits/really-kill-the-index, commit\n> \"merge.c: remove...\".\n>\n> Or you just leave it to me, update has_index_changes() to always take\n> 'struct index_state *' and just pass &the_index in all uninteresting\n> places. (Or not update at all if it's really not needed for your work)\n\nActually, I'm thinking maybe I should just push that series forward\nwithout changing index_has_changes() to take an istate (since it's not\nactually important to that series yet), and then once your changes\nland, then update the function appropriately.  (Or maybe your series\nwill update that function too.)\n\n> What about merge-recursive.c? Given that this whole thing will take\n> many release cycles to finish, your work may get merged before mine\n> and I could do the conversion now (and resolve conflicts and resubmit\n> later). Of course if you like to keep merge-recursive.c the_index-free\n> now, I will not stop you ;-)\n\nI was just worried that since I was making changes in\nmerge-recursive.c that it'd cause you conflict pain, so I offered to\nconvert it.  If that pain doesn't bother you, feel free to do the\nconversion and we'll just work through the minor conflicts as we go.\nBesides, sounds like you've converted nearly all of git, so it may\nmake sense to just keep it together in one big series.\n"},{"id":"349915","messageId":"CACsJy8A17oqM4wTQo8A=KMcStGQ=xdQuq8pORVGEezPZJxHuOA@mail.gmail.com","threadId":"48624","inReplyTo":"CABPp-BES3XFmM16TTqRxnCkO=sbqkSuWf6gBsbLYya8MzogMgQ@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-11T16:49:00Z","receivedAt":"2018-06-11T16:49:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jun 11, 2018 at 6:44 PM Elijah Newren <newren@gmail.com> wrote:\n> > What about merge-recursive.c? Given that this whole thing will take\n> > many release cycles to finish, your work may get merged before mine\n> > and I could do the conversion now (and resolve conflicts and resubmit\n> > later). Of course if you like to keep merge-recursive.c the_index-free\n> > now, I will not stop you ;-)\n>\n> I was just worried that since I was making changes in\n> merge-recursive.c that it'd cause you conflict pain, so I offered to\n> convert it.  If that pain doesn't bother you, feel free to do the\n> conversion and we'll just work through the minor conflicts as we go.\n> Besides, sounds like you've converted nearly all of git, so it may\n> make sense to just keep it together in one big series.\n\nOK let's just \"quickly\" get your series in then. I still have a few\nfiles to go and a couple more places to look back and ponder. I'm in\nno hurry to convert merge-recursive now :D\n-- \nDuy\n"},{"id":"349926","messageId":"CACsJy8CDwGwiVk_Y-dbDowYjJH3iDQHntb_HvwK7R5-4Gy4SzA@mail.gmail.com","threadId":"48624","inReplyTo":"CACsJy8Ba74iSPf4_zFxuV=_uNJgL6Z2QunOvAvi3qab-6EWi5g@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-11T18:20:03Z","receivedAt":"2018-06-11T18:20:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jun 11, 2018 at 6:05 PM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Sat, Jun 9, 2018 at 9:58 PM Elijah Newren <newren@gmail.com> wrote:\n> > I read over the rest.  Found a small grammatical error in a commit\n> > message.  Found multiple places that still need conversion, from\n> > pushing up &the_index usages to callers of ll-merge.c and sha1-file.c\n> > instead of having them in those files, to mixes of _cache_ and _index_\n> > functions as in apply.c and merge-recursive.c.  However, Duy pointed\n> > out there was more work to do,\n>\n> Yes. This is just fyi, 40 patches later, ...\n\nJunio, just to be clear, I think I'll withdraw this 23-patch series\n(reviews are still welcome though). It does fix some potential bugs\nbut it's not that critical. This will let me merge it with the other\n40+ patches and reorganize better (after all this started out as a\nsingle rfc patch, I didn't realize what I got myself into)\n\n> i'm down to leaving the_index\n> in three files outside builtin/: merge-recursive, notes-merge.c and\n> transport.c. Even after the conversion we may need some more follow-up\n> patches because it now shows places where we should _not_ touch the\n> index at all, which may involve not simply passing NULL index_state to\n> some functions, but fixing them up to tolerate NULL index_state. So\n> it's going to be a few patch series until the_index is gone for good\n> [1].\n>\n> [1] but like cheap horror movies, there's always a sequel:\n> the_repository is still spread in many places and hides dependencies\n> in the same way. We can't do anything about it though until struct\n> repository conversion is more or less complete.\n> --\n> Duy\n\n\n\n-- \nDuy\n"},{"id":"350163","messageId":"20180614171849.GA7675@duynguyen.home","threadId":"48624","inReplyTo":"CACsJy8A17oqM4wTQo8A=KMcStGQ=xdQuq8pORVGEezPZJxHuOA@mail.gmail.com","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-14T17:18:49Z","receivedAt":"2018-06-14T17:18:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jun 11, 2018 at 06:49:00PM +0200, Duy Nguyen wrote:\n> On Mon, Jun 11, 2018 at 6:44 PM Elijah Newren <newren@gmail.com> wrote:\n> > > What about merge-recursive.c? Given that this whole thing will take\n> > > many release cycles to finish, your work may get merged before mine\n> > > and I could do the conversion now (and resolve conflicts and resubmit\n> > > later). Of course if you like to keep merge-recursive.c the_index-free\n> > > now, I will not stop you ;-)\n> >\n> > I was just worried that since I was making changes in\n> > merge-recursive.c that it'd cause you conflict pain, so I offered to\n> > convert it.  If that pain doesn't bother you, feel free to do the\n> > conversion and we'll just work through the minor conflicts as we go.\n> > Besides, sounds like you've converted nearly all of git, so it may\n> > make sense to just keep it together in one big series.\n> \n> OK let's just \"quickly\" get your series in then. I still have a few\n> files to go and a couple more places to look back and ponder. I'm in\n> no hurry to convert merge-recursive now :D\n\nActually could you quickly check if I pass the right index in the\nfollowing patch? I realize you only have one extra index, but I don't\nknow if it gets passed elsewhere and in some function I'm supposed to\nuse another index than the default \"o->repo->index\". Sometimes\no->repo->index is not the correct answer.\n\nIt takes many patches to get to this stage, so if you diff context\nlooks so strange to you, just ignore this for now. I'll eventually\nsend this one out in a series.\n\nPS. I put a 'struct repository *' in 'struct merge_options' instead\nbecause it turns out we do need full repo struct in some function.\n\n-- 8< --\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 3961878871..5d2ff9aa8c 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1592,7 +1592,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa\n \t * changes.\n \t */\n \n-\tinit_merge_options(&o);\n+\tinit_merge_options(&o, the_repository);\n \n \to.branch1 = \"HEAD\";\n \ttheir_tree_name = xstrfmt(\"%.*s\", linelen(state->msg), state->msg);\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 528c6de7e1..4fd53cec6e 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -570,7 +570,7 @@ static int merge_working_tree(const struct checkout_opts *opts,\n \t\t\t * a pain; plumb in an option to set\n \t\t\t * o.renormalize?\n \t\t\t */\n-\t\t\tinit_merge_options(&o);\n+\t\t\tinit_merge_options(&o, the_repository);\n \t\t\to.verbosity = 0;\n \t\t\twork = write_tree_from_memory(&o);\n \ndiff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c\nindex 0dd9021958..c4a9e575d6 100644\n--- a/builtin/merge-recursive.c\n+++ b/builtin/merge-recursive.c\n@@ -28,7 +28,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)\n \tstruct merge_options o;\n \tstruct commit *result;\n \n-\tinit_merge_options(&o);\n+\tinit_merge_options(&o, the_repository);\n \tif (argv[0] && ends_with(argv[0], \"-subtree\"))\n \t\to.subtree_shift = \"\";\n \ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex db460a35cf..2ebd939b76 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -671,7 +671,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \t\t\treturn 2;\n \t\t}\n \n-\t\tinit_merge_options(&o);\n+\t\tinit_merge_options(&o, the_repository);\n \t\tif (!strcmp(strategy, \"subtree\"))\n \t\t\to.subtree_shift = \"\";\n \ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a296ba3874..fd6556b6de 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -309,26 +309,29 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)\n }\n \n static int add_cacheinfo(struct merge_options *o,\n-\t\tunsigned int mode, const struct object_id *oid,\n-\t\tconst char *path, int stage, int refresh, int options)\n+\t\t\t unsigned int mode,\n+\t\t\t const struct object_id *oid,\n+\t\t\t const char *path, int stage,\n+\t\t\t int refresh, int options)\n {\n+\tstruct index_state *istate = o->repo->index;\n \tstruct cache_entry *ce;\n \tint ret;\n \n-\tce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n+\tce = make_index_entry(istate, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n \tif (!ce)\n \t\treturn err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n \n-\tret = add_index_entry(&the_index, ce, options);\n+\tret = add_index_entry(istate, ce, options);\n \tif (refresh) {\n \t\tstruct cache_entry *nce;\n \n-\t\tnce = refresh_index_entry(&the_index, ce,\n+\t\tnce = refresh_index_entry(istate, ce,\n \t\t\t\t\t  CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);\n \t\tif (!nce)\n \t\t\treturn err(o, _(\"add_cacheinfo failed to refresh for path '%s'; merge aborting.\"), path);\n \t\tif (nce != ce)\n-\t\t\tret = add_index_entry(&the_index, nce, options);\n+\t\t\tret = add_index_entry(istate, nce, options);\n \t}\n \treturn ret;\n }\n@@ -356,7 +359,7 @@ static int unpack_trees_start(struct merge_options *o,\n \to->unpack_opts.merge = 1;\n \to->unpack_opts.head_idx = 2;\n \to->unpack_opts.fn = threeway_merge;\n-\to->unpack_opts.src_index = &the_index;\n+\to->unpack_opts.src_index = o->repo->index;\n \to->unpack_opts.dst_index = &tmp_index;\n \to->unpack_opts.aggressive = !merge_detect_rename(o);\n \tsetup_unpack_trees_porcelain(&o->unpack_opts, \"merge\");\n@@ -366,16 +369,16 @@ static int unpack_trees_start(struct merge_options *o,\n \tinit_tree_desc_from_tree(t+2, merge);\n \n \trc = unpack_trees(3, t, &o->unpack_opts);\n-\tcache_tree_free(&the_index.cache_tree);\n+\tcache_tree_free(&o->repo->index->cache_tree);\n \n \t/*\n-\t * Update the_index to match the new results, AFTER saving a copy\n+\t * Update o->repo->index to match the new results, AFTER saving a copy\n \t * in o->orig_index.  Update src_index to point to the saved copy.\n \t * (verify_uptodate() checks src_index, and the original index is\n \t * the one that had the necessary modification timestamps.)\n \t */\n-\to->orig_index = the_index;\n-\tthe_index = tmp_index;\n+\to->orig_index = *o->repo->index;\n+\t*o->repo->index = tmp_index;\n \to->unpack_opts.src_index = &o->orig_index;\n \n \treturn rc;\n@@ -390,12 +393,13 @@ static void unpack_trees_finish(struct merge_options *o)\n struct tree *write_tree_from_memory(struct merge_options *o)\n {\n \tstruct tree *result = NULL;\n+\tstruct index_state *istate = o->repo->index;\n \n-\tif (unmerged_index(&the_index)) {\n+\tif (unmerged_index(istate)) {\n \t\tint i;\n \t\tfprintf(stderr, \"BUG: There are unmerged index entries:\\n\");\n-\t\tfor (i = 0; i < the_index.cache_nr; i++) {\n-\t\t\tconst struct cache_entry *ce = the_index.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 (ce_stage(ce))\n \t\t\t\tfprintf(stderr, \"BUG: %d %.*s\\n\", ce_stage(ce),\n \t\t\t\t\t(int)ce_namelen(ce), ce->name);\n@@ -403,16 +407,16 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n \t\tBUG(\"unmerged index entries in merge-recursive.c\");\n \t}\n \n-\tif (!the_index.cache_tree)\n-\t\tthe_index.cache_tree = cache_tree();\n+\tif (!istate->cache_tree)\n+\t\tistate->cache_tree = cache_tree();\n \n-\tif (!cache_tree_fully_valid(the_index.cache_tree) &&\n-\t    cache_tree_update(&the_index, 0) < 0) {\n+\tif (!cache_tree_fully_valid(istate->cache_tree) &&\n+\t    cache_tree_update(istate, 0) < 0) {\n \t\terr(o, _(\"error building trees\"));\n \t\treturn NULL;\n \t}\n \n-\tresult = lookup_tree(&the_index.cache_tree->oid);\n+\tresult = lookup_tree(&istate->cache_tree->oid);\n \n \treturn result;\n }\n@@ -482,17 +486,17 @@ static struct stage_data *insert_stage_data(const char *path,\n  * Create a dictionary mapping file names to stage_data objects. The\n  * dictionary contains one entry for every path with a non-zero stage entry.\n  */\n-static struct string_list *get_unmerged(void)\n+static struct string_list *get_unmerged(struct index_state *istate)\n {\n \tstruct string_list *unmerged = xcalloc(1, sizeof(struct string_list));\n \tint i;\n \n \tunmerged->strdup_strings = 1;\n \n-\tfor (i = 0; i < the_index.cache_nr; i++) {\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tstruct string_list_item *item;\n \t\tstruct stage_data *e;\n-\t\tconst struct cache_entry *ce = the_index.cache[i];\n+\t\tconst struct cache_entry *ce = istate->cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n \n@@ -652,7 +656,7 @@ static int update_stages(struct merge_options *opt, const char *path,\n \tint clear = 1;\n \tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;\n \tif (clear)\n-\t\tif (remove_file_from_index(&the_index, path))\n+\t\tif (remove_file_from_index(opt->repo->index, path))\n \t\t\treturn -1;\n \tif (o)\n \t\tif (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))\n@@ -708,13 +712,13 @@ static int remove_file(struct merge_options *o, int clean,\n \tint update_working_directory = !o->call_depth && !no_wd;\n \n \tif (update_cache) {\n-\t\tif (remove_file_from_index(&the_index, path))\n+\t\tif (remove_file_from_index(o->repo->index, path))\n \t\t\treturn -1;\n \t}\n \tif (update_working_directory) {\n \t\tif (ignore_case) {\n \t\t\tstruct cache_entry *ce;\n-\t\t\tce = index_file_exists(&the_index, path, strlen(path),\n+\t\t\tce = index_file_exists(o->repo->index, path, strlen(path),\n \t\t\t\t\t       ignore_case);\n \t\t\tif (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))\n \t\t\t\treturn 0;\n@@ -765,7 +769,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char *\n  * check the working directory.  If empty_ok is non-zero, also return\n  * 0 in the case where the working-tree dir exists but is empty.\n  */\n-static int dir_in_way(const char *path, int check_working_copy, int empty_ok)\n+static int dir_in_way(struct index_state *istate, const char *path,\n+\t\t      int check_working_copy, int empty_ok)\n {\n \tint pos;\n \tstruct strbuf dirpath = STRBUF_INIT;\n@@ -774,12 +779,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok)\n \tstrbuf_addstr(&dirpath, path);\n \tstrbuf_addch(&dirpath, '/');\n \n-\tpos = index_name_pos(&the_index, dirpath.buf, dirpath.len);\n+\tpos = index_name_pos(istate, dirpath.buf, dirpath.len);\n \n \tif (pos < 0)\n \t\tpos = -1 - pos;\n-\tif (pos < the_index.cache_nr &&\n-\t    !strncmp(dirpath.buf, the_index.cache[pos]->name, dirpath.len)) {\n+\tif (pos < istate->cache_nr &&\n+\t    !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {\n \t\tstrbuf_release(&dirpath);\n \t\treturn 1;\n \t}\n@@ -822,7 +827,7 @@ static int was_tracked(struct merge_options *o, const char *path)\n \treturn 0;\n }\n \n-static int would_lose_untracked(const char *path)\n+static int would_lose_untracked(struct index_state *istate, const char *path)\n {\n \t/*\n \t * This may look like it can be simplified to:\n@@ -841,19 +846,19 @@ static int would_lose_untracked(const char *path)\n \t * update_file()/would_lose_untracked(); see every comment in this\n \t * file which mentions \"update_stages\".\n \t */\n-\tint pos = index_name_pos(&the_index, path, strlen(path));\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \n \tif (pos < 0)\n \t\tpos = -1 - pos;\n-\twhile (pos < the_index.cache_nr &&\n-\t       !strcmp(path, the_index.cache[pos]->name)) {\n+\twhile (pos < istate->cache_nr &&\n+\t       !strcmp(path, istate->cache[pos]->name)) {\n \t\t/*\n \t\t * If stage #0, it is definitely tracked.\n \t\t * If it has stage #2 then it was tracked\n \t\t * before this merge started.  All other\n \t\t * cases the path was not tracked.\n \t\t */\n-\t\tswitch (ce_stage(the_index.cache[pos])) {\n+\t\tswitch (ce_stage(istate->cache[pos])) {\n \t\tcase 0:\n \t\tcase 2:\n \t\t\treturn 0;\n@@ -913,7 +918,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)\n \t * Do not unlink a file in the work tree if we are not\n \t * tracking it.\n \t */\n-\tif (would_lose_untracked(path))\n+\tif (would_lose_untracked(o->repo->index, path))\n \t\treturn err(o, _(\"refusing to lose untracked file at '%s'\"),\n \t\t\t     path);\n \n@@ -963,7 +968,7 @@ static int update_file_flags(struct merge_options *o,\n \t\t}\n \t\tif (S_ISREG(mode)) {\n \t\t\tstruct strbuf strbuf = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {\n+\t\t\tif (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) {\n \t\t\t\tfree(buf);\n \t\t\t\tsize = strbuf.len;\n \t\t\t\tbuf = strbuf_detach(&strbuf, NULL);\n@@ -1081,7 +1086,7 @@ static int merge_3way(struct merge_options *o,\n \n \tmerge_status = ll_merge(result_buf, a->path, &orig, base_name,\n \t\t\t\t&src1, name1, &src2, name2,\n-\t\t\t\t&the_index, &ll_opts);\n+\t\t\t\to->repo->index, &ll_opts);\n \n \tfree(base_name);\n \tfree(name1);\n@@ -1092,8 +1097,9 @@ static int merge_3way(struct merge_options *o,\n \treturn merge_status;\n }\n \n-static int find_first_merges(struct object_array *result, const char *path,\n-\t\tstruct commit *a, struct commit *b)\n+static int find_first_merges(struct repository *repo,\n+\t\t\t     struct object_array *result, const char *path,\n+\t\t\t     struct commit *a, struct commit *b)\n {\n \tint i, j;\n \tstruct object_array merges = OBJECT_ARRAY_INIT;\n@@ -1112,7 +1118,7 @@ static int find_first_merges(struct object_array *result, const char *path,\n \t/* get all revisions that merge commit a */\n \txsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n \t\t\toid_to_hex(&a->object.oid));\n-\tinit_revisions(&revs, the_repository, NULL);\n+\tinit_revisions(&revs, repo, NULL);\n \trev_opts.submodule = path;\n \t/* FIXME: can't handle linked worktrees in submodules yet */\n \trevs.single_worktree = path != NULL;\n@@ -1242,7 +1248,8 @@ static int merge_submodule(struct merge_options *o,\n \t\treturn 0;\n \n \t/* find commit which merges them */\n-\tparent_count = find_first_merges(&merges, path, commit_a, commit_b);\n+\tparent_count = find_first_merges(o->repo, &merges, path,\n+\t\t\t\t\t commit_a, commit_b);\n \tswitch (parent_count) {\n \tcase 0:\n \t\toutput(o, 1, _(\"Failed to merge submodule %s (merge following commits not found)\"), path);\n@@ -1420,7 +1427,7 @@ static int conflict_rename_dir(struct merge_options *o,\n {\n \tconst struct diff_filespec *dest = pair->two;\n \n-\tif (!o->call_depth && would_lose_untracked(dest->path)) {\n+\tif (!o->call_depth && would_lose_untracked(o->repo->index, dest->path)) {\n \t\tchar *alt_path = unique_path(o, dest->path, rename_branch);\n \n \t\toutput(o, 1, _(\"Error: Refusing to lose untracked file at %s; \"\n@@ -1458,8 +1465,8 @@ static int handle_change_delete(struct merge_options *o,\n \tconst char *update_path = path;\n \tint ret = 0;\n \n-\tif (dir_in_way(path, !o->call_depth, 0) ||\n-\t    (!o->call_depth && would_lose_untracked(path))) {\n+\tif (dir_in_way(o->repo->index, path, !o->call_depth, 0) ||\n+\t    (!o->call_depth && would_lose_untracked(o->repo->index, path))) {\n \t\tupdate_path = alt_path = unique_path(o, path, change_branch);\n \t}\n \n@@ -1469,7 +1476,7 @@ static int handle_change_delete(struct merge_options *o,\n \t\t * correct; since there is no true \"middle point\" between\n \t\t * them, simply reuse the base version for virtual merge base.\n \t\t */\n-\t\tret = remove_file_from_index(&the_index, path);\n+\t\tret = remove_file_from_index(o->repo->index, path);\n \t\tif (!ret)\n \t\t\tret = update_file(o, 0, o_oid, o_mode, update_path);\n \t} else {\n@@ -1530,7 +1537,7 @@ static int conflict_rename_delete(struct merge_options *o,\n \t\treturn -1;\n \n \tif (o->call_depth)\n-\t\treturn remove_file_from_index(&the_index, dest->path);\n+\t\treturn remove_file_from_index(o->repo->index, dest->path);\n \telse\n \t\treturn update_stages(o, dest->path, NULL,\n \t\t\t\t     rename_branch == o->branch1 ? dest : NULL,\n@@ -1592,12 +1599,12 @@ static int handle_file(struct merge_options *o,\n \t\tremove_file(o, 0, rename->path, ren_src_was_dirty);\n \t\tdst_name = unique_path(o, rename->path, cur_branch);\n \t} else {\n-\t\tif (dir_in_way(rename->path, !o->call_depth, 0)) {\n+\t\tif (dir_in_way(o->repo->index, rename->path, !o->call_depth, 0)) {\n \t\t\tdst_name = unique_path(o, rename->path, cur_branch);\n \t\t\toutput(o, 1, _(\"%s is a directory in %s adding as %s instead\"),\n \t\t\t       rename->path, other_branch, dst_name);\n \t\t} else if (!o->call_depth &&\n-\t\t\t   would_lose_untracked(rename->path)) {\n+\t\t\t   would_lose_untracked(o->repo->index, rename->path)) {\n \t\t\tdst_name = unique_path(o, rename->path, cur_branch);\n \t\t\toutput(o, 1, _(\"Refusing to lose untracked file at %s; \"\n \t\t\t\t       \"adding as %s instead\"),\n@@ -1665,14 +1672,14 @@ static int conflict_rename_rename_1to2(struct merge_options *o,\n \t\t\t\treturn -1;\n \t\t}\n \t\telse\n-\t\t\tremove_file_from_index(&the_index, a->path);\n+\t\t\tremove_file_from_index(o->repo->index, a->path);\n \t\tadd = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);\n \t\tif (add) {\n \t\t\tif (update_file(o, 0, &add->oid, add->mode, b->path))\n \t\t\t\treturn -1;\n \t\t}\n \t\telse\n-\t\t\tremove_file_from_index(&the_index, b->path);\n+\t\t\tremove_file_from_index(o->repo->index, b->path);\n \t} else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))\n \t\treturn -1;\n \n@@ -1680,8 +1687,9 @@ static int conflict_rename_rename_1to2(struct merge_options *o,\n }\n \n static int conflict_rename_rename_2to1(struct merge_options *o,\n-\t\t\t\t\tstruct rename_conflict_info *ci)\n+\t\t\t\t       struct rename_conflict_info *ci)\n {\n+\tstruct index_state *istate = o->repo->index;\n \t/* Two files, a & b, were renamed to the same thing, c. */\n \tstruct diff_filespec *a = ci->pair1->one;\n \tstruct diff_filespec *b = ci->pair2->one;\n@@ -1700,8 +1708,12 @@ static int conflict_rename_rename_2to1(struct merge_options *o,\n \t       a->path, c1->path, ci->branch1,\n \t       b->path, c2->path, ci->branch2);\n \n-\tremove_file(o, 1, a->path, o->call_depth || would_lose_untracked(a->path));\n-\tremove_file(o, 1, b->path, o->call_depth || would_lose_untracked(b->path));\n+\tremove_file(o, 1, a->path,\n+\t\t    (o->call_depth ||\n+\t\t     would_lose_untracked(istate, a->path)));\n+\tremove_file(o, 1, b->path,\n+\t\t    (o->call_depth ||\n+\t\t     would_lose_untracked(istate, b->path)));\n \n \tpath_side_1_desc = xstrfmt(\"%s (was %s)\", path, a->path);\n \tpath_side_2_desc = xstrfmt(\"%s (was %s)\", path, b->path);\n@@ -1738,7 +1750,7 @@ static int conflict_rename_rename_2to1(struct merge_options *o,\n \t\tif (was_dirty(o, path))\n \t\t\toutput(o, 1, _(\"Refusing to lose dirty file at %s\"),\n \t\t\t       path);\n-\t\telse if (would_lose_untracked(path))\n+\t\telse if (would_lose_untracked(istate, path))\n \t\t\t/*\n \t\t\t * Only way we get here is if both renames were from\n \t\t\t * a directory rename AND user had an untracked file\n@@ -1789,7 +1801,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,\n \tstruct diff_queue_struct *ret;\n \tstruct diff_options opts;\n \n-\tdiff_setup(&opts, &the_index);\n+\tdiff_setup(&opts, o->repo->index);\n \topts.flags.recursive = 1;\n \topts.flags.rename_empty = 0;\n \topts.detect_rename = merge_detect_rename(o);\n@@ -2949,8 +2961,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(&the_index, path, o.buf, o.len, &o) |\n-\t    renormalize_buffer(&the_index, path, a.buf, a.len, &a))\n+\tif (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) |\n+\t    renormalize_buffer(opt->repo->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@@ -3028,7 +3040,7 @@ static int merge_content(struct merge_options *o,\n \t\t\t o->branch2 == rename_conflict_info->branch1) ?\n \t\t\tpair1->two->path : pair1->one->path;\n \n-\t\tif (dir_in_way(path, !o->call_depth,\n+\t\tif (dir_in_way(o->repo->index, path, !o->call_depth,\n \t\t\t       S_ISGITLINK(pair1->two->mode)))\n \t\t\tdf_conflict_remains = 1;\n \t}\n@@ -3066,7 +3078,7 @@ static int merge_content(struct merge_options *o,\n \tif (df_conflict_remains || is_dirty) {\n \t\tchar *new_path;\n \t\tif (o->call_depth) {\n-\t\t\tremove_file_from_index(&the_index, path);\n+\t\t\tremove_file_from_index(o->repo->index, path);\n \t\t} else {\n \t\t\tif (!mfi.clean) {\n \t\t\t\tif (update_stages(o, path, &one, &a, &b))\n@@ -3212,7 +3224,7 @@ static int process_entry(struct merge_options *o,\n \t\t\toid = b_oid;\n \t\t\tconf = _(\"directory/file\");\n \t\t}\n-\t\tif (dir_in_way(path,\n+\t\tif (dir_in_way(o->repo->index, path,\n \t\t\t       !o->call_depth && !S_ISGITLINK(a_mode),\n \t\t\t       0)) {\n \t\t\tchar *new_path = unique_path(o, path, add_branch);\n@@ -3223,7 +3235,7 @@ static int process_entry(struct merge_options *o,\n \t\t\tif (update_file(o, 0, oid, mode, new_path))\n \t\t\t\tclean_merge = -1;\n \t\t\telse if (o->call_depth)\n-\t\t\t\tremove_file_from_index(&the_index, path);\n+\t\t\t\tremove_file_from_index(o->repo->index, path);\n \t\t\tfree(new_path);\n \t\t} else {\n \t\t\toutput(o, 2, _(\"Adding %s\"), path);\n@@ -3256,6 +3268,7 @@ int merge_trees(struct merge_options *o,\n \t\tstruct tree *common,\n \t\tstruct tree **result)\n {\n+\tstruct index_state *istate = o->repo->index;\n \tint code, clean;\n \n \tif (o->subtree_shift) {\n@@ -3266,7 +3279,7 @@ int merge_trees(struct merge_options *o,\n \tif (oid_eq(&common->object.oid, &merge->object.oid)) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n-\t\tif (!o->call_depth && index_has_changes(&the_index, &sb)) {\n+\t\tif (!o->call_depth && index_has_changes(istate, &sb)) {\n \t\t\terr(o, _(\"Dirty index: cannot merge (dirty: %s)\"),\n \t\t\t    sb.buf);\n \t\t\treturn 0;\n@@ -3287,7 +3300,7 @@ int merge_trees(struct merge_options *o,\n \t\treturn -1;\n \t}\n \n-\tif (unmerged_index(&the_index)) {\n+\tif (unmerged_index(istate)) {\n \t\tstruct string_list *entries;\n \t\tstruct rename_info re_info;\n \t\tint i;\n@@ -3302,7 +3315,7 @@ int merge_trees(struct merge_options *o,\n \t\tget_files_dirs(o, head);\n \t\tget_files_dirs(o, merge);\n \n-\t\tentries = get_unmerged();\n+\t\tentries = get_unmerged(o->repo->index);\n \t\tclean = handle_renames(o, common, head, merge, entries,\n \t\t\t\t       &re_info);\n \t\trecord_df_conflict_files(o, entries);\n@@ -3418,7 +3431,7 @@ int merge_recursive(struct merge_options *o,\n \t\t * overwritten it: the committed \"conflicts\" were\n \t\t * already resolved.\n \t\t */\n-\t\tdiscard_index(&the_index);\n+\t\tdiscard_index(o->repo->index);\n \t\tsaved_b1 = o->branch1;\n \t\tsaved_b2 = o->branch2;\n \t\to->branch1 = \"Temporary merge branch 1\";\n@@ -3434,9 +3447,9 @@ int merge_recursive(struct merge_options *o,\n \t\t\treturn err(o, _(\"merge returned no commit\"));\n \t}\n \n-\tdiscard_index(&the_index);\n+\tdiscard_index(o->repo->index);\n \tif (!o->call_depth)\n-\t\trepo_read_index(the_repository);\n+\t\trepo_read_index(o->repo);\n \n \to->ancestor = \"merged common ancestors\";\n \tclean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2),\n@@ -3501,7 +3514,7 @@ int merge_recursive_generic(struct merge_options *o,\n \t\t}\n \t}\n \n-\trepo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);\n+\trepo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR);\n \tclean = merge_recursive(o, head_commit, next_commit, ca,\n \t\t\tresult);\n \tif (clean < 0) {\n@@ -3509,7 +3522,7 @@ int merge_recursive_generic(struct merge_options *o,\n \t\treturn clean;\n \t}\n \n-\tif (write_locked_index(&the_index, &lock,\n+\tif (write_locked_index(o->repo->index, &lock,\n \t\t\t       COMMIT_LOCK | SKIP_IF_UNCHANGED))\n \t\treturn err(o, _(\"Unable to write index.\"));\n \n@@ -3533,10 +3546,12 @@ static void merge_recursive_config(struct merge_options *o)\n \tgit_config(git_xmerge_config, NULL);\n }\n \n-void init_merge_options(struct merge_options *o)\n+void init_merge_options(struct merge_options *o,\n+\t\t\tstruct repository *repo)\n {\n \tconst char *merge_verbosity;\n \tmemset(o, 0, sizeof(struct merge_options));\n+\to->repo = repo;\n \to->verbosity = 2;\n \to->buffer_output = 1;\n \to->diff_rename_limit = -1;\ndiff --git a/merge-recursive.h b/merge-recursive.h\nindex fa7bc6b683..b2985b621f 100644\n--- a/merge-recursive.h\n+++ b/merge-recursive.h\n@@ -4,6 +4,8 @@\n #include \"unpack-trees.h\"\n #include \"string-list.h\"\n \n+struct repository;\n+\n struct merge_options {\n \tconst char *ancestor;\n \tconst char *branch1;\n@@ -31,6 +33,7 @@ struct merge_options {\n \tstruct string_list df_conflict_file_set;\n \tstruct unpack_trees_options unpack_opts;\n \tstruct index_state orig_index;\n+\tstruct repository *repo;\n };\n \n /*\n@@ -89,7 +92,8 @@ int merge_recursive_generic(struct merge_options *o,\n \t\t\t    const struct object_id **ca,\n \t\t\t    struct commit **result);\n \n-void init_merge_options(struct merge_options *o);\n+void init_merge_options(struct merge_options *o,\n+\t\t\tstruct repository *repo);\n struct tree *write_tree_from_memory(struct merge_options *o);\n \n int parse_merge_opt(struct merge_options *out, const char *s);\ndiff --git a/sequencer.c b/sequencer.c\nindex 5be3b5c79d..a8fb1861a3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -532,7 +532,7 @@ static int do_recursive_merge(struct repository *repo,\n \n \trepo_read_index(repo);\n \n-\tinit_merge_options(&o);\n+\tinit_merge_options(&o, repo);\n \to.ancestor = base ? base_label : \"(empty tree)\";\n \to.branch1 = \"HEAD\";\n \to.branch2 = next ? next_label : \"(empty tree)\";\n@@ -3022,7 +3022,7 @@ static int do_merge(struct repository *repo,\n \tfree_commit_list(bases);\n \n \trepo_read_index(repo);\n-\tinit_merge_options(&o);\n+\tinit_merge_options(&o, repo);\n \to.branch1 = \"HEAD\";\n \to.branch2 = ref_name.buf;\n \to.buffer_output = 2;\n-- 8< --\n\n> -- \n> Duy\n"},{"id":"350203","messageId":"CABPp-BH249etuVxQkYgE4a3C7wKFcicNsWzbOKdY2p4McdJYuw@mail.gmail.com","threadId":"48624","inReplyTo":"20180614171849.GA7675@duynguyen.home","subject":"Re: [PATCH v4 00/23] Fix incorrect use of the_index","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-14T20:57:37Z","receivedAt":"2018-06-14T20:57:42Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 14, 2018 at 10:18 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Mon, Jun 11, 2018 at 06:49:00PM +0200, Duy Nguyen wrote:\n>> On Mon, Jun 11, 2018 at 6:44 PM Elijah Newren <newren@gmail.com> wrote:\n>> > > What about merge-recursive.c? Given that this whole thing will take\n>> > > many release cycles to finish, your work may get merged before mine\n>> > > and I could do the conversion now (and resolve conflicts and resubmit\n>> > > later). Of course if you like to keep merge-recursive.c the_index-free\n>> > > now, I will not stop you ;-)\n>> >\n>> > I was just worried that since I was making changes in\n>> > merge-recursive.c that it'd cause you conflict pain, so I offered to\n>> > convert it.  If that pain doesn't bother you, feel free to do the\n>> > conversion and we'll just work through the minor conflicts as we go.\n>> > Besides, sounds like you've converted nearly all of git, so it may\n>> > make sense to just keep it together in one big series.\n>>\n>> OK let's just \"quickly\" get your series in then. I still have a few\n>> files to go and a couple more places to look back and ponder. I'm in\n>> no hurry to convert merge-recursive now :D\n>\n> Actually could you quickly check if I pass the right index in the\n> following patch? I realize you only have one extra index, but I don't\n> know if it gets passed elsewhere and in some function I'm supposed to\n> use another index than the default \"o->repo->index\". Sometimes\n> o->repo->index is not the correct answer.\n>\n> It takes many patches to get to this stage, so if you diff context\n> looks so strange to you, just ignore this for now. I'll eventually\n> send this one out in a series.\n>\n> PS. I put a 'struct repository *' in 'struct merge_options' instead\n> because it turns out we do need full repo struct in some function.\n\nYes, this looks right.\n\nIt'd be nice to be able to apply the patch locally so I could also\nlook at the --color-words version, but it's not a real big deal.\n\nIn general, this is how the index stuff works in merge-recursive:\n  * In unpack_trees_start(), we call unpack_trees() using the_index as\nsrc, and tmp_index as dest.\n  * As soon as unpack_trees() finishes, we swap: (orig_index,\nthe_index) = (the_index, tmp_index).\n  * We ONLY use orig_index (also called unpack_opts.src_index) in the\nwas_*() family of functions, which query about what the index was like\nbefore the merge started.  (To name these functions explicitly:\nwas_tracked_and_matches(), was_tracked(), and was_dirty()).  ALL other\ncallsites within merge-recursive.c should be operating on the_index,\nor, after your patch, o->repo->index.\n\n\n(Also, if you want to avoid merge conflicts, you might want to avoid\nunrelated changes like the whitespace and alignment fixes.  You'll be\nhappy to know, though, that I think I fixed them all up as part of the\nen/merge-recursive-cleanup series in pu.)\n\nElijah\n\n>\n> -- 8< --\n> diff --git a/builtin/am.c b/builtin/am.c\n> index 3961878871..5d2ff9aa8c 100644\n> --- a/builtin/am.c\n> +++ b/builtin/am.c\n> @@ -1592,7 +1592,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa\n>          * changes.\n>          */\n>\n> -       init_merge_options(&o);\n> +       init_merge_options(&o, the_repository);\n>\n>         o.branch1 = \"HEAD\";\n>         their_tree_name = xstrfmt(\"%.*s\", linelen(state->msg), state->msg);\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 528c6de7e1..4fd53cec6e 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -570,7 +570,7 @@ static int merge_working_tree(const struct checkout_opts *opts,\n>                          * a pain; plumb in an option to set\n>                          * o.renormalize?\n>                          */\n> -                       init_merge_options(&o);\n> +                       init_merge_options(&o, the_repository);\n>                         o.verbosity = 0;\n>                         work = write_tree_from_memory(&o);\n>\n> diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c\n> index 0dd9021958..c4a9e575d6 100644\n> --- a/builtin/merge-recursive.c\n> +++ b/builtin/merge-recursive.c\n> @@ -28,7 +28,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)\n>         struct merge_options o;\n>         struct commit *result;\n>\n> -       init_merge_options(&o);\n> +       init_merge_options(&o, the_repository);\n>         if (argv[0] && ends_with(argv[0], \"-subtree\"))\n>                 o.subtree_shift = \"\";\n>\n> diff --git a/builtin/merge.c b/builtin/merge.c\n> index db460a35cf..2ebd939b76 100644\n> --- a/builtin/merge.c\n> +++ b/builtin/merge.c\n> @@ -671,7 +671,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,\n>                         return 2;\n>                 }\n>\n> -               init_merge_options(&o);\n> +               init_merge_options(&o, the_repository);\n>                 if (!strcmp(strategy, \"subtree\"))\n>                         o.subtree_shift = \"\";\n>\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index a296ba3874..fd6556b6de 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -309,26 +309,29 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)\n>  }\n>\n>  static int add_cacheinfo(struct merge_options *o,\n> -               unsigned int mode, const struct object_id *oid,\n> -               const char *path, int stage, int refresh, int options)\n> +                        unsigned int mode,\n> +                        const struct object_id *oid,\n> +                        const char *path, int stage,\n> +                        int refresh, int options)\n>  {\n> +       struct index_state *istate = o->repo->index;\n>         struct cache_entry *ce;\n>         int ret;\n>\n> -       ce = make_index_entry(&the_index, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n> +       ce = make_index_entry(istate, mode, oid ? oid->hash : null_sha1, path, stage, 0);\n>         if (!ce)\n>                 return err(o, _(\"add_cacheinfo failed for path '%s'; merge aborting.\"), path);\n>\n> -       ret = add_index_entry(&the_index, ce, options);\n> +       ret = add_index_entry(istate, ce, options);\n>         if (refresh) {\n>                 struct cache_entry *nce;\n>\n> -               nce = refresh_index_entry(&the_index, ce,\n> +               nce = refresh_index_entry(istate, ce,\n>                                           CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);\n>                 if (!nce)\n>                         return err(o, _(\"add_cacheinfo failed to refresh for path '%s'; merge aborting.\"), path);\n>                 if (nce != ce)\n> -                       ret = add_index_entry(&the_index, nce, options);\n> +                       ret = add_index_entry(istate, nce, options);\n>         }\n>         return ret;\n>  }\n> @@ -356,7 +359,7 @@ static int unpack_trees_start(struct merge_options *o,\n>         o->unpack_opts.merge = 1;\n>         o->unpack_opts.head_idx = 2;\n>         o->unpack_opts.fn = threeway_merge;\n> -       o->unpack_opts.src_index = &the_index;\n> +       o->unpack_opts.src_index = o->repo->index;\n>         o->unpack_opts.dst_index = &tmp_index;\n>         o->unpack_opts.aggressive = !merge_detect_rename(o);\n>         setup_unpack_trees_porcelain(&o->unpack_opts, \"merge\");\n> @@ -366,16 +369,16 @@ static int unpack_trees_start(struct merge_options *o,\n>         init_tree_desc_from_tree(t+2, merge);\n>\n>         rc = unpack_trees(3, t, &o->unpack_opts);\n> -       cache_tree_free(&the_index.cache_tree);\n> +       cache_tree_free(&o->repo->index->cache_tree);\n>\n>         /*\n> -        * Update the_index to match the new results, AFTER saving a copy\n> +        * Update o->repo->index to match the new results, AFTER saving a copy\n>          * in o->orig_index.  Update src_index to point to the saved copy.\n>          * (verify_uptodate() checks src_index, and the original index is\n>          * the one that had the necessary modification timestamps.)\n>          */\n> -       o->orig_index = the_index;\n> -       the_index = tmp_index;\n> +       o->orig_index = *o->repo->index;\n> +       *o->repo->index = tmp_index;\n>         o->unpack_opts.src_index = &o->orig_index;\n>\n>         return rc;\n> @@ -390,12 +393,13 @@ static void unpack_trees_finish(struct merge_options *o)\n>  struct tree *write_tree_from_memory(struct merge_options *o)\n>  {\n>         struct tree *result = NULL;\n> +       struct index_state *istate = o->repo->index;\n>\n> -       if (unmerged_index(&the_index)) {\n> +       if (unmerged_index(istate)) {\n>                 int i;\n>                 fprintf(stderr, \"BUG: There are unmerged index entries:\\n\");\n> -               for (i = 0; i < the_index.cache_nr; i++) {\n> -                       const struct cache_entry *ce = the_index.cache[i];\n> +               for (i = 0; i < istate->cache_nr; i++) {\n> +                       const struct cache_entry *ce = istate->cache[i];\n>                         if (ce_stage(ce))\n>                                 fprintf(stderr, \"BUG: %d %.*s\\n\", ce_stage(ce),\n>                                         (int)ce_namelen(ce), ce->name);\n> @@ -403,16 +407,16 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n>                 BUG(\"unmerged index entries in merge-recursive.c\");\n>         }\n>\n> -       if (!the_index.cache_tree)\n> -               the_index.cache_tree = cache_tree();\n> +       if (!istate->cache_tree)\n> +               istate->cache_tree = cache_tree();\n>\n> -       if (!cache_tree_fully_valid(the_index.cache_tree) &&\n> -           cache_tree_update(&the_index, 0) < 0) {\n> +       if (!cache_tree_fully_valid(istate->cache_tree) &&\n> +           cache_tree_update(istate, 0) < 0) {\n>                 err(o, _(\"error building trees\"));\n>                 return NULL;\n>         }\n>\n> -       result = lookup_tree(&the_index.cache_tree->oid);\n> +       result = lookup_tree(&istate->cache_tree->oid);\n>\n>         return result;\n>  }\n> @@ -482,17 +486,17 @@ static struct stage_data *insert_stage_data(const char *path,\n>   * Create a dictionary mapping file names to stage_data objects. The\n>   * dictionary contains one entry for every path with a non-zero stage entry.\n>   */\n> -static struct string_list *get_unmerged(void)\n> +static struct string_list *get_unmerged(struct index_state *istate)\n>  {\n>         struct string_list *unmerged = xcalloc(1, sizeof(struct string_list));\n>         int i;\n>\n>         unmerged->strdup_strings = 1;\n>\n> -       for (i = 0; i < the_index.cache_nr; i++) {\n> +       for (i = 0; i < istate->cache_nr; i++) {\n>                 struct string_list_item *item;\n>                 struct stage_data *e;\n> -               const struct cache_entry *ce = the_index.cache[i];\n> +               const struct cache_entry *ce = istate->cache[i];\n>                 if (!ce_stage(ce))\n>                         continue;\n>\n> @@ -652,7 +656,7 @@ static int update_stages(struct merge_options *opt, const char *path,\n>         int clear = 1;\n>         int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;\n>         if (clear)\n> -               if (remove_file_from_index(&the_index, path))\n> +               if (remove_file_from_index(opt->repo->index, path))\n>                         return -1;\n>         if (o)\n>                 if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))\n> @@ -708,13 +712,13 @@ static int remove_file(struct merge_options *o, int clean,\n>         int update_working_directory = !o->call_depth && !no_wd;\n>\n>         if (update_cache) {\n> -               if (remove_file_from_index(&the_index, path))\n> +               if (remove_file_from_index(o->repo->index, path))\n>                         return -1;\n>         }\n>         if (update_working_directory) {\n>                 if (ignore_case) {\n>                         struct cache_entry *ce;\n> -                       ce = index_file_exists(&the_index, path, strlen(path),\n> +                       ce = index_file_exists(o->repo->index, path, strlen(path),\n>                                                ignore_case);\n>                         if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))\n>                                 return 0;\n> @@ -765,7 +769,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char *\n>   * check the working directory.  If empty_ok is non-zero, also return\n>   * 0 in the case where the working-tree dir exists but is empty.\n>   */\n> -static int dir_in_way(const char *path, int check_working_copy, int empty_ok)\n> +static int dir_in_way(struct index_state *istate, const char *path,\n> +                     int check_working_copy, int empty_ok)\n>  {\n>         int pos;\n>         struct strbuf dirpath = STRBUF_INIT;\n> @@ -774,12 +779,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok)\n>         strbuf_addstr(&dirpath, path);\n>         strbuf_addch(&dirpath, '/');\n>\n> -       pos = index_name_pos(&the_index, dirpath.buf, dirpath.len);\n> +       pos = index_name_pos(istate, dirpath.buf, dirpath.len);\n>\n>         if (pos < 0)\n>                 pos = -1 - pos;\n> -       if (pos < the_index.cache_nr &&\n> -           !strncmp(dirpath.buf, the_index.cache[pos]->name, dirpath.len)) {\n> +       if (pos < istate->cache_nr &&\n> +           !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {\n>                 strbuf_release(&dirpath);\n>                 return 1;\n>         }\n> @@ -822,7 +827,7 @@ static int was_tracked(struct merge_options *o, const char *path)\n>         return 0;\n>  }\n>\n> -static int would_lose_untracked(const char *path)\n> +static int would_lose_untracked(struct index_state *istate, const char *path)\n>  {\n>         /*\n>          * This may look like it can be simplified to:\n> @@ -841,19 +846,19 @@ static int would_lose_untracked(const char *path)\n>          * update_file()/would_lose_untracked(); see every comment in this\n>          * file which mentions \"update_stages\".\n>          */\n> -       int pos = index_name_pos(&the_index, path, strlen(path));\n> +       int pos = index_name_pos(istate, path, strlen(path));\n>\n>         if (pos < 0)\n>                 pos = -1 - pos;\n> -       while (pos < the_index.cache_nr &&\n> -              !strcmp(path, the_index.cache[pos]->name)) {\n> +       while (pos < istate->cache_nr &&\n> +              !strcmp(path, istate->cache[pos]->name)) {\n>                 /*\n>                  * If stage #0, it is definitely tracked.\n>                  * If it has stage #2 then it was tracked\n>                  * before this merge started.  All other\n>                  * cases the path was not tracked.\n>                  */\n> -               switch (ce_stage(the_index.cache[pos])) {\n> +               switch (ce_stage(istate->cache[pos])) {\n>                 case 0:\n>                 case 2:\n>                         return 0;\n> @@ -913,7 +918,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)\n>          * Do not unlink a file in the work tree if we are not\n>          * tracking it.\n>          */\n> -       if (would_lose_untracked(path))\n> +       if (would_lose_untracked(o->repo->index, path))\n>                 return err(o, _(\"refusing to lose untracked file at '%s'\"),\n>                              path);\n>\n> @@ -963,7 +968,7 @@ static int update_file_flags(struct merge_options *o,\n>                 }\n>                 if (S_ISREG(mode)) {\n>                         struct strbuf strbuf = STRBUF_INIT;\n> -                       if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {\n> +                       if (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) {\n>                                 free(buf);\n>                                 size = strbuf.len;\n>                                 buf = strbuf_detach(&strbuf, NULL);\n> @@ -1081,7 +1086,7 @@ static int merge_3way(struct merge_options *o,\n>\n>         merge_status = ll_merge(result_buf, a->path, &orig, base_name,\n>                                 &src1, name1, &src2, name2,\n> -                               &the_index, &ll_opts);\n> +                               o->repo->index, &ll_opts);\n>\n>         free(base_name);\n>         free(name1);\n> @@ -1092,8 +1097,9 @@ static int merge_3way(struct merge_options *o,\n>         return merge_status;\n>  }\n>\n> -static int find_first_merges(struct object_array *result, const char *path,\n> -               struct commit *a, struct commit *b)\n> +static int find_first_merges(struct repository *repo,\n> +                            struct object_array *result, const char *path,\n> +                            struct commit *a, struct commit *b)\n>  {\n>         int i, j;\n>         struct object_array merges = OBJECT_ARRAY_INIT;\n> @@ -1112,7 +1118,7 @@ static int find_first_merges(struct object_array *result, const char *path,\n>         /* get all revisions that merge commit a */\n>         xsnprintf(merged_revision, sizeof(merged_revision), \"^%s\",\n>                         oid_to_hex(&a->object.oid));\n> -       init_revisions(&revs, the_repository, NULL);\n> +       init_revisions(&revs, repo, NULL);\n>         rev_opts.submodule = path;\n>         /* FIXME: can't handle linked worktrees in submodules yet */\n>         revs.single_worktree = path != NULL;\n> @@ -1242,7 +1248,8 @@ static int merge_submodule(struct merge_options *o,\n>                 return 0;\n>\n>         /* find commit which merges them */\n> -       parent_count = find_first_merges(&merges, path, commit_a, commit_b);\n> +       parent_count = find_first_merges(o->repo, &merges, path,\n> +                                        commit_a, commit_b);\n>         switch (parent_count) {\n>         case 0:\n>                 output(o, 1, _(\"Failed to merge submodule %s (merge following commits not found)\"), path);\n> @@ -1420,7 +1427,7 @@ static int conflict_rename_dir(struct merge_options *o,\n>  {\n>         const struct diff_filespec *dest = pair->two;\n>\n> -       if (!o->call_depth && would_lose_untracked(dest->path)) {\n> +       if (!o->call_depth && would_lose_untracked(o->repo->index, dest->path)) {\n>                 char *alt_path = unique_path(o, dest->path, rename_branch);\n>\n>                 output(o, 1, _(\"Error: Refusing to lose untracked file at %s; \"\n> @@ -1458,8 +1465,8 @@ static int handle_change_delete(struct merge_options *o,\n>         const char *update_path = path;\n>         int ret = 0;\n>\n> -       if (dir_in_way(path, !o->call_depth, 0) ||\n> -           (!o->call_depth && would_lose_untracked(path))) {\n> +       if (dir_in_way(o->repo->index, path, !o->call_depth, 0) ||\n> +           (!o->call_depth && would_lose_untracked(o->repo->index, path))) {\n>                 update_path = alt_path = unique_path(o, path, change_branch);\n>         }\n>\n> @@ -1469,7 +1476,7 @@ static int handle_change_delete(struct merge_options *o,\n>                  * correct; since there is no true \"middle point\" between\n>                  * them, simply reuse the base version for virtual merge base.\n>                  */\n> -               ret = remove_file_from_index(&the_index, path);\n> +               ret = remove_file_from_index(o->repo->index, path);\n>                 if (!ret)\n>                         ret = update_file(o, 0, o_oid, o_mode, update_path);\n>         } else {\n> @@ -1530,7 +1537,7 @@ static int conflict_rename_delete(struct merge_options *o,\n>                 return -1;\n>\n>         if (o->call_depth)\n> -               return remove_file_from_index(&the_index, dest->path);\n> +               return remove_file_from_index(o->repo->index, dest->path);\n>         else\n>                 return update_stages(o, dest->path, NULL,\n>                                      rename_branch == o->branch1 ? dest : NULL,\n> @@ -1592,12 +1599,12 @@ static int handle_file(struct merge_options *o,\n>                 remove_file(o, 0, rename->path, ren_src_was_dirty);\n>                 dst_name = unique_path(o, rename->path, cur_branch);\n>         } else {\n> -               if (dir_in_way(rename->path, !o->call_depth, 0)) {\n> +               if (dir_in_way(o->repo->index, rename->path, !o->call_depth, 0)) {\n>                         dst_name = unique_path(o, rename->path, cur_branch);\n>                         output(o, 1, _(\"%s is a directory in %s adding as %s instead\"),\n>                                rename->path, other_branch, dst_name);\n>                 } else if (!o->call_depth &&\n> -                          would_lose_untracked(rename->path)) {\n> +                          would_lose_untracked(o->repo->index, rename->path)) {\n>                         dst_name = unique_path(o, rename->path, cur_branch);\n>                         output(o, 1, _(\"Refusing to lose untracked file at %s; \"\n>                                        \"adding as %s instead\"),\n> @@ -1665,14 +1672,14 @@ static int conflict_rename_rename_1to2(struct merge_options *o,\n>                                 return -1;\n>                 }\n>                 else\n> -                       remove_file_from_index(&the_index, a->path);\n> +                       remove_file_from_index(o->repo->index, a->path);\n>                 add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);\n>                 if (add) {\n>                         if (update_file(o, 0, &add->oid, add->mode, b->path))\n>                                 return -1;\n>                 }\n>                 else\n> -                       remove_file_from_index(&the_index, b->path);\n> +                       remove_file_from_index(o->repo->index, b->path);\n>         } else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))\n>                 return -1;\n>\n> @@ -1680,8 +1687,9 @@ static int conflict_rename_rename_1to2(struct merge_options *o,\n>  }\n>\n>  static int conflict_rename_rename_2to1(struct merge_options *o,\n> -                                       struct rename_conflict_info *ci)\n> +                                      struct rename_conflict_info *ci)\n>  {\n> +       struct index_state *istate = o->repo->index;\n>         /* Two files, a & b, were renamed to the same thing, c. */\n>         struct diff_filespec *a = ci->pair1->one;\n>         struct diff_filespec *b = ci->pair2->one;\n> @@ -1700,8 +1708,12 @@ static int conflict_rename_rename_2to1(struct merge_options *o,\n>                a->path, c1->path, ci->branch1,\n>                b->path, c2->path, ci->branch2);\n>\n> -       remove_file(o, 1, a->path, o->call_depth || would_lose_untracked(a->path));\n> -       remove_file(o, 1, b->path, o->call_depth || would_lose_untracked(b->path));\n> +       remove_file(o, 1, a->path,\n> +                   (o->call_depth ||\n> +                    would_lose_untracked(istate, a->path)));\n> +       remove_file(o, 1, b->path,\n> +                   (o->call_depth ||\n> +                    would_lose_untracked(istate, b->path)));\n>\n>         path_side_1_desc = xstrfmt(\"%s (was %s)\", path, a->path);\n>         path_side_2_desc = xstrfmt(\"%s (was %s)\", path, b->path);\n> @@ -1738,7 +1750,7 @@ static int conflict_rename_rename_2to1(struct merge_options *o,\n>                 if (was_dirty(o, path))\n>                         output(o, 1, _(\"Refusing to lose dirty file at %s\"),\n>                                path);\n> -               else if (would_lose_untracked(path))\n> +               else if (would_lose_untracked(istate, path))\n>                         /*\n>                          * Only way we get here is if both renames were from\n>                          * a directory rename AND user had an untracked file\n> @@ -1789,7 +1801,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,\n>         struct diff_queue_struct *ret;\n>         struct diff_options opts;\n>\n> -       diff_setup(&opts, &the_index);\n> +       diff_setup(&opts, o->repo->index);\n>         opts.flags.recursive = 1;\n>         opts.flags.rename_empty = 0;\n>         opts.detect_rename = merge_detect_rename(o);\n> @@ -2949,8 +2961,8 @@ static int blob_unchanged(struct merge_options *opt,\n>          * performed.  Comparison can be skipped if both files are\n>          * unchanged since their sha1s have already been compared.\n>          */\n> -       if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |\n> -           renormalize_buffer(&the_index, path, a.buf, a.len, &a))\n> +       if (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) |\n> +           renormalize_buffer(opt->repo->index, path, a.buf, a.len, &a))\n>                 ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));\n>\n>  error_return:\n> @@ -3028,7 +3040,7 @@ static int merge_content(struct merge_options *o,\n>                          o->branch2 == rename_conflict_info->branch1) ?\n>                         pair1->two->path : pair1->one->path;\n>\n> -               if (dir_in_way(path, !o->call_depth,\n> +               if (dir_in_way(o->repo->index, path, !o->call_depth,\n>                                S_ISGITLINK(pair1->two->mode)))\n>                         df_conflict_remains = 1;\n>         }\n> @@ -3066,7 +3078,7 @@ static int merge_content(struct merge_options *o,\n>         if (df_conflict_remains || is_dirty) {\n>                 char *new_path;\n>                 if (o->call_depth) {\n> -                       remove_file_from_index(&the_index, path);\n> +                       remove_file_from_index(o->repo->index, path);\n>                 } else {\n>                         if (!mfi.clean) {\n>                                 if (update_stages(o, path, &one, &a, &b))\n> @@ -3212,7 +3224,7 @@ static int process_entry(struct merge_options *o,\n>                         oid = b_oid;\n>                         conf = _(\"directory/file\");\n>                 }\n> -               if (dir_in_way(path,\n> +               if (dir_in_way(o->repo->index, path,\n>                                !o->call_depth && !S_ISGITLINK(a_mode),\n>                                0)) {\n>                         char *new_path = unique_path(o, path, add_branch);\n> @@ -3223,7 +3235,7 @@ static int process_entry(struct merge_options *o,\n>                         if (update_file(o, 0, oid, mode, new_path))\n>                                 clean_merge = -1;\n>                         else if (o->call_depth)\n> -                               remove_file_from_index(&the_index, path);\n> +                               remove_file_from_index(o->repo->index, path);\n>                         free(new_path);\n>                 } else {\n>                         output(o, 2, _(\"Adding %s\"), path);\n> @@ -3256,6 +3268,7 @@ int merge_trees(struct merge_options *o,\n>                 struct tree *common,\n>                 struct tree **result)\n>  {\n> +       struct index_state *istate = o->repo->index;\n>         int code, clean;\n>\n>         if (o->subtree_shift) {\n> @@ -3266,7 +3279,7 @@ int merge_trees(struct merge_options *o,\n>         if (oid_eq(&common->object.oid, &merge->object.oid)) {\n>                 struct strbuf sb = STRBUF_INIT;\n>\n> -               if (!o->call_depth && index_has_changes(&the_index, &sb)) {\n> +               if (!o->call_depth && index_has_changes(istate, &sb)) {\n>                         err(o, _(\"Dirty index: cannot merge (dirty: %s)\"),\n>                             sb.buf);\n>                         return 0;\n> @@ -3287,7 +3300,7 @@ int merge_trees(struct merge_options *o,\n>                 return -1;\n>         }\n>\n> -       if (unmerged_index(&the_index)) {\n> +       if (unmerged_index(istate)) {\n>                 struct string_list *entries;\n>                 struct rename_info re_info;\n>                 int i;\n> @@ -3302,7 +3315,7 @@ int merge_trees(struct merge_options *o,\n>                 get_files_dirs(o, head);\n>                 get_files_dirs(o, merge);\n>\n> -               entries = get_unmerged();\n> +               entries = get_unmerged(o->repo->index);\n>                 clean = handle_renames(o, common, head, merge, entries,\n>                                        &re_info);\n>                 record_df_conflict_files(o, entries);\n> @@ -3418,7 +3431,7 @@ int merge_recursive(struct merge_options *o,\n>                  * overwritten it: the committed \"conflicts\" were\n>                  * already resolved.\n>                  */\n> -               discard_index(&the_index);\n> +               discard_index(o->repo->index);\n>                 saved_b1 = o->branch1;\n>                 saved_b2 = o->branch2;\n>                 o->branch1 = \"Temporary merge branch 1\";\n> @@ -3434,9 +3447,9 @@ int merge_recursive(struct merge_options *o,\n>                         return err(o, _(\"merge returned no commit\"));\n>         }\n>\n> -       discard_index(&the_index);\n> +       discard_index(o->repo->index);\n>         if (!o->call_depth)\n> -               repo_read_index(the_repository);\n> +               repo_read_index(o->repo);\n>\n>         o->ancestor = \"merged common ancestors\";\n>         clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2),\n> @@ -3501,7 +3514,7 @@ int merge_recursive_generic(struct merge_options *o,\n>                 }\n>         }\n>\n> -       repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);\n> +       repo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR);\n>         clean = merge_recursive(o, head_commit, next_commit, ca,\n>                         result);\n>         if (clean < 0) {\n> @@ -3509,7 +3522,7 @@ int merge_recursive_generic(struct merge_options *o,\n>                 return clean;\n>         }\n>\n> -       if (write_locked_index(&the_index, &lock,\n> +       if (write_locked_index(o->repo->index, &lock,\n>                                COMMIT_LOCK | SKIP_IF_UNCHANGED))\n>                 return err(o, _(\"Unable to write index.\"));\n>\n> @@ -3533,10 +3546,12 @@ static void merge_recursive_config(struct merge_options *o)\n>         git_config(git_xmerge_config, NULL);\n>  }\n>\n> -void init_merge_options(struct merge_options *o)\n> +void init_merge_options(struct merge_options *o,\n> +                       struct repository *repo)\n>  {\n>         const char *merge_verbosity;\n>         memset(o, 0, sizeof(struct merge_options));\n> +       o->repo = repo;\n>         o->verbosity = 2;\n>         o->buffer_output = 1;\n>         o->diff_rename_limit = -1;\n> diff --git a/merge-recursive.h b/merge-recursive.h\n> index fa7bc6b683..b2985b621f 100644\n> --- a/merge-recursive.h\n> +++ b/merge-recursive.h\n> @@ -4,6 +4,8 @@\n>  #include \"unpack-trees.h\"\n>  #include \"string-list.h\"\n>\n> +struct repository;\n> +\n>  struct merge_options {\n>         const char *ancestor;\n>         const char *branch1;\n> @@ -31,6 +33,7 @@ struct merge_options {\n>         struct string_list df_conflict_file_set;\n>         struct unpack_trees_options unpack_opts;\n>         struct index_state orig_index;\n> +       struct repository *repo;\n>  };\n>\n>  /*\n> @@ -89,7 +92,8 @@ int merge_recursive_generic(struct merge_options *o,\n>                             const struct object_id **ca,\n>                             struct commit **result);\n>\n> -void init_merge_options(struct merge_options *o);\n> +void init_merge_options(struct merge_options *o,\n> +                       struct repository *repo);\n>  struct tree *write_tree_from_memory(struct merge_options *o);\n>\n>  int parse_merge_opt(struct merge_options *out, const char *s);\n> diff --git a/sequencer.c b/sequencer.c\n> index 5be3b5c79d..a8fb1861a3 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -532,7 +532,7 @@ static int do_recursive_merge(struct repository *repo,\n>\n>         repo_read_index(repo);\n>\n> -       init_merge_options(&o);\n> +       init_merge_options(&o, repo);\n>         o.ancestor = base ? base_label : \"(empty tree)\";\n>         o.branch1 = \"HEAD\";\n>         o.branch2 = next ? next_label : \"(empty tree)\";\n> @@ -3022,7 +3022,7 @@ static int do_merge(struct repository *repo,\n>         free_commit_list(bases);\n>\n>         repo_read_index(repo);\n> -       init_merge_options(&o);\n> +       init_merge_options(&o, repo);\n>         o.branch1 = \"HEAD\";\n>         o.branch2 = ref_name.buf;\n>         o.buffer_output = 2;\n> -- 8< --\n>\n>> --\n>> Duy\n"}]}