diff-tree: integrate with sparse index

The index is read in 'cmd_diff_tree' at two points: 1. The first index read was added in fd66bcc31ff (diff-tree: read the index so attribute checks work in bare repositories, 2017-12-06) to deal with reading '.gitattributes' content. 77efbb366ab (attr: be careful about sparse directories, 2021-09-08) established that, in a sparse index, we do _not_ try to load a '.gitattributes' file from within a sparse directory. 2. The second index access point is involved in rename detection, specifically when reading from stdin.This was initially added in f0c6b2a2fd9 ([PATCH] Optimize diff-tree -[CM]--stdin, 2005-05-27), where 'setup' was set to 'DIFF_SETUP_USE_SIZE_CACHE |DIFF_SETUP_USE_CACHE'. That assignment was later modified to drop the'DIFF_SETUP_USE_CACHE' in ff7fe37b053 (diff.c: move read_index() code back to the caller, 2018-08-13).However, 'DIFF_SETUP_USE_SIZE_CACHE' seems to be unused as of 6e0b8ed6d35 (diff.c: do not use a separate "size cache"., 2007-05-07) and nothing about 'detect_rename' otherwise indicates index usage. Hence we can just set the requires-full-index to false for "diff-tree". Add tests that verify that 'git diff-tree' behaves correctly when the sparse index is enabled and test to ensure the index is not expanded. The `p2000` tests demonstrate a ~98% execution time reduction for 'git diff-tree' using a sparse index: Test before after ----------------------------------------------------------------------- 2000.94: git diff-tree HEAD (full-v3) 0.05 0.04 -20.0% 2000.95: git diff-tree HEAD (full-v4) 0.06 0.05 -16.7% 2000.96: git diff-tree HEAD (sparse-v3) 0.59 0.01 -98.3% 2000.97: git diff-tree HEAD (sparse-v4) 0.61 0.01 -98.4% 2000.98: git diff-tree HEAD -- f2/f4/a (full-v3) 0.05 0.05 +0.0% 2000.99: git diff-tree HEAD -- f2/f4/a (full-v4) 0.05 0.04 -20.0% 2000.100: git diff-tree HEAD -- f2/f4/a (sparse-v3) 0.58 0.01 -98.3% 2000.101: git diff-tree HEAD -- f2/f4/a (sparse-v4) 0.55 0.01 -98.2% Helped-by: Victoria Dye <vdye@github.com> Signed-off-by: Shuqi Liang <cheskaqiqi@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shuqi Liang committed May 18, 2023 at 11:44 UTC 48c5fbfb8976c733b7ea550675594a77777db2fa
3 files changed +48
builtin/diff-tree.c
+4
@@ -122,6 +122,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
122 usage(diff_tree_usage);
123
124 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
125 +
126 + prepare_repo_settings(the_repository);
127 + the_repository->settings.command_requires_full_index = 0;
128 +
129 repo_init_revisions(the_repository, opt, prefix);
130 if (repo_read_index(the_repository) < 0)
131 die(_("index file corrupt"));
t/perf/p2000-sparse-operations.sh
+2
@@ -131,5 +131,7 @@ test_perf_on_all git describe --dirty
131 test_perf_on_all 'echo >>new && git describe --dirty'
132 test_perf_on_all git diff-files
133 test_perf_on_all git diff-files -- $SPARSE_CONE/a
134 +test_perf_on_all git diff-tree HEAD
135 +test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a
136
137 test_done
t/t1092-sparse-checkout-compatibility.sh
+42
@@ -2170,4 +2170,46 @@ test_expect_success 'sparse index is not expanded: diff-files' '
2170 ensure_not_expanded diff-files -- "deep/*"
2171 '
2172
2173 +test_expect_success 'diff-tree' '
2174 + init_repos &&
2175 +
2176 + # Test change inside sparse cone
2177 + tree1=$(git -C sparse-index rev-parse HEAD^{tree}) &&
2178 + tree2=$(git -C sparse-index rev-parse update-deep^{tree}) &&
2179 + test_all_match git diff-tree $tree1 $tree2 &&
2180 + test_all_match git diff-tree $tree1 $tree2 -- deep/a &&
2181 + test_all_match git diff-tree HEAD update-deep &&
2182 + test_all_match git diff-tree HEAD update-deep -- deep/a &&
2183 +
2184 + # Test change outside sparse cone
2185 + tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) &&
2186 + test_all_match git diff-tree $tree1 $tree3 &&
2187 + test_all_match git diff-tree $tree1 $tree3 -- folder1/a &&
2188 + test_all_match git diff-tree HEAD update-folder1 &&
2189 + test_all_match git diff-tree HEAD update-folder1 -- folder1/a &&
2190 +
2191 + # Check that SKIP_WORKTREE files are not materialized
2192 + test_path_is_missing sparse-checkout/folder1/a &&
2193 + test_path_is_missing sparse-index/folder1/a &&
2194 + test_path_is_missing sparse-checkout/folder2/a &&
2195 + test_path_is_missing sparse-index/folder2/a
2196 +'
2197 +
2198 +test_expect_success 'sparse-index is not expanded: diff-tree' '
2199 + init_repos &&
2200 +
2201 + tree1=$(git -C sparse-index rev-parse HEAD^{tree}) &&
2202 + tree2=$(git -C sparse-index rev-parse update-deep^{tree}) &&
2203 + tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) &&
2204 +
2205 + ensure_not_expanded diff-tree $tree1 $tree2 &&
2206 + ensure_not_expanded diff-tree $tree1 $tree2 -- deep/a &&
2207 + ensure_not_expanded diff-tree HEAD update-deep &&
2208 + ensure_not_expanded diff-tree HEAD update-deep -- deep/a &&
2209 + ensure_not_expanded diff-tree $tree1 $tree3 &&
2210 + ensure_not_expanded diff-tree $tree1 $tree3 -- folder1/a &&
2211 + ensure_not_expanded diff-tree HEAD update-folder1 &&
2212 + ensure_not_expanded diff-tree HEAD update-folder1 -- folder1/a
2213 +'
2214 +
2215 test_done