Skip to content

Commit 122ba1f

Browse files
derrickstoleegitster
authored andcommitted
sparse-checkout: toggle sparse index from builtin
The sparse index extension is used to signal that index writes should be in sparse mode. This was only updated using GIT_TEST_SPARSE_INDEX=1. Add a '--[no-]sparse-index' option to 'git sparse-checkout init' that specifies if the sparse index should be used. It also updates the index to use the correct format, either way. Add a warning in the documentation that the use of a repository extension might reduce compatibility with third-party tools. 'git sparse-checkout init' already sets extension.worktreeConfig, which places most sparse-checkout users outside of the scope of most third-party tools. Update t1092-sparse-checkout-compatibility.sh to use this CLI instead of GIT_TEST_SPARSE_INDEX=1. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 58300f4 commit 122ba1f

File tree

5 files changed

+80
-34
lines changed

5 files changed

+80
-34
lines changed

Documentation/git-sparse-checkout.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ To avoid interfering with other worktrees, it first enables the
4545
When `--cone` is provided, the `core.sparseCheckoutCone` setting is
4646
also set, allowing for better performance with a limited set of
4747
patterns (see 'CONE PATTERN SET' below).
48+
+
49+
Use the `--[no-]sparse-index` option to toggle the use of the sparse
50+
index format. This reduces the size of the index to be more closely
51+
aligned with your sparse-checkout definition. This can have significant
52+
performance advantages for commands such as `git status` or `git add`.
53+
This feature is still experimental. Some commands might be slower with
54+
a sparse index until they are properly integrated with the feature.
55+
+
56+
**WARNING:** Using a sparse index requires modifying the index in a way
57+
that is not completely understood by external tools. If you have trouble
58+
with this compatibility, then run `git sparse-checkout init --no-sparse-index`
59+
to rewrite your index to not be sparse. Older versions of Git will not
60+
understand the sparse directory entries index extension and may fail to
61+
interact with your repository until it is disabled.
4862

4963
'set'::
5064
Write a set of patterns to the sparse-checkout file, as given as

builtin/sparse-checkout.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "unpack-trees.h"
1515
#include "wt-status.h"
1616
#include "quote.h"
17+
#include "sparse-index.h"
1718

1819
static const char *empty_base = "";
1920

@@ -283,12 +284,13 @@ static int set_config(enum sparse_checkout_mode mode)
283284
}
284285

285286
static char const * const builtin_sparse_checkout_init_usage[] = {
286-
N_("git sparse-checkout init [--cone]"),
287+
N_("git sparse-checkout init [--cone] [--[no-]sparse-index]"),
287288
NULL
288289
};
289290

290291
static struct sparse_checkout_init_opts {
291292
int cone_mode;
293+
int sparse_index;
292294
} init_opts;
293295

294296
static int sparse_checkout_init(int argc, const char **argv)
@@ -303,11 +305,15 @@ static int sparse_checkout_init(int argc, const char **argv)
303305
static struct option builtin_sparse_checkout_init_options[] = {
304306
OPT_BOOL(0, "cone", &init_opts.cone_mode,
305307
N_("initialize the sparse-checkout in cone mode")),
308+
OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
309+
N_("toggle the use of a sparse index")),
306310
OPT_END(),
307311
};
308312

309313
repo_read_index(the_repository);
310314

315+
init_opts.sparse_index = -1;
316+
311317
argc = parse_options(argc, argv, NULL,
312318
builtin_sparse_checkout_init_options,
313319
builtin_sparse_checkout_init_usage, 0);
@@ -326,6 +332,15 @@ static int sparse_checkout_init(int argc, const char **argv)
326332
sparse_filename = get_sparse_checkout_filename();
327333
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
328334

