worktree: integrate with sparse-index

The index is read in 'worktree.c' at two points:

1.The 'validate_no_submodules' function, which checks if there are any
submodules present in the worktree.

2.The 'check_clean_worktree' function, which verifies if a worktree is
'clean', i.e., there are no untracked or modified but uncommitted files.
This is done by running the 'git status' command, and an error message
is thrown if the worktree is not clean. Given that 'git status' is
already sparse-aware, the function is also sparse-aware.

Hence we can just set the requires-full-index to false for
"git worktree".

Add tests that verify that 'git worktree' behaves correctly when the
sparse index is enabled and test to ensure the index is not expanded.

The `p2000` tests demonstrate a ~20% execution time reduction for
'git worktree' using a sparse index:

(Note:the p2000 test results didn't reflect the huge speedup because of
the index reading time is minuscule comparing to the filesystem
operations.)

Test                                       before  after
-----------------------------------------------------------------------
2000.102: git worktree add....(full-v3)    3.15    2.82  -10.5%
2000.103: git worktree add....(full-v4)    3.14    2.84  -9.6%
2000.104: git worktree add....(sparse-v3)  2.59    2.14  -16.4%
2000.105: git worktree add....(sparse-v4)  2.10    1.57  -25.2%

Helped-by: Victoria Dye <vdye@github.com>
Signed-off-by: Shuqi Liang <cheskaqiqi@gmail.com>
Acked-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Shuqi Liang 2023-06-06 13:26:33 -04:00 committed by Junio C Hamano
parent fe86abd751
commit 8fac776f44
3 changed files with 42 additions and 0 deletions

View file

@ -1200,5 +1200,9 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
prefix = "";
ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
return fn(ac, av, prefix);
}

View file

@ -131,5 +131,6 @@ test_perf_on_all git describe --dirty
test_perf_on_all 'echo >>new && git describe --dirty'
test_perf_on_all git diff-files
test_perf_on_all git diff-files -- $SPARSE_CONE/a
test_perf_on_all "git worktree add ../temp && git worktree remove ../temp"
test_done

View file

@ -2180,4 +2180,41 @@ test_expect_success 'sparse index is not expanded: diff-files' '
ensure_not_expanded diff-files -- "deep/*"
'
test_expect_success 'worktree' '
init_repos &&
write_script edit-contents <<-\EOF &&
echo text >>"$1"
EOF
for repo in full-checkout sparse-checkout sparse-index
do
worktree=${repo}-wt &&
git -C $repo worktree add ../$worktree &&
# Compare worktree content with "ls"
(cd $repo && ls) >worktree_contents &&
(cd $worktree && ls) >new_worktree_contents &&
test_cmp worktree_contents new_worktree_contents &&
# Compare index content with "ls-files --sparse"
git -C $repo ls-files --sparse >index_contents &&
git -C $worktree ls-files --sparse >new_index_contents &&
test_cmp index_contents new_index_contents &&
git -C $repo worktree remove ../$worktree || return 1
done &&
test_all_match git worktree add .worktrees/hotfix &&
run_on_all ../edit-contents .worktrees/hotfix/deep/a &&
test_all_match test_must_fail git worktree remove .worktrees/hotfix
'
test_expect_success 'worktree is not expanded' '
init_repos &&
ensure_not_expanded worktree add .worktrees/hotfix &&
ensure_not_expanded worktree remove .worktrees/hotfix
'
test_done