]> git.ipfire.org Git - thirdparty/git.git/commitdiff
sparse-checkout: toggle sparse index from builtin
authorDerrick Stolee <dstolee@microsoft.com>
Tue, 30 Mar 2021 13:11:00 +0000 (13:11 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Mar 2021 19:57:48 +0000 (12:57 -0700)
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 <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-sparse-checkout.txt
builtin/sparse-checkout.c
sparse-index.c
sparse-index.h
t/t1092-sparse-checkout-compatibility.sh

index a0eeaeb02ee31073a5b3989cfbc00e3ab731c3e3..fdcf43f87cb373caa4cfd0b1cb307454bd84f9c0 100644 (file)
@@ -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
index e00b82af727b5d006f05e8a920a9c69d98c3f801..ca63e2c64e9595df0b52850e368e703ae20a4acf 100644 (file)
@@ -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);
index 6f4d95d35b1ef95768f9e437d6393aaa67616639..4c73772c6d6c8f25a5b3c89d47b47b4da4b78a80 100644 (file)
@@ -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.
index 64380e121d8035314f438b40b62c89b98b4a7009..39dcc859735e2b7e7eab933a98414658266cffe9 100644 (file)
@@ -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
index 47f98321785204cc8bda4723562f1807e081ef70..472c5337de1bf486fa14e825633cc6ecf4370390 100755 (executable)
@@ -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