Skip to content

Commit c12a978

Browse files
committed
Merge branch 'nd/invalidate-i-t-a-cache-tree' into maint
* nd/invalidate-i-t-a-cache-tree: cache-tree: invalidate i-t-a paths after generating trees cache-tree: fix writing cache-tree when CE_REMOVE is present cache-tree: replace "for" loops in update_one with "while" loops cache-tree: remove dead i-t-a code in verify_cache()
2 parents f70eec8 + eec3e7e commit c12a978

File tree

3 files changed

+65
-17
lines changed

3 files changed

+65
-17
lines changed

cache-tree.c

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,8 @@ static int verify_cache(struct cache_entry **cache,
166166
fprintf(stderr, "...\n");
167167
break;
168168
}
169-
if (ce_stage(ce))
170-
fprintf(stderr, "%s: unmerged (%s)\n",
171-
ce->name, sha1_to_hex(ce->sha1));
172-
else
173-
fprintf(stderr, "%s: not added yet\n",
174-
ce->name);
169+
fprintf(stderr, "%s: unmerged (%s)\n",
170+
ce->name, sha1_to_hex(ce->sha1));
175171
}
176172
}
177173
if (funny)
@@ -242,13 +238,17 @@ static int update_one(struct cache_tree *it,
242238
int entries,
243239
const char *base,
244240
int baselen,
241+
int *skip_count,
245242
int flags)
246243
{
247244
struct strbuf buffer;
248245
int missing_ok = flags & WRITE_TREE_MISSING_OK;
249246
int dryrun = flags & WRITE_TREE_DRY_RUN;
247+
int to_invalidate = 0;
250248
int i;
251249

250+
*skip_count = 0;
251+
252252
if (0 <= it->entry_count && has_sha1_file(it->sha1))
253253
return it->entry_count;
254254

@@ -263,20 +263,23 @@ static int update_one(struct cache_tree *it,
263263
/*
264264
* Find the subtrees and update them.
265265
*/
266-
for (i = 0; i < entries; i++) {
266+
i = 0;
267+
while (i < entries) {
267268
struct cache_entry *ce = cache[i];
268269
struct cache_tree_sub *sub;
269270
const char *path, *slash;
270-
int pathlen, sublen, subcnt;
271+
int pathlen, sublen, subcnt, subskip;
271272

272273
path = ce->name;
273274
pathlen = ce_namelen(ce);
274275
if (pathlen <= baselen || memcmp(base, path, baselen))
275276
break; /* at the end of this level */
276277

277278
slash = strchr(path + baselen, '/');
278-
if (!slash)
279+
if (!slash) {
280+
i++;
279281
continue;
282+
}
280283
/*
281284
* a/bbb/c (base = a/, slash = /c)
282285
* ==>
@@ -290,10 +293,13 @@ static int update_one(struct cache_tree *it,
290293
cache + i, entries - i,
291294
path,
292295
baselen + sublen + 1,
296+
&subskip,
293297
flags);
294298
if (subcnt < 0)
295299
return subcnt;
296-
i += subcnt - 1;
300+
i += subcnt;
301+
sub->count = subcnt; /* to be used in the next loop */
302+
*skip_count += subskip;
297303
sub->used = 1;
298304
}
299305

@@ -304,7 +310,8 @@ static int update_one(struct cache_tree *it,
304310
*/
305311
strbuf_init(&buffer, 8192);
306312

307-
for (i = 0; i < entries; i++) {
313+
i = 0;
314+
while (i < entries) {
308315
struct cache_entry *ce = cache[i];
309316
struct cache_tree_sub *sub;
310317
const char *path, *slash;
@@ -324,23 +331,43 @@ static int update_one(struct cache_tree *it,
324331
if (!sub)
325332
die("cache-tree.c: '%.*s' in '%s' not found",
326333
entlen, path + baselen, path);
327-
i += sub->cache_tree->entry_count - 1;
334+
i += sub->count;
328335
sha1 = sub->cache_tree->sha1;
329336
mode = S_IFDIR;
337+
if (sub->cache_tree->entry_count < 0)
338+
to_invalidate = 1;
330339
}
331340
else {
332341
sha1 = ce->sha1;
333342
mode = ce->ce_mode;
334343
entlen = pathlen - baselen;
344+
i++;
335345
}
336346
if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
337347
strbuf_release(&buffer);
338348
return error("invalid object %06o %s for '%.*s'",
339349
mode, sha1_to_hex(sha1), entlen+baselen, path);
340350
}
341351

342-
if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))
343-
continue; /* entry being removed or placeholder */
352+
/*
353+
* CE_REMOVE entries are removed before the index is
354+
* written to disk. Skip them to remain consistent
355+
* with the future on-disk index.
356+
*/
357+
if (ce->ce_flags & CE_REMOVE) {
358+
*skip_count = *skip_count + 1;
359+
continue;
360+
}
361+
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+
}
344371

345372
strbuf_grow(&buffer, entlen + 100);
346373
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
@@ -360,7 +387,7 @@ static int update_one(struct cache_tree *it,
360387
}
361388

362389
strbuf_release(&buffer);
363-
it->entry_count = i;
390+
it->entry_count = to_invalidate ? -1 : i - *skip_count;
364391
#if DEBUG
365392
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
366393
it->entry_count, it->subtree_nr,
@@ -374,11 +401,11 @@ int cache_tree_update(struct cache_tree *it,
374401
int entries,
375402
int flags)
376403
{
377-
int i;
404+
int i, skip;
378405
i = verify_cache(cache, entries, flags);
379406
if (i)
380407
return i;
381-
i = update_one(it, cache, entries, "", 0, flags);
408+
i = update_one(it, cache, entries, "", 0, &skip, flags);
382409
if (i < 0)
383410
return i;
384411
return 0;

cache-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
struct cache_tree;
88
struct cache_tree_sub {
99
struct cache_tree *cache_tree;
10+
int count; /* internally used by update_one() */
1011
int namelen;
1112
int used;
1213
char name[FLEX_ARRAY];

t/t2203-add-intent.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' '
6262
git commit -a -m all
6363
'
6464

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+
6585
test_done
6686

0 commit comments

Comments
 (0)