Git fork

ls-files: conditionally leave index sparse

When running 'git ls-files' with a pathspec, the index entries get
filtered according to that pathspec before iterating over them in
show_files(). In 78087097b8 (ls-files: add --sparse option,
2021-12-22), this iteration was prefixed with a check for the '--sparse'
option which allows the command to output directory entries; this
created a pre-loop call to ensure_full_index().

However, when a user runs 'git ls-files' where the pathspec matches
directories that are recursively matched in the sparse-checkout, there
are not any sparse directories that match the pathspec so they would not
be written to the output. The expansion in this case is just a
performance drop for no behavior difference.

Replace this global check to expand the index with a check inside the
loop for a matched sparse directory. If we see one, then expand the
index and continue from the current location. This is safe since the
previous entries in the index did not have any sparse directories and
thus would remain stable in this expansion.

A test in t1092 confirms that this changes the behavior.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Derrick Stolee and committed by
Junio C Hamano
681f26bc f368df43

+23 -3
+10 -3
builtin/ls-files.c
··· 413 413 if (!(show_cached || show_stage || show_deleted || show_modified)) 414 414 return; 415 415 416 - if (!show_sparse_dirs) 417 - ensure_full_index(repo->index); 418 - 419 416 for (i = 0; i < repo->index->cache_nr; i++) { 420 417 const struct cache_entry *ce = repo->index->cache[i]; 421 418 struct stat st; 422 419 int stat_err; 420 + 421 + if (S_ISSPARSEDIR(ce->ce_mode) && !show_sparse_dirs) { 422 + /* 423 + * This is the first time we've hit a sparse dir, 424 + * so expansion will leave the first 'i' entries 425 + * alone. 426 + */ 427 + ensure_full_index(repo->index); 428 + ce = repo->index->cache[i]; 429 + } 423 430 424 431 construct_fullname(&fullname, repo, ce); 425 432
+13
t/t1092-sparse-checkout-compatibility.sh
··· 1506 1506 ensure_not_expanded reset --hard && 1507 1507 ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 && 1508 1508 1509 + ensure_not_expanded ls-files deep/deeper1 && 1510 + 1509 1511 echo >>sparse-index/README.md && 1510 1512 ensure_not_expanded add -A && 1511 1513 echo >>sparse-index/extra.txt && ··· 1607 1609 test_all_match git describe --dirty 1608 1610 ' 1609 1611 1612 + test_expect_success 'ls-files filtering and expansion' ' 1613 + init_repos && 1614 + 1615 + # This filtering will hit a sparse directory midway 1616 + # through the iteration. 1617 + test_all_match git ls-files deep && 1618 + 1619 + # This pathspec will filter the index to only a sparse 1620 + # directory. 1621 + test_all_match git ls-files folder1 1622 + ' 1610 1623 1611 1624 test_expect_success 'sparse-index is not expanded: describe' ' 1612 1625 init_repos &&