Skip to content

Commit 18844c9

Browse files
authored
Merge pull request git-for-windows#424 from vdye/sparse-index/checkout-index
Sparse index: `checkout-index`
2 parents 0bd3c7f + 61c3288 commit 18844c9

File tree

4 files changed

+94
-6
lines changed

4 files changed

+94
-6
lines changed

Documentation/git-checkout-index.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SYNOPSIS
1212
'git checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
1313
[--stage=<number>|all]
1414
[--temp]
15+
[--sparse]
1516
[-z] [--stdin]
1617
[--] [<file>...]
1718

@@ -37,8 +38,9 @@ OPTIONS
3738

3839
-a::
3940
--all::
40-
checks out all files in the index. Cannot be used
41-
together with explicit filenames.
41+
checks out all files in the index, excluding those outside
42+
any specified sparse checkout patterns (see `--sparse`).
43+
Cannot be used together with explicit filenames.
4244

4345
-n::
4446
--no-create::
@@ -59,6 +61,10 @@ OPTIONS
5961
write the content to temporary files. The temporary name
6062
associations will be written to stdout.
6163

64+
--sparse::
65+
Refresh files outside of the sparse checkout boundary. May
66+
only be used in conjunction with `--all`.
67+
6268
--stdin::
6369
Instead of taking list of paths from the command line,
6470
read list of paths from the standard input. Paths are

builtin/checkout-index.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define USE_THE_INDEX_COMPATIBILITY_MACROS
88
#include "builtin.h"
99
#include "config.h"
10+
#include "dir.h"
1011
#include "lockfile.h"
1112
#include "quote.h"
1213
#include "cache-tree.h"
@@ -65,6 +66,7 @@ static int checkout_file(const char *name, const char *prefix)
6566
int namelen = strlen(name);
6667
int pos = cache_name_pos(name, namelen);
6768
int has_same_name = 0;
69+
int is_file = 0;
6870
int did_checkout = 0;
6971
int errs = 0;
7072