335+
if (init_opts.sparse_index >= 0) {
336+
if (set_sparse_index_config(the_repository, init_opts.sparse_index) < 0)
337+
die(_("failed to modify sparse-index config"));
338+
339+
/* force an index rewrite */
340+
repo_read_index(the_repository);
341+
the_repository->index->updated_workdir = 1;
342+
}
343+
329344
/* If we already have a sparse-checkout file, use it. */
330345
if (res >= 0) {
331346
free(sparse_filename);

sparse-index.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,32 @@ static int convert_to_sparse_rec(struct index_state *istate,
102102
return num_converted - start_converted;
103103
}
104104

105-
static int enable_sparse_index(struct repository *repo)
105+
static int set_index_sparse_config(struct repository *repo, int enable)
106106
{
107-
const char *config_path = repo_git_path(repo, "config.worktree");
108-
109-
git_config_set_in_file_gently(config_path,
110-
"index.sparse",
111-
"true");
107+
int res;
108+
char *config_path = repo_git_path(repo, "config.worktree");
109+
res = git_config_set_in_file_gently(config_path,
110+
"index.sparse",
111+
enable ? "true" : NULL);
112+
free(config_path);
112113

113114
prepare_repo_settings(repo);
114115
repo->settings.sparse_index = 1;
115-
return 0;
116+
return res;
117+
}
118+
119+
int set_sparse_index_config(struct repository *repo, int enable)
120+
{
121+
int res = set_index_sparse_config(repo, enable);
122+
123+
prepare_repo_settings(repo);
124+
repo->settings.sparse_index = enable;
125+
return res;
116126
}
117127

118128
int convert_to_sparse(struct index_state *istate)
119129
{
130+
int test_env;
120131
if (istate->split_index || istate->sparse_index ||
121132
!core_apply_sparse_checkout || !core_sparse_checkout_cone)
122133
return 0;
@@ -128,11 +139,9 @@ int convert_to_sparse(struct index_state *istate)
128139
* The GIT_TEST_SPARSE_INDEX environment variable triggers the
129140
* index.sparse config variable to be on.
130141
*/
131-
if (git_env_bool("GIT_TEST_SPARSE_INDEX", 0)) {
132-
int err = enable_sparse_index(istate->repo);
133-
if (err < 0)
134-
return err;
135-
}
142+
test_env = git_env_bool("GIT_TEST_SPARSE_INDEX", -1);
143+
if (test_env >= 0)
144+
set_sparse_index_config(istate->repo, test_env);
136145

137146
/*
138147
* Only convert to sparse if index.sparse is set.

sparse-index.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ struct index_state;
55
void ensure_full_index(struct index_state *istate);
66
int convert_to_sparse(struct index_state *istate);
77

8+
struct repository;
9+
int set_sparse_index_config(struct repository *repo, int enable);
10+
811
#endif

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ test_description='compare full workdir to sparse workdir'
66
# So, disable the check until that integration is complete.
77
GIT_TEST_CHECK_CACHE_TREE=0
88
GIT_TEST_SPLIT_INDEX=0
9+
GIT_TEST_SPARSE_INDEX=
910

1011
. ./test-lib.sh
1112

@@ -100,25 +101,26 @@ init_repos () {
100101
# initialize sparse-checkout definitions
101102
git -C sparse-checkout sparse-checkout init --cone &&
102103
git -C sparse-checkout sparse-checkout set deep &&
103-
GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout init --cone &&
104-
GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set deep
104+
git -C sparse-index sparse-checkout init --cone --sparse-index &&
105+
test_cmp_config -C sparse-index true index.sparse &&
106+
git -C sparse-index sparse-checkout set deep
105107
}
106108

107109
run_on_sparse () {
108110
(
109111
cd sparse-checkout &&
110-
GIT_TEST_SPARSE_INDEX=0 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
112+
"$@" >../sparse-checkout-out 2>../sparse-checkout-err
111113
) &&
112114
(
113115
cd sparse-index &&
114-
GIT_TEST_SPARSE_INDEX=1 "$@" >../sparse-index-out 2>../sparse-index-err
116+
"$@" >../sparse-index-out 2>../sparse-index-err
115117
)
116118
}
117119

118120
run_on_all () {
119121
(
120122
cd full-checkout &&
121-
GIT_TEST_SPARSE_INDEX=0 "$@" >../full-checkout-out 2>../full-checkout-err
123+
"$@" >../full-checkout-out 2>../full-checkout-err
122124
) &&
123125
run_on_sparse "$@"
124126
}
@@ -148,7 +150,7 @@ test_expect_success 'sparse-index contents' '
148150
|| return 1
149151
done &&
150152
151-
GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set folder1 &&
153+
git -C sparse-index sparse-checkout set folder1 &&
152154
153155
test-tool -C sparse-index read-cache --table >cache &&
154156
for dir in deep folder2 x
@@ -158,15 +160,22 @@ test_expect_success 'sparse-index contents' '
158160
|| return 1
159161
done &&
160162
161-
GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set deep/deeper1 &&
163+
git -C sparse-index sparse-checkout set deep/deeper1 &&
162164
163165
test-tool -C sparse-index read-cache --table >cache &&
164166
for dir in deep/deeper2 folder1 folder2 x
165167
do
166168
TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
167169
grep "040000 tree $TREE $dir/" cache \
168170
|| return 1
169-
done
171+
done &&
172+
173+
# Disabling the sparse-index removes tree entries with full ones
174+
git -C sparse-index sparse-checkout init --no-sparse-index &&
175+
176+
test-tool -C sparse-index read-cache --table >cache &&
177+
! grep "040000 tree" cache &&
178+
test_sparse_match test-tool read-cache --table
170179
'
171180

172181
test_expect_success 'expanded in-memory index matches full index' '
@@ -396,19 +405,15 @@ test_expect_success 'submodule handling' '
396405
test_expect_success 'sparse-index is expanded and converted back' '
397406
init_repos &&
398407
399-
(
400-
GIT_TEST_SPARSE_INDEX=1 &&
401-
export GIT_TEST_SPARSE_INDEX &&
402-
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
403-
git -C sparse-index -c core.fsmonitor="" reset --hard &&
404-
test_region index convert_to_sparse trace2.txt &&
405-
test_region index ensure_full_index trace2.txt &&
406-
407-
rm trace2.txt &&
408-
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
409-
git -C sparse-index -c core.fsmonitor="" status -uno &&
410-
test_region index ensure_full_index trace2.txt
411-
)
408+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
409+
git -C sparse-index -c core.fsmonitor="" reset --hard &&
410+
test_region index convert_to_sparse trace2.txt &&
411+
test_region index ensure_full_index trace2.txt &&
412+
413+
rm trace2.txt &&
414+
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
415+
git -C sparse-index -c core.fsmonitor="" status -uno &&
416+
test_region index ensure_full_index trace2.txt
412417
'
413418

414419
test_done

0 commit comments

Comments
 (0)