]> git.ipfire.org Git - thirdparty/git.git/commitdiff
add: allow operating on a sparse-only index
authorDerrick Stolee <dstolee@microsoft.com>
Thu, 29 Jul 2021 14:52:04 +0000 (14:52 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 29 Jul 2021 19:36:34 +0000 (12:36 -0700)
Disable command_requires_full_index for 'git add'. This does not require
any additional removals of ensure_full_index(). The main reason is that
'git add' discovers changes based on the pathspec and the worktree
itself. These are then inserted into the index directly, and calls to
index_name_pos() or index_file_exists() already call expand_to_path() at
the appropriate time to support a sparse-index.

Add a test to check that 'git add -A' and 'git add <file>' does not
expand the index at all, as long as <file> is not within a sparse
directory. This does not help the global 'git add .' case.

We can measure the improvement using p2000-sparse-operations.sh with
these results:

Test                                  HEAD~1           HEAD
------------------------------------------------------------------------------
2000.6: git add -A (full-index-v3)    0.35(0.30+0.05)  0.37(0.29+0.06) +5.7%
2000.7: git add -A (full-index-v4)    0.31(0.26+0.06)  0.33(0.27+0.06) +6.5%
2000.8: git add -A (sparse-index-v3)  0.57(0.53+0.07)  0.05(0.04+0.08) -91.2%
2000.9: git add -A (sparse-index-v4)  0.58(0.55+0.06)  0.05(0.05+0.06) -91.4%

While the 91% improvement seems impressive, it's important to recognize
that previously we had significant overhead for expanding the
sparse-index. Comparing to the full index case, 'git add -A' goes from
0.37s to 0.05s, which is "only" an 86% improvement.

This modification to 'git add' creates some behavior change depending on
the use of a sparse index. We modify a test in t1092 to demonstrate
these changes which will be remedied in future changes.

Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/add.c
t/t1092-sparse-checkout-compatibility.sh

index b773b5a4993e3e0e955199d07a23669f051e0be9..c76e6ddd359e417c5192168dcebea1a8f8dc10b5 100644 (file)
@@ -528,6 +528,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
        require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
 
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
+
        hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
        /*
index 4c3bcb349992f20514810c944130feb017b5a05d..77343cb6d95cac8eef54742f1b738ebc7bbfe0df 100755 (executable)
@@ -340,21 +340,27 @@ test_expect_success 'status/add: outside sparse cone' '
 
        test_sparse_match git status --porcelain=v2 &&
 
-       # This "git add folder1/a" fails with a warning
-       # in the sparse repos, differing from the full
-       # repo. This is intentional.
+       # Adding the path outside of the sparse-checkout cone should fail.
        test_sparse_match test_must_fail git add folder1/a &&
-       test_sparse_match test_must_fail git add --refresh folder1/a &&
-       test_all_match git status --porcelain=v2 &&
+
+       test_must_fail git -C sparse-checkout add --refresh folder1/a 2>sparse-checkout-err &&
+       test_must_fail git -C sparse-index add --refresh folder1/a 2>sparse-index-err &&
+       # NEEDSWORK: A sparse index changes the error message.
+       ! test_cmp sparse-checkout-err sparse-index-err &&
+
+       # NEEDSWORK: Adding a newly-tracked file outside the cone succeeds
+       test_sparse_match git add folder1/new &&
 
        test_all_match git add . &&
        test_all_match git status --porcelain=v2 &&
        test_all_match git commit -m folder1/new &&
+       test_all_match git rev-parse HEAD^{tree} &&
 
        run_on_all ../edit-contents folder1/newer &&
        test_all_match git add folder1/ &&
        test_all_match git status --porcelain=v2 &&
-       test_all_match git commit -m folder1/newer
+       test_all_match git commit -m folder1/newer &&
+       test_all_match git rev-parse HEAD^{tree}
 '
 
 test_expect_success 'checkout and reset --hard' '
@@ -641,7 +647,12 @@ test_expect_success 'sparse-index is not expanded' '
        git -C sparse-index reset --hard &&
        ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 &&
        git -C sparse-index reset --hard &&
-       ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1
+       ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 &&
+
+       echo >>sparse-index/README.md &&
+       ensure_not_expanded add -A &&
+       echo >>sparse-index/extra.txt &&
+       ensure_not_expanded add extra.txt
 '
 
 # NEEDSWORK: a sparse-checkout behaves differently from a full checkout