cache-tree: invalidate i-t-a paths after generating trees

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@JonathonMah.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Dec 16, 2012 at 11:15 UTC eec3e7e406867487036cf447fe8fa18740824b2f
2 files changed +32 -2
cache-tree.c
+12 -2
@@ -244,6 +244,7 @@ static int update_one(struct cache_tree *it,
244 struct strbuf buffer;
245 int missing_ok = flags & WRITE_TREE_MISSING_OK;
246 int dryrun = flags & WRITE_TREE_DRY_RUN;
247 + int to_invalidate = 0;
248 int i;
249
250 *skip_count = 0;
@@ -333,6 +334,8 @@ static int update_one(struct cache_tree *it,
334 i += sub->count;
335 sha1 = sub->cache_tree->sha1;
336 mode = S_IFDIR;
337 + if (sub->cache_tree->entry_count < 0)
338 + to_invalidate = 1;
339 }
340 else {
341 sha1 = ce->sha1;
@@ -356,8 +359,15 @@ static int update_one(struct cache_tree *it,
359 continue;
360 }
361
359 - if (ce->ce_flags & CE_INTENT_TO_ADD)
362 + /*
363 + * CE_INTENT_TO_ADD entries exist on on-disk index but
364 + * they are not part of generated trees. Invalidate up
365 + * to root to force cache-tree users to read elsewhere.
366 + */
367 + if (ce->ce_flags & CE_INTENT_TO_ADD) {
368 + to_invalidate = 1;
369 continue;
370 + }
371
372 strbuf_grow(&buffer, entlen + 100);
373 strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
@@ -377,7 +387,7 @@ static int update_one(struct cache_tree *it,
387 }
388
389 strbuf_release(&buffer);
380 - it->entry_count = i - *skip_count;
390 + it->entry_count = to_invalidate ? -1 : i - *skip_count;
391 #if DEBUG
392 fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
393 it->entry_count, it->subtree_nr,
t/t2203-add-intent.sh
+20
@@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' '
62 git commit -a -m all
63 '
64
65 +test_expect_success 'cache-tree invalidates i-t-a paths' '
66 + git reset --hard &&
67 + mkdir dir &&
68 + : >dir/foo &&
69 + git add dir/foo &&
70 + git commit -m foo &&
71 +
72 + : >dir/bar &&
73 + git add -N dir/bar &&
74 + git diff --cached --name-only >actual &&
75 + echo dir/bar >expect &&
76 + test_cmp expect actual &&
77 +
78 + git write-tree >/dev/null &&
79 +
80 + git diff --cached --name-only >actual &&
81 + echo dir/bar >expect &&
82 + test_cmp expect actual
83 +'
84 +
85 test_done
86