diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt index 4d33e7be0f5599..cf5d1de8424542 100644 --- a/Documentation/git-checkout-index.txt +++ b/Documentation/git-checkout-index.txt @@ -12,6 +12,7 @@ SYNOPSIS 'git checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=] [--stage=|all] [--temp] + [--sparse] [-z] [--stdin] [--] [...] @@ -37,8 +38,9 @@ OPTIONS -a:: --all:: - checks out all files in the index. Cannot be used - together with explicit filenames. + checks out all files in the index, excluding those outside + any specified sparse checkout patterns (see `--sparse`). + Cannot be used together with explicit filenames. -n:: --no-create:: @@ -59,6 +61,10 @@ OPTIONS write the content to temporary files. The temporary name associations will be written to stdout. +--sparse:: + Refresh files outside of the sparse checkout boundary. May + only be used in conjunction with `--all`. + --stdin:: Instead of taking list of paths from the command line, read list of paths from the standard input. Paths are diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index e21620d964e5e8..a0dbab1246e580 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -7,6 +7,7 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" #include "config.h" +#include "dir.h" #include "lockfile.h" #include "quote.h" #include "cache-tree.h" @@ -116,15 +117,18 @@ static int checkout_file(const char *name, const char *prefix) return -1; } -static int checkout_all(const char *prefix, int prefix_length) +static int checkout_all(const char *prefix, int prefix_length, int include_sparse) { int i, errs = 0; struct cache_entry *last_ce = NULL; - /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); + 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 && !path_in_sparse_checkout(ce->name, &the_index)) + continue; if (ce_stage(ce) != checkout_stage && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce))) continue; @@ -176,6 +180,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) int i; struct lock_file lock_file = LOCK_INIT; int all = 0; + int include_sparse = 0; int read_from_stdin = 0; int prefix_length; int force = 0, quiet = 0, not_new = 0; @@ -185,6 +190,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) struct option builtin_checkout_index_options[] = { OPT_BOOL('a', "all", &all, N_("check out all files in the index")), + OPT_BOOL(0, "sparse", &include_sparse, + N_("do not skip files outside the sparse checkout boundary")), OPT__FORCE(&force, N_("force overwrite of existing files"), 0), OPT__QUIET(&quiet, N_("no warning for existing files and files not in index")), @@ -247,6 +254,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (all) die("git checkout-index: don't mix '--all' and explicit filenames"); + if (include_sparse) + die("git checkout-index: don't mix '--sparse' and explicit filenames"); if (read_from_stdin) die("git checkout-index: don't mix '--stdin' and explicit filenames"); p = prefix_path(prefix, prefix_length, arg); @@ -280,7 +289,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) } if (all) - err |= checkout_all(prefix, prefix_length); + err |= checkout_all(prefix, prefix_length, include_sparse); if (pc_workers > 1) err |= run_parallel_checkout(&state, pc_workers, pc_threshold, diff --git a/builtin/stash.c b/builtin/stash.c index 1ef2017c595dc0..3d4e7ad86c1523 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -365,7 +365,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/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index ac91912828613e..4b096d8712138a 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1049,6 +1049,60 @@ test_expect_success 'cherry-pick with conflicts' ' test_all_match test_must_fail git cherry-pick to-cherry-pick ' +test_expect_success 'checkout-index inside sparse definition' ' + init_repos && + + run_on_all rm -f deep/a && + test_all_match git checkout-index -- deep/a && + test_all_match git status --porcelain=v2 && + + echo test >>new-a && + run_on_all cp ../new-a a && + test_all_match test_must_fail git checkout-index -- a && + test_all_match git checkout-index -f -- a && + test_all_match git status --porcelain=v2 +' + +test_expect_success 'checkout-index outside sparse definition' ' + init_repos && + + # File does not exist on disk yet for sparse checkouts, so checkout-index + # succeeds without -f + test_sparse_match git checkout-index -- folder1/a && + test_cmp sparse-checkout/folder1/a sparse-index/folder1/a && + test_cmp sparse-checkout/folder1/a full-checkout/folder1/a && + + run_on_sparse rm -rf folder1 && + echo test >new-a && + run_on_sparse mkdir -p folder1 && + run_on_all cp ../new-a folder1/a && + + test_all_match test_must_fail git checkout-index -- folder1/a && + test_all_match git checkout-index -f -- folder1/a && + test_cmp sparse-checkout/folder1/a sparse-index/folder1/a && + test_cmp sparse-checkout/folder1/a full-checkout/folder1/a +' + +test_expect_success 'checkout-index with folders' ' + init_repos && + + # Inside checkout definition + test_all_match test_must_fail git checkout-index -f -- deep/ && + + # Outside checkout definition + test_all_match test_must_fail git checkout-index -f -- folder1/ +' + +test_expect_success 'checkout-index --all' ' + init_repos && + + test_all_match git checkout-index --all && + test_sparse_match test_path_is_missing folder1 && + + test_all_match git checkout-index --sparse --all && + test_all_match test_path_exists folder1 +' + test_expect_success 'clean' ' init_repos &&