@@ -78,6 +80,9 @@ static int checkout_file(const char *name, const char *prefix)
7880
break;
7981
has_same_name = 1;
8082
pos++;
83+
if (S_ISSPARSEDIR(ce->ce_mode))
84+
break;
85+
is_file = 1;
8186
if (ce_stage(ce) != checkout_stage
8287
&& (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
8388
continue;
@@ -106,6 +111,8 @@ static int checkout_file(const char *name, const char *prefix)
106111
fprintf(stderr, "git checkout-index: %s ", name);
107112
if (!has_same_name)
108113
fprintf(stderr, "is not in the cache");
114+
else if (!is_file)
115+
fprintf(stderr, "is a sparse directory");
109116
else if (checkout_stage)
110117
fprintf(stderr, "does not exist at stage %d",
111118
checkout_stage);
@@ -116,15 +123,18 @@ static int checkout_file(const char *name, const char *prefix)
116123
return -1;
117124
}
118125

119-
static int checkout_all(const char *prefix, int prefix_length)
126+
static int checkout_all(const char *prefix, int prefix_length, int include_sparse)
120127
{
121128
int i, errs = 0;
122129
struct cache_entry *last_ce = NULL;
123130

124-
/* TODO: audit for interaction with sparse-index. */
125-
ensure_full_index(&the_index);
131+
if (include_sparse)
132+
ensure_full_index(&the_index);
133+
126134
for (i = 0; i < active_nr ; i++) {
127135
struct cache_entry *ce = active_cache[i];
136+
if (!include_sparse && !path_in_sparse_checkout(ce->name, &the_index))
137+
continue;
128138
if (ce_stage(ce) != checkout_stage
129139
&& (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
130140
continue;
@@ -176,6 +186,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
176186
int i;
177187
struct lock_file lock_file = LOCK_INIT;
178188
int all = 0;
189+
int include_sparse = 0;
179190
int read_from_stdin = 0;
180191
int prefix_length;
181192
int force = 0, quiet = 0, not_new = 0;
@@ -185,6 +196,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
185196
struct option builtin_checkout_index_options[] = {
186197
OPT_BOOL('a', "all", &all,
187198
N_("check out all files in the index")),
199+
OPT_BOOL(0, "sparse", &include_sparse,
200+
N_("do not skip files outside the sparse checkout boundary")),
188201
OPT__FORCE(&force, N_("force overwrite of existing files"), 0),
189202
OPT__QUIET(&quiet,
190203
N_("no warning for existing files and files not in index")),
@@ -212,6 +225,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
212225
git_config(git_default_config, NULL);
213226
prefix_length = prefix ? strlen(prefix) : 0;
214227

228+
prepare_repo_settings(the_repository);
229+
the_repository->settings.command_requires_full_index = 0;
230+
215231
if (read_cache() < 0) {
216232
die("invalid cache");
217233
}
@@ -247,6 +263,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
247263

248264
if (all)
249265
die("git checkout-index: don't mix '--all' and explicit filenames");
266+
if (include_sparse)
267+
die("git checkout-index: don't mix '--sparse' and explicit filenames");
250268
if (read_from_stdin)
251269
die("git checkout-index: don't mix '--stdin' and explicit filenames");
252270
p = prefix_path(prefix, prefix_length, arg);
@@ -280,7 +298,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
280298
}
281299

282300
if (all)
283-
err |= checkout_all(prefix, prefix_length);
301+
err |= checkout_all(prefix, prefix_length, include_sparse);
284302

285303
if (pc_workers > 1)
286304
err |= run_parallel_checkout(&state, pc_workers, pc_threshold,

t/perf/p2000-sparse-operations.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ test_perf_on_all git commit -a -m A
112112
test_perf_on_all git checkout -f -
113113
test_perf_on_all git reset
114114
test_perf_on_all git reset --hard
115+
test_perf_on_all git checkout-index -f --all
115116
test_perf_on_all git update-index --add --remove
116117
test_perf_on_all git diff
117118
test_perf_on_all git diff --staged

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,67 @@ test_expect_success 'cherry-pick with conflicts' '
883883
test_all_match test_must_fail git cherry-pick to-cherry-pick
884884
'
885885

886+
test_expect_success 'checkout-index inside sparse definition' '
887+
init_repos &&
888+
889+
run_on_all rm -f deep/a &&
890+
test_all_match git checkout-index -- deep/a &&
891+
test_all_match git status --porcelain=v2 &&
892+
893+
echo test >>new-a &&
894+
run_on_all cp ../new-a a &&
895+
test_all_match test_must_fail git checkout-index -- a &&
896+
test_all_match git checkout-index -f -- a &&
897+
test_all_match git status --porcelain=v2
898+
'
899+
900+
test_expect_success 'checkout-index outside sparse definition' '
901+
init_repos &&
902+
903+
# File does not exist on disk yet for sparse checkouts, so checkout-index
904+
# succeeds without -f
905+
test_sparse_match git checkout-index -- folder1/a &&
906+
test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
907+
test_cmp sparse-checkout/folder1/a full-checkout/folder1/a &&
908+
909+
run_on_sparse rm -rf folder1 &&
910+
echo test >new-a &&
911+
run_on_sparse mkdir -p folder1 &&
912+
run_on_all cp ../new-a folder1/a &&
913+
914+
test_all_match test_must_fail git checkout-index -- folder1/a &&
915+
test_all_match git checkout-index -f -- folder1/a &&
916+
test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
917+
test_cmp sparse-checkout/folder1/a full-checkout/folder1/a
918+
'
919+
920+
test_expect_success 'checkout-index with folders' '
921+
init_repos &&
922+
923+
# Inside checkout definition
924+
test_all_match test_must_fail git checkout-index -f -- deep/ &&
925+
926+
# Outside checkout definition
927+
# Note: although all tests fail (as expected), the messaging differs. For
928+
# non-sparse index checkouts, the error is that the "file" does not appear
929+
# in the index; for sparse checkouts, the error is explicitly that the
930+
# entry is a sparse directory.
931+
run_on_all test_must_fail git checkout-index -f -- folder1/ &&
932+
test_cmp full-checkout-err sparse-checkout-err &&
933+
! test_cmp full-checkout-err sparse-index-err &&
934+
grep "is a sparse directory" sparse-index-err
935+
'
936+
937+
test_expect_success 'checkout-index --all' '
938+
init_repos &&
939+
940+
test_all_match git checkout-index --all &&
941+
test_sparse_match test_path_is_missing folder1 &&
942+
943+
test_all_match git checkout-index --sparse --all &&
944+
test_all_match test_path_exists folder1
945+
'
946+
886947
test_expect_success 'clean' '
887948
init_repos &&
888949
@@ -983,6 +1044,8 @@ test_expect_success 'sparse-index is not expanded' '
9831044
echo >>sparse-index/untracked.txt &&
9841045
ensure_not_expanded add . &&
9851046
1047+
ensure_not_expanded checkout-index -f a &&
1048+
ensure_not_expanded checkout-index -f --all &&
9861049
for ref in update-deep update-folder1 update-folder2 update-deep
9871050
do
9881051
echo >>sparse-index/README.md &&

0 commit comments

Comments
 (0)