Intent-to-add entries used to forbid writing trees so it was not a problem. After commit 3f6d56d (commit: ignore intent-to-add entries instead of refusing - 2012-02-07), we can generate trees from an index with i-t-a entries. However, the commit forgets to invalidate all paths leading to i-t-a entries. With fully valid cache-tree (e.g. after commit or write-tree), diff operations may prefer cache-tree to index and not see i-t-a entries in the index, because cache-tree does not have them. Reported-by: Jonathon Mah <me@xxxxxxxxxxxxxxx> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- This version ensures that entry_count can only be >= -1 after update_one returns. Not ideal but good enough. cache-tree.c | 40 ++++++++++++++++++++++++++++++++++++---- t/t2203-add-intent.sh | 20 ++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/cache-tree.c b/cache-tree.c index 28ed657..1fbc81a 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -248,6 +248,7 @@ static int update_one(struct cache_tree *it, int missing_ok = flags & WRITE_TREE_MISSING_OK; int dryrun = flags & WRITE_TREE_DRY_RUN; int i; + int to_invalidate = 0; if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; @@ -324,7 +325,14 @@ static int update_one(struct cache_tree *it, if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); - i += sub->cache_tree->entry_count - 1; + i--; /* this entry is already counted in "sub" */ + if (sub->cache_tree->entry_count < 0) { + i -= sub->cache_tree->entry_count; + sub->cache_tree->entry_count = -1; + to_invalidate = 1; + } + else + i += sub->cache_tree->entry_count; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; } @@ -339,8 +347,23 @@ static int update_one(struct cache_tree *it, mode, sha1_to_hex(sha1), entlen+baselen, path); } - if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD)) - continue; /* entry being removed or placeholder */ + /* + * CE_REMOVE entries are removed before the index is + * written to disk. Skip them to remain consistent + * with the future on-disk index. + */ + if (ce->ce_flags & CE_REMOVE) + continue; + + /* + * CE_INTENT_TO_ADD entries exist on on-disk index but + * they are not part of generated trees. Invalidate up + * to root to force cache-tree users to read elsewhere. + */ + if (ce->ce_flags & CE_INTENT_TO_ADD) { + to_invalidate = 1; + continue; + } strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); @@ -360,7 +383,7 @@ static int update_one(struct cache_tree *it, } strbuf_release(&buffer); - it->entry_count = i; + it->entry_count = to_invalidate ? -i : i; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, @@ -381,6 +404,15 @@ int cache_tree_update(struct cache_tree *it, i = update_one(it, cache, entries, "", 0, flags); if (i < 0) return i; + /* + * update_one() uses negative entry_count as a way to mark an + * entry invalid _and_ pass the number of entries back to + * itself at the parent level. This is for internal use and + * should not be leaked out after the top-level update_one + * exits. + */ + if (it->entry_count < 0) + it->entry_count = -1; return 0; } diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index ec35409..2a4a749 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' ' git commit -a -m all ' +test_expect_success 'cache-tree invalidates i-t-a paths' ' + git reset --hard && + mkdir dir && + : >dir/foo && + git add dir/foo && + git commit -m foo && + + : >dir/bar && + git add -N dir/bar && + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual && + + git write-tree >/dev/null && + + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual +' + test_done -- 1.8.0.rc2.23.g1fb49df -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html