@@ -45,6 +45,20 @@ To avoid interfering with other worktrees, it first enables the
When `--cone` is provided, the `core.sparseCheckoutCone` setting is
also set, allowing for better performance with a limited set of
patterns (see 'CONE PATTERN SET' below).
++
+Use the `--[no-]sparse-index` option to toggle the use of the sparse
+index format. This reduces the size of the index to be more closely
+aligned with your sparse-checkout definition. This can have significant
+performance advantages for commands such as `git status` or `git add`.
+This feature is still experimental. Some commands might be slower with
+a sparse index until they are properly integrated with the feature.
++
+**WARNING:** Using a sparse index requires modifying the index in a way
+that is not completely understood by external tools. If you have trouble
+with this compatibility, then run `git sparse-checkout init --no-sparse-index`
+to rewrite your index to not be sparse. Older versions of Git will not
+understand the sparse directory entries index extension and may fail to
+interact with your repository until it is disabled.
'set'::
Write a set of patterns to the sparse-checkout file, as given as
@@ -14,6 +14,7 @@
#include "unpack-trees.h"
#include "wt-status.h"
#include "quote.h"
+#include "sparse-index.h"
static const char *empty_base = "";
@@ -283,12 +284,13 @@ static int set_config(enum sparse_checkout_mode mode)
}
static char const * const builtin_sparse_checkout_init_usage[] = {
- N_("git sparse-checkout init [--cone]"),
+ N_("git sparse-checkout init [--cone] [--[no-]sparse-index]"),
NULL
};
static struct sparse_checkout_init_opts {
int cone_mode;
+ int sparse_index;
} init_opts;
static int sparse_checkout_init(int argc, const char **argv)
@@ -303,11 +305,15 @@ static int sparse_checkout_init(int argc, const char **argv)
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
N_("initialize the sparse-checkout in cone mode")),
+ OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
+ N_("toggle the use of a sparse index")),
OPT_END(),
};
repo_read_index(the_repository);
+ init_opts.sparse_index = -1;
+
argc = parse_options(argc, argv, NULL,
builtin_sparse_checkout_init_options,
builtin_sparse_checkout_init_usage, 0);
@@ -326,6 +332,15 @@ static int sparse_checkout_init(int argc, const char **argv)
sparse_filename = get_sparse_checkout_filename();
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
+ if (init_opts.sparse_index >= 0) {
+ if (set_sparse_index_config(the_repository, init_opts.sparse_index) < 0)
+ die(_("failed to modify sparse-index config"));
+
+ /* force an index rewrite */
+ repo_read_index(the_repository);
+ the_repository->index->updated_workdir = 1;
+ }
+
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
@@ -102,21 +102,32 @@ static int convert_to_sparse_rec(struct index_state *istate,
return num_converted - start_converted;
}
-static int enable_sparse_index(struct repository *repo)
+static int set_index_sparse_config(struct repository *repo, int enable)
{
- const char *config_path = repo_git_path(repo, "config.worktree");
-
- git_config_set_in_file_gently(config_path,
- "index.sparse",
- "true");
+ int res;
+ char *config_path = repo_git_path(repo, "config.worktree");
+ res = git_config_set_in_file_gently(config_path,
+ "index.sparse",
+ enable ? "true" : NULL);
+ free(config_path);
prepare_repo_settings(repo);
repo->settings.sparse_index = 1;
- return 0;
+ return res;
+}
+
+int set_sparse_index_config(struct repository *repo, int enable)
+{
+ int res = set_index_sparse_config(repo, enable);
+
+ prepare_repo_settings(repo);
+ repo->settings.sparse_index = enable;
+ return res;
}
int convert_to_sparse(struct index_state *istate)
{
+ int test_env;
if (istate->split_index || istate->sparse_index ||
!core_apply_sparse_checkout || !core_sparse_checkout_cone)
return 0;
@@ -128,11 +139,9 @@ int convert_to_sparse(struct index_state *istate)
* The GIT_TEST_SPARSE_INDEX environment variable triggers the
* index.sparse config variable to be on.
*/
- if (git_env_bool("GIT_TEST_SPARSE_INDEX", 0)) {
- int err = enable_sparse_index(istate->repo);
- if (err < 0)
- return err;
- }
+ test_env = git_env_bool("GIT_TEST_SPARSE_INDEX", -1);
+ if (test_env >= 0)
+ set_sparse_index_config(istate->repo, test_env);
/*
* Only convert to sparse if index.sparse is set.
@@ -5,4 +5,7 @@ struct index_state;
void ensure_full_index(struct index_state *istate);
int convert_to_sparse(struct index_state *istate);
+struct repository;
+int set_sparse_index_config(struct repository *repo, int enable);
+
#endif
@@ -6,6 +6,7 @@ test_description='compare full workdir to sparse workdir'
# So, disable the check until that integration is complete.
GIT_TEST_CHECK_CACHE_TREE=0
GIT_TEST_SPLIT_INDEX=0
+GIT_TEST_SPARSE_INDEX=
. ./test-lib.sh
@@ -100,25 +101,26 @@ init_repos () {
# initialize sparse-checkout definitions
git -C sparse-checkout sparse-checkout init --cone &&
git -C sparse-checkout sparse-checkout set deep &&
- GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout init --cone &&
- GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set deep
+ git -C sparse-index sparse-checkout init --cone --sparse-index &&
+ test_cmp_config -C sparse-index true index.sparse &&
+ git -C sparse-index sparse-checkout set deep
}
run_on_sparse () {
(
cd sparse-checkout &&
- GIT_TEST_SPARSE_INDEX=0 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
+ "$@" >../sparse-checkout-out 2>../sparse-checkout-err
) &&
(
cd sparse-index &&
- GIT_TEST_SPARSE_INDEX=1 "$@" >../sparse-index-out 2>../sparse-index-err
+ "$@" >../sparse-index-out 2>../sparse-index-err
)
}
run_on_all () {
(
cd full-checkout &&
- GIT_TEST_SPARSE_INDEX=0 "$@" >../full-checkout-out 2>../full-checkout-err
+ "$@" >../full-checkout-out 2>../full-checkout-err
) &&
run_on_sparse "$@"
}
@@ -148,7 +150,7 @@ test_expect_success 'sparse-index contents' '
|| return 1
done &&
- GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set folder1 &&
+ git -C sparse-index sparse-checkout set folder1 &&
test-tool -C sparse-index read-cache --table >cache &&
for dir in deep folder2 x
@@ -158,7 +160,7 @@ test_expect_success 'sparse-index contents' '
|| return 1
done &&
- GIT_TEST_SPARSE_INDEX=1 git -C sparse-index sparse-checkout set deep/deeper1 &&
+ git -C sparse-index sparse-checkout set deep/deeper1 &&
test-tool -C sparse-index read-cache --table >cache &&
for dir in deep/deeper2 folder1 folder2 x
@@ -166,7 +168,14 @@ test_expect_success 'sparse-index contents' '
TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
grep "040000 tree $TREE $dir/" cache \
|| return 1
- done
+ done &&
+
+ # Disabling the sparse-index removes tree entries with full ones
+ git -C sparse-index sparse-checkout init --no-sparse-index &&
+
+ test-tool -C sparse-index read-cache --table >cache &&
+ ! grep "040000 tree" cache &&
+ test_sparse_match test-tool read-cache --table
'
test_expect_success 'expanded in-memory index matches full index' '
@@ -396,19 +405,15 @@ test_expect_success 'submodule handling' '
test_expect_success 'sparse-index is expanded and converted back' '
init_repos &&
- (
- GIT_TEST_SPARSE_INDEX=1 &&
- export GIT_TEST_SPARSE_INDEX &&
- GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
- git -C sparse-index -c core.fsmonitor="" reset --hard &&
- test_region index convert_to_sparse trace2.txt &&
- test_region index ensure_full_index trace2.txt &&
-
- rm trace2.txt &&
- GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
- git -C sparse-index -c core.fsmonitor="" status -uno &&
- test_region index ensure_full_index trace2.txt
- )
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse-index -c core.fsmonitor="" reset --hard &&
+ test_region index convert_to_sparse trace2.txt &&
+ test_region index ensure_full_index trace2.txt &&
+
+ rm trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse-index -c core.fsmonitor="" status -uno &&
+ test_region index ensure_full_index trace2.txt
'
test_done