diff --git a/builtin/clean.c b/builtin/clean.c index d0ec5e9963917f..92ad3148b4f5c1 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -1010,6 +1010,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix) dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS; } + prepare_repo_settings(the_repository); + the_repository->settings.command_requires_full_index = 0; + if (read_cache() < 0) die(_("index file corrupt")); enable_fscache(active_nr); diff --git a/builtin/stash.c b/builtin/stash.c index 9647b29efe8680..b54bccdd065f40 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -350,7 +350,7 @@ static int restore_untracked(struct object_id *u_tree) child_process_init(&cp); cp.git_cmd = 1; - strvec_pushl(&cp.args, "checkout-index", "--all", NULL); + strvec_pushl(&cp.args, "checkout-index", "--all", "--sparse", NULL); strvec_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", stash_index_path.buf); diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh index 92a2fbdfbf9e37..1259d22222b5cd 100755 --- a/t/perf/p2000-sparse-operations.sh +++ b/t/perf/p2000-sparse-operations.sh @@ -107,6 +107,7 @@ test_perf_on_all () { test_perf_on_all git status test_perf_on_all 'git stash && git stash pop' +test_perf_on_all 'echo >>new && git stash -u && git stash pop' test_perf_on_all git add -A test_perf_on_all git add . test_perf_on_all git commit -a -m A diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 508cf99187d82b..bd2e54f259e545 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1068,23 +1068,42 @@ test_expect_success 'clean' ' test_all_match git commit -m "ignore bogus files" && run_on_sparse mkdir folder1 && + run_on_all mkdir -p deep/untracked-deep && run_on_all touch folder1/bogus && + run_on_all touch folder1/untracked && + run_on_all touch deep/untracked-deep/bogus && + run_on_all touch deep/untracked-deep/untracked && test_all_match git status --porcelain=v2 && test_all_match git clean -f && test_all_match git status --porcelain=v2 && test_sparse_match ls && test_sparse_match ls folder1 && + run_on_all test_path_exists folder1/bogus && + run_on_all test_path_is_missing folder1/untracked && + run_on_all test_path_exists deep/untracked-deep/bogus && + run_on_all test_path_exists deep/untracked-deep/untracked && + + test_all_match git clean -fd && + test_all_match git status --porcelain=v2 && + test_sparse_match ls && + test_sparse_match ls folder1 && + run_on_all test_path_exists folder1/bogus && + run_on_all test_path_exists deep/untracked-deep/bogus && + run_on_all test_path_is_missing deep/untracked-deep/untracked && test_all_match git clean -xf && test_all_match git status --porcelain=v2 && test_sparse_match ls && test_sparse_match ls folder1 && + run_on_all test_path_is_missing folder1/bogus && + run_on_all test_path_exists deep/untracked-deep/bogus && test_all_match git clean -xdf && test_all_match git status --porcelain=v2 && test_sparse_match ls && test_sparse_match ls folder1 && + run_on_all test_path_is_missing deep/untracked-deep/bogus && test_sparse_match test_path_is_dir folder1 ' @@ -1202,6 +1221,8 @@ test_expect_success 'sparse-index is not expanded' ' git -C sparse-index add README.md && ensure_not_expanded diff --staged && + ensure_not_expanded clean -fd && + ensure_not_expanded checkout -f update-deep && ( sane_unset GIT_TEST_MERGE_ALGORITHM && @@ -1280,6 +1301,46 @@ 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' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo text >>$1 + EOF + + run_on_sparse mkdir -p folder1 && + run_on_all ../edit-contents folder1/new && + test_all_match git stash -u && + test_all_match git status --porcelain=v2 && + + test_all_match git stash pop -q && + test_all_match git status --porcelain=v2 +' + # NEEDSWORK: a sparse-checkout behaves differently from a full checkout # in this scenario, but it shouldn't. test_expect_success 'reset mixed and checkout orphan' '