diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 4ac566b5e22cb2..63500438468b44 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -128,11 +128,18 @@ static int checkout_all(const char *prefix, int prefix_length, int include_spars int i, errs = 0; struct cache_entry *last_ce = NULL; - if (include_sparse) - ensure_full_index(&the_index); - for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; + if (include_sparse && S_ISSPARSEDIR(ce->ce_mode)) { + /* + * If the current entry is a sparse directory (and entries outside the + * sparse checkout definition are included), expand the index and + * continue the loop on the current index position (now pointing to the + * first entry inside the expanded sparse directory). + */ + ensure_full_index(&the_index); + ce = active_cache[i]; + } if (!include_sparse && !path_in_sparse_checkout(ce->name, &the_index)) continue; if (ce_stage(ce) != checkout_stage diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 9b450c070a51ac..e623795b0fb979 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1234,6 +1234,9 @@ test_expect_success 'sparse-index is not expanded' ' ensure_not_expanded stash apply stash@{0} && ensure_not_expanded stash drop stash@{0} && + ensure_not_expanded stash -u && + ensure_not_expanded stash pop && + ensure_not_expanded stash create && oid=$(git -C sparse-index stash create) && ensure_not_expanded stash store -m "test" $oid && @@ -1383,28 +1386,6 @@ test_expect_success 'sparse index is not expanded: read-tree' ' ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest ' -# NEEDSWORK: although the full repository's index is _not_ expanded as part of -# stash, a temporary index, which is _not_ sparse, is created when stashing and -# applying a stash of untracked files. As a result, the test reports that it -# finds an instance of `ensure_full_index`, but it does not carry with it the -# performance implications of expanding the full repository index. -test_expect_success 'sparse index is not expanded: stash -u' ' - init_repos && - - mkdir -p sparse-index/folder1 && - echo >>sparse-index/README.md && - echo >>sparse-index/a && - echo >>sparse-index/folder1/new && - - GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ - git -C sparse-index stash -u && - test_region index ensure_full_index trace2.txt && - - GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ - git -C sparse-index stash pop && - test_region index ensure_full_index trace2.txt -' - # NEEDSWORK: similar to `git add`, untracked files outside of the sparse # checkout definition are successfully stashed and unstashed. test_expect_success 'stash -u outside sparse checkout definition' ' diff --git a/unpack-trees.c b/unpack-trees.c index 614e7ee38660f8..7229a4a820de5c 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1961,6 +1961,30 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options } } + /* + * After unpacking trees, the index will be marked "sparse" if any sparse + * directories have been encountered. However, the index may still be + * sparse if there are no sparse directories. To make sure the index is + * marked "sparse" as often as possible, the index is marked sparse if + * all of the following are true: + * - the command in progress allows use of a sparse index + * - the index is not already sparse + * - cone-mode sparse checkout with sparse index is enabled for the repo + * - all index entries are inside of the sparse checkout cone + */ + if (!repo->settings.command_requires_full_index && !o->result.sparse_index && + core_apply_sparse_checkout && core_sparse_checkout_cone && repo->settings.sparse_index) { + o->result.sparse_index = COLLAPSED; + for (i = 0; i < o->result.cache_nr; i++) { + struct cache_entry *ce = o->result.cache[i]; + + if (!path_in_cone_mode_sparse_checkout(ce->name, &o->result)) { + o->result.sparse_index = COMPLETELY_FULL; + break; + } + } + } + ret = check_updates(o, &o->result) ? (-2) : 0; if (o->dst_index) { move_index_extensions(&o->result, o->src_index);