]>
Commit | Line | Data |
---|---|---|
19a0acc8 DS |
1 | #!/bin/sh |
2 | ||
3 | test_description='compare full workdir to sparse workdir' | |
4 | ||
6e773527 | 5 | GIT_TEST_SPLIT_INDEX=0 |
122ba1f7 | 6 | GIT_TEST_SPARSE_INDEX= |
6e773527 | 7 | |
19a0acc8 DS |
8 | . ./test-lib.sh |
9 | ||
10 | test_expect_success 'setup' ' | |
11 | git init initial-repo && | |
12 | ( | |
ecfc47c0 | 13 | GIT_TEST_SPARSE_INDEX=0 && |
19a0acc8 DS |
14 | cd initial-repo && |
15 | echo a >a && | |
16 | echo "after deep" >e && | |
17 | echo "after folder1" >g && | |
18 | echo "after x" >z && | |
c3a9cecc VD |
19 | mkdir folder1 folder2 deep before x && |
20 | echo "before deep" >before/a && | |
21 | echo "before deep again" >before/b && | |
e669ffb2 | 22 | mkdir deep/deeper1 deep/deeper2 deep/before deep/later && |
19a0acc8 | 23 | mkdir deep/deeper1/deepest && |
1b38efc7 DS |
24 | mkdir deep/deeper1/deepest2 && |
25 | mkdir deep/deeper1/deepest3 && | |
19a0acc8 DS |
26 | echo "after deeper1" >deep/e && |
27 | echo "after deepest" >deep/deeper1/e && | |
28 | cp a folder1 && | |
29 | cp a folder2 && | |
30 | cp a x && | |
31 | cp a deep && | |
e669ffb2 | 32 | cp a deep/before && |
19a0acc8 DS |
33 | cp a deep/deeper1 && |
34 | cp a deep/deeper2 && | |
e669ffb2 | 35 | cp a deep/later && |
19a0acc8 | 36 | cp a deep/deeper1/deepest && |
1b38efc7 DS |
37 | cp a deep/deeper1/deepest2 && |
38 | cp a deep/deeper1/deepest3 && | |
39 | cp -r deep/deeper1/ deep/deeper2 && | |
e669ffb2 DS |
40 | mkdir deep/deeper1/0 && |
41 | mkdir deep/deeper1/0/0 && | |
42 | touch deep/deeper1/0/1 && | |
43 | touch deep/deeper1/0/0/0 && | |
44 | >folder1- && | |
45 | >folder1.x && | |
46 | >folder10 && | |
47 | cp -r deep/deeper1/0 folder1 && | |
48 | cp -r deep/deeper1/0 folder2 && | |
49 | echo >>folder1/0/0/0 && | |
50 | echo >>folder2/0/1 && | |
19a0acc8 DS |
51 | git add . && |
52 | git commit -m "initial commit" && | |
53 | git checkout -b base && | |
54 | for dir in folder1 folder2 deep | |
55 | do | |
a3380639 | 56 | git checkout -b update-$dir base && |
19a0acc8 DS |
57 | echo "updated $dir" >$dir/a && |
58 | git commit -a -m "update $dir" || return 1 | |
59 | done && | |
60 | ||
61 | git checkout -b rename-base base && | |
3d814b5d | 62 | cat >folder1/larger-content <<-\EOF && |
19a0acc8 DS |
63 | matching |
64 | lines | |
65 | help | |
66 | inexact | |
67 | renames | |
68 | EOF | |
69 | cp folder1/larger-content folder2/ && | |
70 | cp folder1/larger-content deep/deeper1/ && | |
71 | git add . && | |
72 | git commit -m "add interesting rename content" && | |
73 | ||
74 | git checkout -b rename-out-to-out rename-base && | |
75 | mv folder1/a folder2/b && | |
76 | mv folder1/larger-content folder2/edited-content && | |
77 | echo >>folder2/edited-content && | |
e669ffb2 DS |
78 | echo >>folder2/0/1 && |
79 | echo stuff >>deep/deeper1/a && | |
19a0acc8 DS |
80 | git add . && |
81 | git commit -m "rename folder1/... to folder2/..." && | |
82 | ||
83 | git checkout -b rename-out-to-in rename-base && | |
84 | mv folder1/a deep/deeper1/b && | |
e669ffb2 DS |
85 | echo more stuff >>deep/deeper1/a && |
86 | rm folder2/0/1 && | |
87 | mkdir folder2/0/1 && | |
88 | echo >>folder2/0/1/1 && | |
19a0acc8 DS |
89 | mv folder1/larger-content deep/deeper1/edited-content && |
90 | echo >>deep/deeper1/edited-content && | |
91 | git add . && | |
92 | git commit -m "rename folder1/... to deep/deeper1/..." && | |
93 | ||
94 | git checkout -b rename-in-to-out rename-base && | |
95 | mv deep/deeper1/a folder1/b && | |
e669ffb2 DS |
96 | echo >>folder2/0/1 && |
97 | rm -rf folder1/0/0 && | |
98 | echo >>folder1/0/0 && | |
19a0acc8 DS |
99 | mv deep/deeper1/larger-content folder1/edited-content && |
100 | echo >>folder1/edited-content && | |
101 | git add . && | |
102 | git commit -m "rename deep/deeper1/... to folder1/..." && | |
103 | ||
70569fad DS |
104 | git checkout -b df-conflict-1 base && |
105 | rm -rf folder1 && | |
106 | echo content >folder1 && | |
107 | git add . && | |
108 | git commit -m "dir to file" && | |
109 | ||
110 | git checkout -b df-conflict-2 base && | |
111 | rm -rf folder2 && | |
112 | echo content >folder2 && | |
113 | git add . && | |
114 | git commit -m "dir to file" && | |
115 | ||
116 | git checkout -b fd-conflict base && | |
117 | rm a && | |
118 | mkdir a && | |
119 | echo content >a/a && | |
120 | git add . && | |
121 | git commit -m "file to dir" && | |
122 | ||
83ad8ca5 DS |
123 | for side in left right |
124 | do | |
125 | git checkout -b merge-$side base && | |
126 | echo $side >>deep/deeper2/a && | |
127 | echo $side >>folder1/a && | |
128 | echo $side >>folder2/a && | |
129 | git add . && | |
130 | git commit -m "$side" || return 1 | |
131 | done && | |
132 | ||
19a0acc8 DS |
133 | git checkout -b deepest base && |
134 | echo "updated deepest" >deep/deeper1/deepest/a && | |
1b38efc7 DS |
135 | echo "updated deepest2" >deep/deeper1/deepest2/a && |
136 | echo "updated deepest3" >deep/deeper1/deepest3/a && | |
19a0acc8 DS |
137 | git commit -a -m "update deepest" && |
138 | ||
139 | git checkout -f base && | |
140 | git reset --hard | |
141 | ) | |
142 | ' | |
143 | ||
144 | init_repos () { | |
145 | rm -rf full-checkout sparse-checkout sparse-index && | |
146 | ||
147 | # create repos in initial state | |
148 | cp -r initial-repo full-checkout && | |
149 | git -C full-checkout reset --hard && | |
150 | ||
151 | cp -r initial-repo sparse-checkout && | |
152 | git -C sparse-checkout reset --hard && | |
ecfc47c0 DS |
153 | |
154 | cp -r initial-repo sparse-index && | |
155 | git -C sparse-index reset --hard && | |
19a0acc8 DS |
156 | |
157 | # initialize sparse-checkout definitions | |
ecfc47c0 DS |
158 | git -C sparse-checkout sparse-checkout init --cone && |
159 | git -C sparse-checkout sparse-checkout set deep && | |
122ba1f7 DS |
160 | git -C sparse-index sparse-checkout init --cone --sparse-index && |
161 | test_cmp_config -C sparse-index true index.sparse && | |
162 | git -C sparse-index sparse-checkout set deep | |
19a0acc8 DS |
163 | } |
164 | ||
7cae7627 SY |
165 | init_repos_as_submodules () { |
166 | git reset --hard && | |
167 | init_repos && | |
168 | git submodule add ./full-checkout && | |
169 | git submodule add ./sparse-checkout && | |
170 | git submodule add ./sparse-index && | |
171 | ||
172 | git submodule status >actual && | |
173 | grep full-checkout actual && | |
174 | grep sparse-checkout actual && | |
175 | grep sparse-index actual | |
176 | } | |
177 | ||
19a0acc8 DS |
178 | run_on_sparse () { |
179 | ( | |
180 | cd sparse-checkout && | |
a96355d8 | 181 | GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err |
ecfc47c0 DS |
182 | ) && |
183 | ( | |
184 | cd sparse-index && | |
a96355d8 | 185 | GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err |
19a0acc8 DS |
186 | ) |
187 | } | |
188 | ||
189 | run_on_all () { | |
190 | ( | |
191 | cd full-checkout && | |
a96355d8 | 192 | GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err |
19a0acc8 | 193 | ) && |
4b3f765a | 194 | run_on_sparse "$@" |
19a0acc8 DS |
195 | } |
196 | ||
197 | test_all_match () { | |
4b3f765a | 198 | run_on_all "$@" && |
19a0acc8 | 199 | test_cmp full-checkout-out sparse-checkout-out && |
6e773527 DS |
200 | test_cmp full-checkout-out sparse-index-out && |
201 | test_cmp full-checkout-err sparse-checkout-err && | |
202 | test_cmp full-checkout-err sparse-index-err | |
19a0acc8 DS |
203 | } |
204 | ||
ecfc47c0 DS |
205 | test_sparse_match () { |
206 | run_on_sparse "$@" && | |
207 | test_cmp sparse-checkout-out sparse-index-out && | |
208 | test_cmp sparse-checkout-err sparse-index-err | |
209 | } | |
210 | ||
edd2cd34 DS |
211 | test_sparse_unstaged () { |
212 | file=$1 && | |
213 | for repo in sparse-checkout sparse-index | |
214 | do | |
215 | # Skip "unmerged" paths | |
216 | git -C $repo diff --staged --diff-filter=u -- "$file" >diff && | |
217 | test_must_be_empty diff || return 1 | |
218 | done | |
219 | } | |
220 | ||
baa73e2b DS |
221 | # Usage: test_sprase_checkout_set "<c1> ... <cN>" "<s1> ... <sM>" |
222 | # Verifies that "git sparse-checkout set <c1> ... <cN>" succeeds and | |
223 | # leaves the sparse index in a state where <s1> ... <sM> are sparse | |
224 | # directories (and <c1> ... <cN> are not). | |
225 | test_sparse_checkout_set () { | |
226 | CONE_DIRS=$1 && | |
227 | SPARSE_DIRS=$2 && | |
8846847a | 228 | git -C sparse-index sparse-checkout set --skip-checks $CONE_DIRS && |
3a9a6ac5 | 229 | git -C sparse-index ls-files --sparse --stage >cache && |
baa73e2b DS |
230 | |
231 | # Check that the directories outside of the sparse-checkout cone | |
232 | # have sparse directory entries. | |
233 | for dir in $SPARSE_DIRS | |
6e773527 DS |
234 | do |
235 | TREE=$(git -C sparse-index rev-parse HEAD:$dir) && | |
3a9a6ac5 | 236 | grep "040000 $TREE 0 $dir/" cache \ |
6e773527 DS |
237 | || return 1 |
238 | done && | |
239 | ||
baa73e2b DS |
240 | # Check that the directories in the sparse-checkout cone |
241 | # are not sparse directory entries. | |
242 | for dir in $CONE_DIRS | |
6e773527 | 243 | do |
8846847a DS |
244 | # Allow TREE to not exist because |
245 | # $dir does not exist at HEAD. | |
246 | TREE=$(git -C sparse-index rev-parse HEAD:$dir) || | |
baa73e2b | 247 | ! grep "040000 $TREE 0 $dir/" cache \ |
6e773527 | 248 | || return 1 |
baa73e2b DS |
249 | done |
250 | } | |
6e773527 | 251 | |
baa73e2b DS |
252 | test_expect_success 'sparse-index contents' ' |
253 | init_repos && | |
6e773527 | 254 | |
baa73e2b DS |
255 | # Remove deep, add three other directories. |
256 | test_sparse_checkout_set \ | |
257 | "folder1 folder2 x" \ | |
258 | "before deep" && | |
259 | ||
260 | # Remove folder1, add deep | |
261 | test_sparse_checkout_set \ | |
262 | "deep folder2 x" \ | |
263 | "before folder1" && | |
264 | ||
265 | # Replace deep with deep/deeper2 (dropping deep/deeper1) | |
266 | # Add folder1 | |
267 | test_sparse_checkout_set \ | |
268 | "deep/deeper2 folder1 folder2 x" \ | |
269 | "before deep/deeper1" && | |
122ba1f7 | 270 | |
8846847a DS |
271 | # Replace deep/deeper2 with deep/deeper1 |
272 | # Replace folder1 with folder1/0/0 | |
273 | # Replace folder2 with non-existent folder2/2/3 | |
274 | # Add non-existent "bogus" | |
275 | test_sparse_checkout_set \ | |
276 | "bogus deep/deeper1 folder1/0/0 folder2/2/3 x" \ | |
277 | "before deep/deeper2 folder2/0" && | |
278 | ||
279 | # Drop down to only files at root | |
280 | test_sparse_checkout_set \ | |
281 | "" \ | |
282 | "before deep folder1 folder2 x" && | |
122ba1f7 | 283 | |
3a9a6ac5 | 284 | # Disabling the sparse-index replaces tree entries with full ones |
122ba1f7 | 285 | git -C sparse-index sparse-checkout init --no-sparse-index && |
3a9a6ac5 | 286 | test_sparse_match git ls-files --stage --sparse |
6e773527 DS |
287 | ' |
288 | ||
2782db3e DS |
289 | test_expect_success 'expanded in-memory index matches full index' ' |
290 | init_repos && | |
3a9a6ac5 | 291 | test_sparse_match git ls-files --stage |
2782db3e DS |
292 | ' |
293 | ||
287fd17e VD |
294 | test_expect_success 'root directory cannot be sparse' ' |
295 | init_repos && | |
296 | ||
297 | # Remove all in-cone files and directories from the index, collapse index | |
298 | # with `git sparse-checkout reapply` | |
299 | git -C sparse-index rm -r . && | |
300 | git -C sparse-index sparse-checkout reapply && | |
301 | ||
302 | # Verify sparse directories still present, root directory is not sparse | |
303 | cat >expect <<-EOF && | |
c3a9cecc | 304 | before/ |
287fd17e VD |
305 | folder1/ |
306 | folder2/ | |
307 | x/ | |
308 | EOF | |
309 | git -C sparse-index ls-files --sparse >actual && | |
310 | test_cmp expect actual | |
311 | ' | |
312 | ||
19a0acc8 DS |
313 | test_expect_success 'status with options' ' |
314 | init_repos && | |
6e773527 | 315 | test_sparse_match ls && |
19a0acc8 DS |
316 | test_all_match git status --porcelain=v2 && |
317 | test_all_match git status --porcelain=v2 -z -u && | |
318 | test_all_match git status --porcelain=v2 -uno && | |
4b3f765a | 319 | run_on_all touch README.md && |
19a0acc8 DS |
320 | test_all_match git status --porcelain=v2 && |
321 | test_all_match git status --porcelain=v2 -z -u && | |
322 | test_all_match git status --porcelain=v2 -uno && | |
323 | test_all_match git add README.md && | |
324 | test_all_match git status --porcelain=v2 && | |
325 | test_all_match git status --porcelain=v2 -z -u && | |
326 | test_all_match git status --porcelain=v2 -uno | |
327 | ' | |
328 | ||
2c521b0e VD |
329 | test_expect_success 'status with diff in unexpanded sparse directory' ' |
330 | init_repos && | |
331 | test_all_match git checkout rename-base && | |
332 | test_all_match git reset --soft rename-out-to-out && | |
333 | test_all_match git status --porcelain=v2 | |
334 | ' | |
335 | ||
bf48e5ac DS |
336 | test_expect_success 'status reports sparse-checkout' ' |
337 | init_repos && | |
338 | git -C sparse-checkout status >full && | |
339 | git -C sparse-index status >sparse && | |
6789275d JH |
340 | test_grep "You are in a sparse checkout with " full && |
341 | test_grep "You are in a sparse checkout." sparse | |
bf48e5ac DS |
342 | ' |
343 | ||
19a0acc8 DS |
344 | test_expect_success 'add, commit, checkout' ' |
345 | init_repos && | |
346 | ||
347 | write_script edit-contents <<-\EOF && | |
348 | echo text >>$1 | |
349 | EOF | |
4b3f765a | 350 | run_on_all ../edit-contents README.md && |
19a0acc8 DS |
351 | |
352 | test_all_match git add README.md && | |
353 | test_all_match git status --porcelain=v2 && | |
354 | test_all_match git commit -m "Add README.md" && | |
355 | ||
356 | test_all_match git checkout HEAD~1 && | |
357 | test_all_match git checkout - && | |
358 | ||
4b3f765a | 359 | run_on_all ../edit-contents README.md && |
19a0acc8 DS |
360 | |
361 | test_all_match git add -A && | |
362 | test_all_match git status --porcelain=v2 && | |
363 | test_all_match git commit -m "Extend README.md" && | |
364 | ||
365 | test_all_match git checkout HEAD~1 && | |
366 | test_all_match git checkout - && | |
367 | ||
4b3f765a | 368 | run_on_all ../edit-contents deep/newfile && |
19a0acc8 DS |
369 | |
370 | test_all_match git status --porcelain=v2 -uno && | |
371 | test_all_match git status --porcelain=v2 && | |
372 | test_all_match git add . && | |
373 | test_all_match git status --porcelain=v2 && | |
374 | test_all_match git commit -m "add deep/newfile" && | |
375 | ||
376 | test_all_match git checkout HEAD~1 && | |
377 | test_all_match git checkout - | |
378 | ' | |
379 | ||
8c5de0d2 | 380 | test_expect_success 'deep changes during checkout' ' |
1b38efc7 DS |
381 | init_repos && |
382 | ||
383 | test_sparse_match git sparse-checkout set deep/deeper1/deepest && | |
384 | test_all_match git checkout deepest && | |
385 | test_all_match git checkout base | |
386 | ' | |
387 | ||
49ff3cb9 VD |
388 | test_expect_success 'checkout with modified sparse directory' ' |
389 | init_repos && | |
390 | ||
391 | test_all_match git checkout rename-in-to-out -- . && | |
392 | test_sparse_match git sparse-checkout reapply && | |
393 | test_all_match git checkout base | |
394 | ' | |
395 | ||
037f8ea6 VD |
396 | test_expect_success 'checkout orphan then non-orphan' ' |
397 | init_repos && | |
398 | ||
399 | test_all_match git checkout --orphan test-orphan && | |
400 | test_all_match git status --porcelain=v2 && | |
401 | test_all_match git checkout base && | |
402 | test_all_match git status --porcelain=v2 | |
403 | ' | |
404 | ||
bfc763df | 405 | test_expect_success 'add outside sparse cone' ' |
edd2cd34 DS |
406 | init_repos && |
407 | ||
408 | run_on_sparse mkdir folder1 && | |
409 | run_on_sparse ../edit-contents folder1/a && | |
410 | run_on_sparse ../edit-contents folder1/newfile && | |
411 | test_sparse_match test_must_fail git add folder1/a && | |
412 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
413 | test_sparse_unstaged folder1/a && | |
105e8b01 DS |
414 | test_sparse_match test_must_fail git add folder1/newfile && |
415 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
416 | test_sparse_unstaged folder1/newfile | |
edd2cd34 DS |
417 | ' |
418 | ||
daa1acef DS |
419 | test_expect_success 'commit including unstaged changes' ' |
420 | init_repos && | |
421 | ||
422 | write_script edit-file <<-\EOF && | |
423 | echo $1 >$2 | |
424 | EOF | |
425 | ||
426 | run_on_all ../edit-file 1 a && | |
427 | run_on_all ../edit-file 1 deep/a && | |
428 | ||
429 | test_all_match git commit -m "-a" -a && | |
430 | test_all_match git status --porcelain=v2 && | |
431 | ||
432 | run_on_all ../edit-file 2 a && | |
433 | run_on_all ../edit-file 2 deep/a && | |
434 | ||
435 | test_all_match git commit -m "--include" --include deep/a && | |
436 | test_all_match git status --porcelain=v2 && | |
437 | test_all_match git commit -m "--include" --include a && | |
438 | test_all_match git status --porcelain=v2 && | |
439 | ||
440 | run_on_all ../edit-file 3 a && | |
441 | run_on_all ../edit-file 3 deep/a && | |
442 | ||
443 | test_all_match git commit -m "--amend" -a --amend && | |
444 | test_all_match git status --porcelain=v2 | |
445 | ' | |
446 | ||
bfc763df | 447 | test_expect_success 'status/add: outside sparse cone' ' |
bf26c06f DS |
448 | init_repos && |
449 | ||
bf26c06f DS |
450 | # folder1 is at HEAD, but outside the sparse cone |
451 | run_on_sparse mkdir folder1 && | |
452 | cp initial-repo/folder1/a sparse-checkout/folder1/a && | |
453 | cp initial-repo/folder1/a sparse-index/folder1/a && | |
454 | ||
455 | test_sparse_match git status && | |
456 | ||
457 | write_script edit-contents <<-\EOF && | |
458 | echo text >>$1 | |
459 | EOF | |
af6a5187 | 460 | run_on_all ../edit-contents folder1/a && |
bf26c06f DS |
461 | run_on_all ../edit-contents folder1/new && |
462 | ||
463 | test_sparse_match git status --porcelain=v2 && | |
464 | ||
5e7cbab1 | 465 | # Adding the path outside of the sparse-checkout cone should fail. |
bf26c06f | 466 | test_sparse_match test_must_fail git add folder1/a && |
edd2cd34 DS |
467 | grep "Disable or modify the sparsity rules" sparse-checkout-err && |
468 | test_sparse_unstaged folder1/a && | |
af6a5187 EN |
469 | test_all_match git add --refresh folder1/a && |
470 | test_must_be_empty sparse-checkout-err && | |
edd2cd34 | 471 | test_sparse_unstaged folder1/a && |
105e8b01 DS |
472 | test_sparse_match test_must_fail git add folder1/new && |
473 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
474 | test_sparse_unstaged folder1/new && | |
0299a696 DS |
475 | test_sparse_match git add --sparse folder1/a && |
476 | test_sparse_match git add --sparse folder1/new && | |
5e7cbab1 | 477 | |
0299a696 | 478 | test_all_match git add --sparse . && |
bf26c06f DS |
479 | test_all_match git status --porcelain=v2 && |
480 | test_all_match git commit -m folder1/new && | |
5e7cbab1 | 481 | test_all_match git rev-parse HEAD^{tree} && |
bf26c06f DS |
482 | |
483 | run_on_all ../edit-contents folder1/newer && | |
0299a696 | 484 | test_all_match git add --sparse folder1/ && |
bf26c06f | 485 | test_all_match git status --porcelain=v2 && |
5e7cbab1 DS |
486 | test_all_match git commit -m folder1/newer && |
487 | test_all_match git rev-parse HEAD^{tree} | |
bf26c06f DS |
488 | ' |
489 | ||
19a0acc8 DS |
490 | test_expect_success 'checkout and reset --hard' ' |
491 | init_repos && | |
492 | ||
493 | test_all_match git checkout update-folder1 && | |
494 | test_all_match git status --porcelain=v2 && | |
495 | ||
496 | test_all_match git checkout update-deep && | |
497 | test_all_match git status --porcelain=v2 && | |
498 | ||
499 | test_all_match git checkout -b reset-test && | |
500 | test_all_match git reset --hard deepest && | |
501 | test_all_match git reset --hard update-folder1 && | |
502 | test_all_match git reset --hard update-folder2 | |
503 | ' | |
504 | ||
338e2a9a | 505 | test_expect_success 'diff --cached' ' |
19a0acc8 DS |
506 | init_repos && |
507 | ||
508 | write_script edit-contents <<-\EOF && | |
509 | echo text >>README.md | |
510 | EOF | |
4b3f765a | 511 | run_on_all ../edit-contents && |
19a0acc8 DS |
512 | |
513 | test_all_match git diff && | |
338e2a9a | 514 | test_all_match git diff --cached && |
19a0acc8 DS |
515 | test_all_match git add README.md && |
516 | test_all_match git diff && | |
338e2a9a | 517 | test_all_match git diff --cached |
19a0acc8 DS |
518 | ' |
519 | ||
70569fad DS |
520 | # NEEDSWORK: sparse-checkout behaves differently from full-checkout when |
521 | # running this test with 'df-conflict-2' after 'df-conflict-1'. | |
e669ffb2 | 522 | test_expect_success 'diff with renames and conflicts' ' |
19a0acc8 DS |
523 | init_repos && |
524 | ||
70569fad DS |
525 | for branch in rename-out-to-out \ |
526 | rename-out-to-in \ | |
527 | rename-in-to-out \ | |
528 | df-conflict-1 \ | |
529 | fd-conflict | |
19a0acc8 DS |
530 | do |
531 | test_all_match git checkout rename-base && | |
e669ffb2 DS |
532 | test_all_match git checkout $branch -- . && |
533 | test_all_match git status --porcelain=v2 && | |
338e2a9a LD |
534 | test_all_match git diff --cached --no-renames && |
535 | test_all_match git diff --cached --find-renames || return 1 | |
e669ffb2 DS |
536 | done |
537 | ' | |
538 | ||
539 | test_expect_success 'diff with directory/file conflicts' ' | |
540 | init_repos && | |
541 | ||
70569fad DS |
542 | for branch in rename-out-to-out \ |
543 | rename-out-to-in \ | |
544 | rename-in-to-out \ | |
e05cdb17 DS |
545 | df-conflict-1 \ |
546 | df-conflict-2 \ | |
70569fad | 547 | fd-conflict |
e669ffb2 DS |
548 | do |
549 | git -C full-checkout reset --hard && | |
550 | test_sparse_match git reset --hard && | |
551 | test_all_match git checkout $branch && | |
552 | test_all_match git checkout rename-base -- . && | |
553 | test_all_match git status --porcelain=v2 && | |
338e2a9a LD |
554 | test_all_match git diff --cached --no-renames && |
555 | test_all_match git diff --cached --find-renames || return 1 | |
19a0acc8 DS |
556 | done |
557 | ' | |
558 | ||
559 | test_expect_success 'log with pathspec outside sparse definition' ' | |
560 | init_repos && | |
561 | ||
562 | test_all_match git log -- a && | |
563 | test_all_match git log -- folder1/a && | |
564 | test_all_match git log -- folder2/a && | |
565 | test_all_match git log -- deep/a && | |
566 | test_all_match git log -- deep/deeper1/a && | |
567 | test_all_match git log -- deep/deeper1/deepest/a && | |
568 | ||
569 | test_all_match git checkout update-folder1 && | |
570 | test_all_match git log -- folder1/a | |
571 | ' | |
572 | ||
573 | test_expect_success 'blame with pathspec inside sparse definition' ' | |
574 | init_repos && | |
575 | ||
add4c864 LD |
576 | for file in a \ |
577 | deep/a \ | |
578 | deep/deeper1/a \ | |
579 | deep/deeper1/deepest/a | |
580 | do | |
0e66bc1b | 581 | test_all_match git blame $file || return 1 |
add4c864 | 582 | done |
19a0acc8 DS |
583 | ' |
584 | ||
add4c864 LD |
585 | # Without a revision specified, blame will error if passed any file that |
586 | # is not present in the working directory (even if the file is tracked). | |
587 | # Here we just verify that this is also true with sparse checkouts. | |
588 | test_expect_success 'blame with pathspec outside sparse definition' ' | |
19a0acc8 | 589 | init_repos && |
add4c864 | 590 | test_sparse_match git sparse-checkout set && |
19a0acc8 | 591 | |
625ff5c3 | 592 | for file in \ |
add4c864 LD |
593 | deep/a \ |
594 | deep/deeper1/a \ | |
595 | deep/deeper1/deepest/a | |
596 | do | |
597 | test_sparse_match test_must_fail git blame $file && | |
598 | cat >expect <<-EOF && | |
599 | fatal: Cannot lstat '"'"'$file'"'"': No such file or directory | |
600 | EOF | |
601 | # We compare sparse-checkout-err and sparse-index-err in | |
602 | # `test_sparse_match`. Given we know they are the same, we | |
603 | # only check the content of sparse-index-err here. | |
625ff5c3 | 604 | test_cmp expect sparse-index-err || return 1 |
add4c864 | 605 | done |
19a0acc8 DS |
606 | ' |
607 | ||
71471b2a | 608 | test_expect_success 'checkout and reset (mixed)' ' |
19a0acc8 DS |
609 | init_repos && |
610 | ||
611 | test_all_match git checkout -b reset-test update-deep && | |
612 | test_all_match git reset deepest && | |
6e773527 | 613 | |
71471b2a VD |
614 | # Because skip-worktree is preserved, resetting to update-folder1 |
615 | # will show worktree changes for folder1/a in full-checkout, but not | |
616 | # in sparse-checkout or sparse-index. | |
617 | git -C full-checkout reset update-folder1 >full-checkout-out && | |
6e773527 | 618 | test_sparse_match git reset update-folder1 && |
71471b2a VD |
619 | grep "M folder1/a" full-checkout-out && |
620 | ! grep "M folder1/a" sparse-checkout-out && | |
621 | run_on_sparse test_path_is_missing folder1 | |
19a0acc8 DS |
622 | ' |
623 | ||
291d77eb | 624 | test_expect_success 'checkout and reset (merge)' ' |
6e773527 DS |
625 | init_repos && |
626 | ||
291d77eb VD |
627 | write_script edit-contents <<-\EOF && |
628 | echo text >>$1 | |
629 | EOF | |
630 | ||
631 | test_all_match git checkout -b reset-test update-deep && | |
632 | run_on_all ../edit-contents a && | |
633 | test_all_match git reset --merge deepest && | |
634 | test_all_match git status --porcelain=v2 && | |
635 | ||
636 | test_all_match git reset --hard update-deep && | |
637 | run_on_all ../edit-contents deep/a && | |
638 | test_all_match test_must_fail git reset --merge deepest | |
639 | ' | |
640 | ||
641 | test_expect_success 'checkout and reset (keep)' ' | |
642 | init_repos && | |
643 | ||
644 | write_script edit-contents <<-\EOF && | |
645 | echo text >>$1 | |
646 | EOF | |
647 | ||
648 | test_all_match git checkout -b reset-test update-deep && | |
649 | run_on_all ../edit-contents a && | |
650 | test_all_match git reset --keep deepest && | |
651 | test_all_match git status --porcelain=v2 && | |
652 | ||
653 | test_all_match git reset --hard update-deep && | |
654 | run_on_all ../edit-contents deep/a && | |
655 | test_all_match test_must_fail git reset --keep deepest | |
656 | ' | |
657 | ||
bfc763df | 658 | test_expect_success 'reset with pathspecs inside sparse definition' ' |
291d77eb VD |
659 | init_repos && |
660 | ||
661 | write_script edit-contents <<-\EOF && | |
662 | echo text >>$1 | |
663 | EOF | |
664 | ||
665 | test_all_match git checkout -b reset-test update-deep && | |
666 | run_on_all ../edit-contents deep/a && | |
667 | ||
668 | test_all_match git reset base -- deep/a && | |
669 | test_all_match git status --porcelain=v2 && | |
670 | ||
671 | test_all_match git reset base -- nonexistent-file && | |
672 | test_all_match git status --porcelain=v2 && | |
673 | ||
674 | test_all_match git reset deepest -- deep && | |
675 | test_all_match git status --porcelain=v2 | |
676 | ' | |
677 | ||
678 | # Although the working tree differs between full and sparse checkouts after | |
679 | # reset, the state of the index is the same. | |
680 | test_expect_success 'reset with pathspecs outside sparse definition' ' | |
681 | init_repos && | |
682 | test_all_match git checkout -b reset-test base && | |
683 | ||
684 | test_sparse_match git reset update-folder1 -- folder1 && | |
685 | git -C full-checkout reset update-folder1 -- folder1 && | |
bb01b26d | 686 | test_all_match git ls-files -s -- folder1 && |
291d77eb VD |
687 | |
688 | test_sparse_match git reset update-folder2 -- folder2/a && | |
689 | git -C full-checkout reset update-folder2 -- folder2/a && | |
bb01b26d | 690 | test_all_match git ls-files -s -- folder2/a |
291d77eb VD |
691 | ' |
692 | ||
693 | test_expect_success 'reset with wildcard pathspec' ' | |
694 | init_repos && | |
695 | ||
696 | test_all_match git reset update-deep -- deep\* && | |
697 | test_all_match git ls-files -s -- deep && | |
698 | ||
699 | test_all_match git reset deepest -- deep\*\*\* && | |
700 | test_all_match git ls-files -s -- deep && | |
701 | ||
702 | # The following `git reset`s result in updating the index on files with | |
703 | # `skip-worktree` enabled. To avoid failing due to discrepencies in reported | |
704 | # "modified" files, `test_sparse_match` reset is performed separately from | |
705 | # "full-checkout" reset, then the index contents of all repos are verified. | |
706 | ||
707 | test_sparse_match git reset update-folder1 -- \*/a && | |
708 | git -C full-checkout reset update-folder1 -- \*/a && | |
709 | test_all_match git ls-files -s -- deep/a folder1/a && | |
710 | ||
711 | test_sparse_match git reset update-folder2 -- folder\* && | |
712 | git -C full-checkout reset update-folder2 -- folder\* && | |
713 | test_all_match git ls-files -s -- folder10 folder1 folder2 && | |
714 | ||
715 | test_sparse_match git reset base -- folder1/\* && | |
716 | git -C full-checkout reset base -- folder1/\* && | |
717 | test_all_match git ls-files -s -- folder1 | |
6e773527 DS |
718 | ' |
719 | ||
b15207b8 VD |
720 | test_expect_success 'reset hard with removed sparse dir' ' |
721 | init_repos && | |
722 | ||
723 | run_on_all git rm -r --sparse folder1 && | |
724 | test_all_match git status --porcelain=v2 && | |
725 | ||
726 | test_all_match git reset --hard && | |
727 | test_all_match git status --porcelain=v2 && | |
728 | ||
729 | cat >expect <<-\EOF && | |
730 | folder1/ | |
731 | EOF | |
732 | ||
733 | git -C sparse-index ls-files --sparse folder1 >out && | |
734 | test_cmp expect out | |
735 | ' | |
736 | ||
e015d4d9 VD |
737 | test_expect_success 'update-index modify outside sparse definition' ' |
738 | init_repos && | |
739 | ||
740 | write_script edit-contents <<-\EOF && | |
741 | echo text >>$1 | |
742 | EOF | |
743 | ||
744 | # Create & modify folder1/a | |
745 | # Note that this setup is a manual way of reaching the erroneous | |
746 | # condition in which a `skip-worktree` enabled, outside-of-cone file | |
747 | # exists on disk. It is used here to ensure `update-index` is stable | |
748 | # and behaves predictably if such a condition occurs. | |
749 | run_on_sparse mkdir -p folder1 && | |
750 | run_on_sparse cp ../initial-repo/folder1/a folder1/a && | |
751 | run_on_all ../edit-contents folder1/a && | |
752 | ||
af6a5187 EN |
753 | # If file has skip-worktree enabled, but the file is present, it is |
754 | # treated the same as if skip-worktree is disabled | |
755 | test_all_match git status --porcelain=v2 && | |
756 | test_all_match git update-index folder1/a && | |
757 | test_all_match git status --porcelain=v2 && | |
e015d4d9 VD |
758 | |
759 | # When skip-worktree is disabled (even on files outside sparse cone), file | |
760 | # is updated in the index | |
761 | test_sparse_match git update-index --no-skip-worktree folder1/a && | |
762 | test_all_match git status --porcelain=v2 && | |
763 | test_all_match git update-index folder1/a && | |
764 | test_all_match git status --porcelain=v2 | |
765 | ' | |
766 | ||
767 | test_expect_success 'update-index --add outside sparse definition' ' | |
768 | init_repos && | |
769 | ||
770 | write_script edit-contents <<-\EOF && | |
771 | echo text >>$1 | |
772 | EOF | |
773 | ||
774 | # Create folder1, add new file | |
775 | run_on_sparse mkdir -p folder1 && | |
776 | run_on_all ../edit-contents folder1/b && | |
777 | ||
778 | # The *untracked* out-of-cone file is added to the index because it does | |
779 | # not have a `skip-worktree` bit to signal that it should be ignored | |
780 | # (unlike in `git add`, which will fail due to the file being outside | |
781 | # the sparse checkout definition). | |
782 | test_all_match git update-index --add folder1/b && | |
783 | test_all_match git status --porcelain=v2 | |
784 | ' | |
785 | ||
786 | # NEEDSWORK: `--remove`, unlike the rest of `update-index`, does not ignore | |
787 | # `skip-worktree` entries by default and will remove them from the index. | |
788 | # The `--ignore-skip-worktree-entries` flag must be used in conjunction with | |
789 | # `--remove` to ignore the `skip-worktree` entries and prevent their removal | |
790 | # from the index. | |
791 | test_expect_success 'update-index --remove outside sparse definition' ' | |
792 | init_repos && | |
793 | ||
794 | # When --ignore-skip-worktree-entries is _not_ specified: | |
795 | # out-of-cone, not-on-disk files are removed from the index | |
796 | test_sparse_match git update-index --remove folder1/a && | |
797 | cat >expect <<-EOF && | |
798 | D folder1/a | |
799 | EOF | |
800 | test_sparse_match git diff --cached --name-status && | |
801 | test_cmp expect sparse-checkout-out && | |
802 | ||
803 | # Reset the state | |
804 | test_all_match git reset --hard && | |
805 | ||
806 | # When --ignore-skip-worktree-entries is specified, out-of-cone | |
807 | # (skip-worktree) files are ignored | |
808 | test_sparse_match git update-index --remove --ignore-skip-worktree-entries folder1/a && | |
809 | test_sparse_match git diff --cached --name-status && | |
810 | test_must_be_empty sparse-checkout-out && | |
811 | ||
812 | # Reset the state | |
813 | test_all_match git reset --hard && | |
814 | ||
815 | # --force-remove supercedes --ignore-skip-worktree-entries, removing | |
816 | # a skip-worktree file from the index (and disk) when both are specified | |
817 | # with --remove | |
818 | test_sparse_match git update-index --force-remove --ignore-skip-worktree-entries folder1/a && | |
819 | cat >expect <<-EOF && | |
820 | D folder1/a | |
821 | EOF | |
822 | test_sparse_match git diff --cached --name-status && | |
823 | test_cmp expect sparse-checkout-out | |
824 | ' | |
825 | ||
826 | test_expect_success 'update-index with directories' ' | |
827 | init_repos && | |
828 | ||
829 | # update-index will exit silently when provided with a directory name | |
830 | # containing a trailing slash | |
831 | test_all_match git update-index deep/ folder1/ && | |
832 | grep "Ignoring path deep/" sparse-checkout-err && | |
833 | grep "Ignoring path folder1/" sparse-checkout-err && | |
834 | ||
835 | # When update-index is given a directory name WITHOUT a trailing slash, it will | |
836 | # behave in different ways depending on the status of the directory on disk: | |
837 | # * if it exists, the command exits with an error ("add individual files instead") | |
838 | # * if it does NOT exist (e.g., in a sparse-checkout), it is assumed to be a | |
839 | # file and either triggers an error ("does not exist and --remove not passed") | |
840 | # or is ignored completely (when using --remove) | |
841 | test_all_match test_must_fail git update-index deep && | |
842 | run_on_all test_must_fail git update-index folder1 && | |
843 | test_must_fail git -C full-checkout update-index --remove folder1 && | |
844 | test_sparse_match git update-index --remove folder1 && | |
845 | test_all_match git status --porcelain=v2 | |
846 | ' | |
847 | ||
848 | test_expect_success 'update-index --again file outside sparse definition' ' | |
849 | init_repos && | |
850 | ||
851 | test_all_match git checkout -b test-reupdate && | |
852 | ||
853 | # Update HEAD without modifying the index to introduce a difference in | |
854 | # folder1/a | |
855 | test_sparse_match git reset --soft update-folder1 && | |
856 | ||
857 | # Because folder1/a differs in the index vs HEAD, | |
858 | # `git update-index --no-skip-worktree --again` will effectively perform | |
859 | # `git update-index --no-skip-worktree folder1/a` and remove the skip-worktree | |
860 | # flag from folder1/a | |
861 | test_sparse_match git update-index --no-skip-worktree --again && | |
862 | test_sparse_match git status --porcelain=v2 && | |
863 | ||
864 | cat >expect <<-EOF && | |
865 | D folder1/a | |
866 | EOF | |
867 | test_sparse_match git diff --name-status && | |
868 | test_cmp expect sparse-checkout-out | |
869 | ' | |
870 | ||
871 | test_expect_success 'update-index --cacheinfo' ' | |
872 | init_repos && | |
873 | ||
874 | deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) && | |
875 | folder2_oid=$(git -C full-checkout rev-parse update-folder2:folder2) && | |
876 | folder1_a_oid=$(git -C full-checkout rev-parse update-folder1:folder1/a) && | |
877 | ||
878 | test_all_match git update-index --cacheinfo 100644 $deep_a_oid deep/a && | |
879 | test_all_match git status --porcelain=v2 && | |
880 | ||
881 | # Cannot add sparse directory, even in sparse index case | |
882 | test_all_match test_must_fail git update-index --add --cacheinfo 040000 $folder2_oid folder2/ && | |
883 | ||
884 | # Sparse match only: the new outside-of-cone entry is added *without* skip-worktree, | |
885 | # so `git status` reports it as "deleted" in the worktree | |
886 | test_sparse_match git update-index --add --cacheinfo 100644 $folder1_a_oid folder1/a && | |
887 | test_sparse_match git status --porcelain=v2 && | |
888 | cat >expect <<-EOF && | |
889 | MD folder1/a | |
890 | EOF | |
891 | test_sparse_match git status --short -- folder1/a && | |
892 | test_cmp expect sparse-checkout-out && | |
893 | ||
894 | # To return folder1/a to "normal" for a sparse checkout (ignored & | |
895 | # outside-of-cone), add the skip-worktree flag. | |
896 | test_sparse_match git update-index --skip-worktree folder1/a && | |
897 | cat >expect <<-EOF && | |
898 | S folder1/a | |
899 | EOF | |
900 | test_sparse_match git ls-files -t -- folder1/a && | |
901 | test_cmp expect sparse-checkout-out | |
902 | ' | |
903 | ||
14bf38cf VD |
904 | for MERGE_TREES in "base HEAD update-folder2" \ |
905 | "update-folder1 update-folder2" \ | |
906 | "update-folder2" | |
907 | do | |
908 | test_expect_success "'read-tree -mu $MERGE_TREES' with files outside sparse definition" ' | |
909 | init_repos && | |
910 | ||
911 | # Although the index matches, without --no-sparse-checkout, outside-of- | |
912 | # definition files will not exist on disk for sparse checkouts | |
913 | test_all_match git read-tree -mu $MERGE_TREES && | |
914 | test_all_match git status --porcelain=v2 && | |
915 | test_path_is_missing sparse-checkout/folder2 && | |
916 | test_path_is_missing sparse-index/folder2 && | |
917 | ||
918 | test_all_match git read-tree --reset -u HEAD && | |
919 | test_all_match git status --porcelain=v2 && | |
920 | ||
921 | test_all_match git read-tree -mu --no-sparse-checkout $MERGE_TREES && | |
922 | test_all_match git status --porcelain=v2 && | |
923 | test_cmp sparse-checkout/folder2/a sparse-index/folder2/a && | |
924 | test_cmp sparse-checkout/folder2/a full-checkout/folder2/a | |
925 | ||
926 | ' | |
927 | done | |
928 | ||
929 | test_expect_success 'read-tree --merge with edit/edit conflicts in sparse directories' ' | |
930 | init_repos && | |
931 | ||
932 | # Merge of multiple changes to same directory (but not same files) should | |
933 | # succeed | |
934 | test_all_match git read-tree -mu base rename-base update-folder1 && | |
935 | test_all_match git status --porcelain=v2 && | |
936 | ||
937 | test_all_match git reset --hard && | |
938 | ||
939 | test_all_match git read-tree -mu rename-base update-folder2 && | |
940 | test_all_match git status --porcelain=v2 && | |
941 | ||
942 | test_all_match git reset --hard && | |
943 | ||
944 | test_all_match test_must_fail git read-tree -mu base update-folder1 rename-out-to-in && | |
945 | test_all_match test_must_fail git read-tree -mu rename-out-to-in update-folder1 | |
946 | ' | |
947 | ||
948 | test_expect_success 'read-tree --prefix' ' | |
949 | init_repos && | |
950 | ||
951 | # If files differing between the index and target <commit-ish> exist | |
952 | # inside the prefix, `read-tree --prefix` should fail | |
953 | test_all_match test_must_fail git read-tree --prefix=deep/ deepest && | |
954 | test_all_match test_must_fail git read-tree --prefix=folder1/ update-folder1 && | |
955 | ||
956 | # If no differing index entries exist matching the prefix, | |
957 | # `read-tree --prefix` updates the index successfully | |
958 | test_all_match git rm -rf deep/deeper1/deepest/ && | |
959 | test_all_match git read-tree --prefix=deep/deeper1/deepest -u deepest && | |
960 | test_all_match git status --porcelain=v2 && | |
961 | ||
ede241c7 | 962 | run_on_all git rm -rf --sparse folder1/ && |
14bf38cf VD |
963 | test_all_match git read-tree --prefix=folder1/ -u update-folder1 && |
964 | test_all_match git status --porcelain=v2 && | |
965 | ||
966 | test_all_match git rm -rf --sparse folder2/0 && | |
967 | test_all_match git read-tree --prefix=folder2/0/ -u rename-out-to-out && | |
968 | test_all_match git status --porcelain=v2 | |
969 | ' | |
970 | ||
971 | test_expect_success 'read-tree --merge with directory-file conflicts' ' | |
972 | init_repos && | |
973 | ||
974 | test_all_match git checkout -b test-branch rename-base && | |
975 | ||
976 | # Although the index matches, without --no-sparse-checkout, outside-of- | |
977 | # definition files will not exist on disk for sparse checkouts | |
978 | test_sparse_match git read-tree -mu rename-out-to-out && | |
979 | test_sparse_match git status --porcelain=v2 && | |
980 | test_path_is_missing sparse-checkout/folder2 && | |
981 | test_path_is_missing sparse-index/folder2 && | |
982 | ||
983 | test_sparse_match git read-tree --reset -u HEAD && | |
984 | test_sparse_match git status --porcelain=v2 && | |
985 | ||
986 | test_sparse_match git read-tree -mu --no-sparse-checkout rename-out-to-out && | |
987 | test_sparse_match git status --porcelain=v2 && | |
988 | test_cmp sparse-checkout/folder2/0/1 sparse-index/folder2/0/1 | |
989 | ' | |
990 | ||
c0b99303 | 991 | test_expect_success 'merge, cherry-pick, and rebase' ' |
19a0acc8 DS |
992 | init_repos && |
993 | ||
5e311edf | 994 | for OPERATION in "merge -m merge" cherry-pick "rebase --apply" "rebase --merge" |
c0b99303 DS |
995 | do |
996 | test_all_match git checkout -B temp update-deep && | |
997 | test_all_match git $OPERATION update-folder1 && | |
998 | test_all_match git rev-parse HEAD^{tree} && | |
999 | test_all_match git $OPERATION update-folder2 && | |
1000 | test_all_match git rev-parse HEAD^{tree} || return 1 | |
1001 | done | |
19a0acc8 DS |
1002 | ' |
1003 | ||
0299a696 | 1004 | test_expect_success 'merge with conflict outside cone' ' |
83ad8ca5 DS |
1005 | init_repos && |
1006 | ||
1007 | test_all_match git checkout -b merge-tip merge-left && | |
1008 | test_all_match git status --porcelain=v2 && | |
1009 | test_all_match test_must_fail git merge -m merge merge-right && | |
1010 | test_all_match git status --porcelain=v2 && | |
1011 | ||
1012 | # Resolve the conflict in different ways: | |
1013 | # 1. Revert to the base | |
1014 | test_all_match git checkout base -- deep/deeper2/a && | |
1015 | test_all_match git status --porcelain=v2 && | |
1016 | ||
1017 | # 2. Add the file with conflict markers | |
49fdd51a DS |
1018 | test_sparse_match test_must_fail git add folder1/a && |
1019 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
1020 | test_sparse_unstaged folder1/a && | |
0299a696 | 1021 | test_all_match git add --sparse folder1/a && |
83ad8ca5 DS |
1022 | test_all_match git status --porcelain=v2 && |
1023 | ||
1024 | # 3. Rename the file to another sparse filename and | |
1025 | # accept conflict markers as resolved content. | |
1026 | run_on_all mv folder2/a folder2/z && | |
49fdd51a DS |
1027 | test_sparse_match test_must_fail git add folder2 && |
1028 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
1029 | test_sparse_unstaged folder2/z && | |
0299a696 | 1030 | test_all_match git add --sparse folder2 && |
83ad8ca5 DS |
1031 | test_all_match git status --porcelain=v2 && |
1032 | ||
1033 | test_all_match git merge --continue && | |
1034 | test_all_match git status --porcelain=v2 && | |
1035 | test_all_match git rev-parse HEAD^{tree} | |
1036 | ' | |
1037 | ||
0299a696 | 1038 | test_expect_success 'cherry-pick/rebase with conflict outside cone' ' |
516680ba DS |
1039 | init_repos && |
1040 | ||
1041 | for OPERATION in cherry-pick rebase | |
1042 | do | |
1043 | test_all_match git checkout -B tip && | |
1044 | test_all_match git reset --hard merge-left && | |
1045 | test_all_match git status --porcelain=v2 && | |
1046 | test_all_match test_must_fail git $OPERATION merge-right && | |
1047 | test_all_match git status --porcelain=v2 && | |
1048 | ||
1049 | # Resolve the conflict in different ways: | |
1050 | # 1. Revert to the base | |
1051 | test_all_match git checkout base -- deep/deeper2/a && | |
1052 | test_all_match git status --porcelain=v2 && | |
1053 | ||
1054 | # 2. Add the file with conflict markers | |
105e8b01 DS |
1055 | # NEEDSWORK: Even though the merge conflict removed the |
1056 | # SKIP_WORKTREE bit from the index entry for folder1/a, we should | |
1057 | # warn that this is a problematic add. | |
49fdd51a DS |
1058 | test_sparse_match test_must_fail git add folder1/a && |
1059 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
1060 | test_sparse_unstaged folder1/a && | |
0299a696 | 1061 | test_all_match git add --sparse folder1/a && |
516680ba DS |
1062 | test_all_match git status --porcelain=v2 && |
1063 | ||
1064 | # 3. Rename the file to another sparse filename and | |
1065 | # accept conflict markers as resolved content. | |
105e8b01 DS |
1066 | # NEEDSWORK: This mode now fails, because folder2/z is |
1067 | # outside of the sparse-checkout cone and does not match an | |
1068 | # existing index entry with the SKIP_WORKTREE bit cleared. | |
516680ba | 1069 | run_on_all mv folder2/a folder2/z && |
49fdd51a DS |
1070 | test_sparse_match test_must_fail git add folder2 && |
1071 | grep "Disable or modify the sparsity rules" sparse-checkout-err && | |
1072 | test_sparse_unstaged folder2/z && | |
0299a696 | 1073 | test_all_match git add --sparse folder2 && |
516680ba DS |
1074 | test_all_match git status --porcelain=v2 && |
1075 | ||
1076 | test_all_match git $OPERATION --continue && | |
1077 | test_all_match git status --porcelain=v2 && | |
1078 | test_all_match git rev-parse HEAD^{tree} || return 1 | |
1079 | done | |
1080 | ' | |
1081 | ||
19a0acc8 DS |
1082 | test_expect_success 'merge with outside renames' ' |
1083 | init_repos && | |
1084 | ||
1085 | for type in out-to-out out-to-in in-to-out | |
1086 | do | |
1087 | test_all_match git reset --hard && | |
1088 | test_all_match git checkout -f -b merge-$type update-deep && | |
1089 | test_all_match git merge -m "$type" rename-$type && | |
1090 | test_all_match git rev-parse HEAD^{tree} || return 1 | |
1091 | done | |
1092 | ' | |
1093 | ||
fc6609d1 DS |
1094 | # Sparse-index fails to convert the index in the |
1095 | # final 'git cherry-pick' command. | |
1096 | test_expect_success 'cherry-pick with conflicts' ' | |
1097 | init_repos && | |
1098 | ||
1099 | write_script edit-conflict <<-\EOF && | |
1100 | echo $1 >conflict | |
1101 | EOF | |
1102 | ||
1103 | test_all_match git checkout -b to-cherry-pick && | |
1104 | run_on_all ../edit-conflict ABC && | |
1105 | test_all_match git add conflict && | |
1106 | test_all_match git commit -m "conflict to pick" && | |
1107 | ||
1108 | test_all_match git checkout -B base HEAD~1 && | |
1109 | run_on_all ../edit-conflict DEF && | |
1110 | test_all_match git add conflict && | |
1111 | test_all_match git commit -m "conflict in base" && | |
1112 | ||
1113 | test_all_match test_must_fail git cherry-pick to-cherry-pick | |
1114 | ' | |
1115 | ||
eae93705 VD |
1116 | test_expect_success 'stash' ' |
1117 | init_repos && | |
1118 | ||
1119 | write_script edit-contents <<-\EOF && | |
1120 | echo text >>$1 | |
1121 | EOF | |
1122 | ||
1123 | # Stash a sparse directory (folder1) | |
1124 | test_all_match git checkout -b test-branch rename-base && | |
1125 | test_all_match git reset --soft rename-out-to-out && | |
1126 | test_all_match git stash && | |
1127 | test_all_match git status --porcelain=v2 && | |
1128 | ||
1129 | # Apply the sparse directory stash without reinstating the index | |
1130 | test_all_match git stash apply -q && | |
1131 | test_all_match git status --porcelain=v2 && | |
1132 | ||
1133 | # Reset to state where stash can be applied | |
1134 | test_sparse_match git sparse-checkout reapply && | |
1135 | test_all_match git reset --hard rename-out-to-out && | |
1136 | ||
1137 | # Apply the sparse directory stash *with* reinstating the index | |
1138 | test_all_match git stash apply --index -q && | |
1139 | test_all_match git status --porcelain=v2 && | |
1140 | ||
1141 | # Reset to state where we will get a conflict applying the stash | |
1142 | test_sparse_match git sparse-checkout reapply && | |
1143 | test_all_match git reset --hard update-folder1 && | |
1144 | ||
1145 | # Apply the sparse directory stash with conflicts | |
1146 | test_all_match test_must_fail git stash apply --index -q && | |
1147 | test_all_match test_must_fail git stash apply -q && | |
1148 | test_all_match git status --porcelain=v2 && | |
1149 | ||
1150 | # Reset to base branch | |
1151 | test_sparse_match git sparse-checkout reapply && | |
1152 | test_all_match git reset --hard base && | |
1153 | ||
1154 | # Stash & unstash an untracked file outside of the sparse checkout | |
1155 | # definition. | |
1156 | run_on_sparse mkdir -p folder1 && | |
1157 | run_on_all ../edit-contents folder1/new && | |
1158 | test_all_match git stash -u && | |
1159 | test_all_match git status --porcelain=v2 && | |
1160 | ||
1161 | test_all_match git stash pop -q && | |
1162 | test_all_match git status --porcelain=v2 | |
1163 | ' | |
1164 | ||
b553ef67 VD |
1165 | test_expect_success 'checkout-index inside sparse definition' ' |
1166 | init_repos && | |
1167 | ||
1168 | run_on_all rm -f deep/a && | |
1169 | test_all_match git checkout-index -- deep/a && | |
1170 | test_all_match git status --porcelain=v2 && | |
1171 | ||
1172 | echo test >>new-a && | |
1173 | run_on_all cp ../new-a a && | |
1174 | test_all_match test_must_fail git checkout-index -- a && | |
1175 | test_all_match git checkout-index -f -- a && | |
1176 | test_all_match git status --porcelain=v2 | |
1177 | ' | |
1178 | ||
1179 | test_expect_success 'checkout-index outside sparse definition' ' | |
1180 | init_repos && | |
1181 | ||
88078f54 VD |
1182 | # Without --ignore-skip-worktree-bits, outside-of-cone files will trigger |
1183 | # an error | |
1184 | test_sparse_match test_must_fail git checkout-index -- folder1/a && | |
6789275d | 1185 | test_grep "folder1/a has skip-worktree enabled" sparse-checkout-err && |
88078f54 VD |
1186 | test_path_is_missing folder1/a && |
1187 | ||
1188 | # With --ignore-skip-worktree-bits, outside-of-cone files are checked out | |
1189 | test_sparse_match git checkout-index --ignore-skip-worktree-bits -- folder1/a && | |
b553ef67 VD |
1190 | test_cmp sparse-checkout/folder1/a sparse-index/folder1/a && |
1191 | test_cmp sparse-checkout/folder1/a full-checkout/folder1/a && | |
1192 | ||
1193 | run_on_sparse rm -rf folder1 && | |
1194 | echo test >new-a && | |
1195 | run_on_sparse mkdir -p folder1 && | |
1196 | run_on_all cp ../new-a folder1/a && | |
1197 | ||
88078f54 VD |
1198 | test_all_match test_must_fail git checkout-index --ignore-skip-worktree-bits -- folder1/a && |
1199 | test_all_match git checkout-index -f --ignore-skip-worktree-bits -- folder1/a && | |
b553ef67 VD |
1200 | test_cmp sparse-checkout/folder1/a sparse-index/folder1/a && |
1201 | test_cmp sparse-checkout/folder1/a full-checkout/folder1/a | |
1202 | ' | |
1203 | ||
1204 | test_expect_success 'checkout-index with folders' ' | |
1205 | init_repos && | |
1206 | ||
1207 | # Inside checkout definition | |
1208 | test_all_match test_must_fail git checkout-index -f -- deep/ && | |
1209 | ||
1210 | # Outside checkout definition | |
35682ada VD |
1211 | # Note: although all tests fail (as expected), the messaging differs. For |
1212 | # non-sparse index checkouts, the error is that the "file" does not appear | |
1213 | # in the index; for sparse checkouts, the error is explicitly that the | |
1214 | # entry is a sparse directory. | |
1215 | run_on_all test_must_fail git checkout-index -f -- folder1/ && | |
1216 | test_cmp full-checkout-err sparse-checkout-err && | |
1217 | ! test_cmp full-checkout-err sparse-index-err && | |
1218 | grep "is a sparse directory" sparse-index-err | |
b553ef67 VD |
1219 | ' |
1220 | ||
88078f54 | 1221 | test_expect_success 'checkout-index --all' ' |
b553ef67 VD |
1222 | init_repos && |
1223 | ||
1224 | test_all_match git checkout-index --all && | |
88078f54 VD |
1225 | test_sparse_match test_path_is_missing folder1 && |
1226 | ||
1227 | # --ignore-skip-worktree-bits will cause `skip-worktree` files to be | |
1228 | # checked out, causing the outside-of-cone `folder1` to exist on-disk | |
1229 | test_all_match git checkout-index --ignore-skip-worktree-bits --all && | |
1230 | test_all_match test_path_exists folder1 | |
b553ef67 VD |
1231 | ' |
1232 | ||
19a0acc8 DS |
1233 | test_expect_success 'clean' ' |
1234 | init_repos && | |
1235 | ||
1236 | echo bogus >>.gitignore && | |
1237 | run_on_all cp ../.gitignore . && | |
1238 | test_all_match git add .gitignore && | |
4b3f765a | 1239 | test_all_match git commit -m "ignore bogus files" && |
19a0acc8 DS |
1240 | |
1241 | run_on_sparse mkdir folder1 && | |
1e9e10e0 | 1242 | run_on_all mkdir -p deep/untracked-deep && |
19a0acc8 | 1243 | run_on_all touch folder1/bogus && |
1e9e10e0 VD |
1244 | run_on_all touch folder1/untracked && |
1245 | run_on_all touch deep/untracked-deep/bogus && | |
1246 | run_on_all touch deep/untracked-deep/untracked && | |
19a0acc8 DS |
1247 | |
1248 | test_all_match git status --porcelain=v2 && | |
1249 | test_all_match git clean -f && | |
1250 | test_all_match git status --porcelain=v2 && | |
6e773527 DS |
1251 | test_sparse_match ls && |
1252 | test_sparse_match ls folder1 && | |
1e9e10e0 VD |
1253 | run_on_all test_path_exists folder1/bogus && |
1254 | run_on_all test_path_is_missing folder1/untracked && | |
1255 | run_on_all test_path_exists deep/untracked-deep/bogus && | |
1256 | run_on_all test_path_exists deep/untracked-deep/untracked && | |
1257 | ||
1258 | test_all_match git clean -fd && | |
1259 | test_all_match git status --porcelain=v2 && | |
1260 | test_sparse_match ls && | |
1261 | test_sparse_match ls folder1 && | |
1262 | run_on_all test_path_exists folder1/bogus && | |
1263 | run_on_all test_path_exists deep/untracked-deep/bogus && | |
1264 | run_on_all test_path_is_missing deep/untracked-deep/untracked && | |
19a0acc8 DS |
1265 | |
1266 | test_all_match git clean -xf && | |
1267 | test_all_match git status --porcelain=v2 && | |
6e773527 DS |
1268 | test_sparse_match ls && |
1269 | test_sparse_match ls folder1 && | |
1e9e10e0 VD |
1270 | run_on_all test_path_is_missing folder1/bogus && |
1271 | run_on_all test_path_exists deep/untracked-deep/bogus && | |
19a0acc8 DS |
1272 | |
1273 | test_all_match git clean -xdf && | |
1274 | test_all_match git status --porcelain=v2 && | |
6e773527 DS |
1275 | test_sparse_match ls && |
1276 | test_sparse_match ls folder1 && | |
1e9e10e0 | 1277 | run_on_all test_path_is_missing deep/untracked-deep/bogus && |
19a0acc8 | 1278 | |
6e773527 | 1279 | test_sparse_match test_path_is_dir folder1 |
19a0acc8 DS |
1280 | ' |
1281 | ||
124b05b2 DS |
1282 | for builtin in show rev-parse |
1283 | do | |
1284 | test_expect_success "$builtin (cached blobs/trees)" " | |
1285 | init_repos && | |
a9e0a49d | 1286 | |
124b05b2 DS |
1287 | test_all_match git $builtin :a && |
1288 | test_all_match git $builtin :deep/a && | |
1289 | test_sparse_match git $builtin :folder1/a && | |
a9e0a49d | 1290 | |
124b05b2 DS |
1291 | # The error message differs depending on whether |
1292 | # the directory exists in the worktree. | |
1293 | test_all_match test_must_fail git $builtin :deep/ && | |
1294 | test_must_fail git -C full-checkout $builtin :folder1/ && | |
1295 | test_sparse_match test_must_fail git $builtin :folder1/ && | |
a37d1442 | 1296 | |
124b05b2 DS |
1297 | # Change the sparse cone for an extra case: |
1298 | run_on_sparse git sparse-checkout set deep/deeper1 && | |
4925adb4 | 1299 | |
124b05b2 DS |
1300 | # deep/deeper2 is a sparse directory in the sparse index. |
1301 | test_sparse_match test_must_fail git $builtin :deep/deeper2/ && | |
4925adb4 | 1302 | |
124b05b2 DS |
1303 | # deep/deeper2/deepest is not in the sparse index, but |
1304 | # will trigger an index expansion. | |
1305 | test_sparse_match test_must_fail git $builtin :deep/deeper2/deepest/ | |
1306 | " | |
1307 | done | |
a9e0a49d | 1308 | |
f442313e DS |
1309 | test_expect_success 'submodule handling' ' |
1310 | init_repos && | |
1311 | ||
105e8b01 | 1312 | test_sparse_match git sparse-checkout add modules && |
f442313e DS |
1313 | test_all_match mkdir modules && |
1314 | test_all_match touch modules/a && | |
1315 | test_all_match git add modules && | |
1316 | test_all_match git commit -m "add modules directory" && | |
1317 | ||
092d3a2b TB |
1318 | test_config_global protocol.file.allow always && |
1319 | ||
f442313e DS |
1320 | run_on_all git submodule add "$(pwd)/initial-repo" modules/sub && |
1321 | test_all_match git commit -m "add submodule" && | |
1322 | ||
1323 | # having a submodule prevents "modules" from collapse | |
105e8b01 | 1324 | test_sparse_match git sparse-checkout set deep/deeper1 && |
3a9a6ac5 DS |
1325 | git -C sparse-index ls-files --sparse --stage >cache && |
1326 | grep "100644 .* modules/a" cache && | |
1327 | grep "160000 $(git -C initial-repo rev-parse HEAD) 0 modules/sub" cache | |
f442313e DS |
1328 | ' |
1329 | ||
86609db9 VD |
1330 | # When working with a sparse index, some commands will need to expand the |
1331 | # index to operate properly. If those commands also write the index back | |
1332 | # to disk, they need to convert the index to sparse before writing. | |
1333 | # This test verifies that both of these events are logged in trace2 logs. | |
0938e6ff DS |
1334 | test_expect_success 'sparse-index is expanded and converted back' ' |
1335 | init_repos && | |
1336 | ||
8c4cbad6 | 1337 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ |
86609db9 | 1338 | git -C sparse-index reset -- folder1/a && |
122ba1f7 | 1339 | test_region index convert_to_sparse trace2.txt && |
78087097 DS |
1340 | test_region index ensure_full_index trace2.txt && |
1341 | ||
1342 | # ls-files expands on read, but does not write. | |
1343 | rm trace2.txt && | |
1344 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ | |
1345 | git -C sparse-index ls-files && | |
d76723ee DS |
1346 | test_region index ensure_full_index trace2.txt |
1347 | ' | |
122ba1f7 | 1348 | |
7ca4fc88 VD |
1349 | test_expect_success 'index.sparse disabled inline uses full index' ' |
1350 | init_repos && | |
1351 | ||
1352 | # When index.sparse is disabled inline with `git status`, the | |
1353 | # index is expanded at the beginning of the execution then never | |
1354 | # converted back to sparse. It is then written to disk as a full index. | |
1355 | rm -f trace2.txt && | |
1356 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ | |
1357 | git -C sparse-index -c index.sparse=false status && | |
1358 | ! test_region index convert_to_sparse trace2.txt && | |
1359 | test_region index ensure_full_index trace2.txt && | |
1360 | ||
1361 | # Since index.sparse is set to true at a repo level, the index | |
1362 | # is converted from full to sparse when read, then never expanded | |
1363 | # over the course of `git status`. It is written to disk as a sparse | |
1364 | # index. | |
1365 | rm -f trace2.txt && | |
1366 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ | |
1367 | git -C sparse-index status && | |
1368 | test_region index convert_to_sparse trace2.txt && | |
1369 | ! test_region index ensure_full_index trace2.txt && | |
1370 | ||
1371 | # Now that the index has been written to disk as sparse, it is not | |
1372 | # converted to sparse (or expanded to full) when read by `git status`. | |
1373 | rm -f trace2.txt && | |
1374 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ | |
1375 | git -C sparse-index status && | |
1376 | ! test_region index convert_to_sparse trace2.txt && | |
1377 | ! test_region index ensure_full_index trace2.txt | |
1378 | ' | |
1379 | ||
8c30be91 | 1380 | run_sparse_index_trace2 () { |
d76723ee | 1381 | rm -f trace2.txt && |
3a58792a VD |
1382 | if test -z "$WITHOUT_UNTRACKED_TXT" |
1383 | then | |
1384 | echo >>sparse-index/untracked.txt | |
1385 | fi && | |
69576367 DS |
1386 | |
1387 | if test "$1" = "!" | |
1388 | then | |
1389 | shift && | |
1390 | test_must_fail env \ | |
8c4cbad6 | 1391 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ |
bcf96cfc SY |
1392 | git -C sparse-index "$@" \ |
1393 | >sparse-index-out \ | |
1394 | 2>sparse-index-error || return 1 | |
69576367 | 1395 | else |
8c4cbad6 | 1396 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ |
bcf96cfc SY |
1397 | git -C sparse-index "$@" \ |
1398 | >sparse-index-out \ | |
1399 | 2>sparse-index-error || return 1 | |
8c30be91 SL |
1400 | fi |
1401 | } | |
1402 | ||
1403 | ensure_expanded () { | |
1404 | run_sparse_index_trace2 "$@" && | |
1405 | test_region index ensure_full_index trace2.txt | |
1406 | } | |
1407 | ||
1408 | ensure_not_expanded () { | |
1409 | run_sparse_index_trace2 "$@" && | |
d76723ee | 1410 | test_region ! index ensure_full_index trace2.txt |
daa1acef DS |
1411 | } |
1412 | ||
1413 | test_expect_success 'sparse-index is not expanded' ' | |
1414 | init_repos && | |
1415 | ||
1416 | ensure_not_expanded status && | |
78087097 | 1417 | ensure_not_expanded ls-files --sparse && |
daa1acef DS |
1418 | ensure_not_expanded commit --allow-empty -m empty && |
1419 | echo >>sparse-index/a && | |
1420 | ensure_not_expanded commit -a -m a && | |
1421 | echo >>sparse-index/a && | |
1422 | ensure_not_expanded commit --include a -m a && | |
1423 | echo >>sparse-index/deep/deeper1/a && | |
1ba5f451 DS |
1424 | ensure_not_expanded commit --include deep/deeper1/a -m deeper && |
1425 | ensure_not_expanded checkout rename-out-to-out && | |
1426 | ensure_not_expanded checkout - && | |
1427 | ensure_not_expanded switch rename-out-to-out && | |
1428 | ensure_not_expanded switch - && | |
20ec2d03 | 1429 | ensure_not_expanded reset --hard && |
1ba5f451 | 1430 | ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 && |
20ec2d03 | 1431 | ensure_not_expanded reset --hard && |
5e7cbab1 DS |
1432 | ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 && |
1433 | ||
1434 | echo >>sparse-index/README.md && | |
1435 | ensure_not_expanded add -A && | |
1436 | echo >>sparse-index/extra.txt && | |
4eaffd81 DS |
1437 | ensure_not_expanded add extra.txt && |
1438 | echo >>sparse-index/untracked.txt && | |
a3380639 DS |
1439 | ensure_not_expanded add . && |
1440 | ||
35682ada VD |
1441 | ensure_not_expanded checkout-index -f a && |
1442 | ensure_not_expanded checkout-index -f --all && | |
20ec2d03 VD |
1443 | for ref in update-deep update-folder1 update-folder2 update-deep |
1444 | do | |
1445 | echo >>sparse-index/README.md && | |
1446 | ensure_not_expanded reset --hard $ref || return 1 | |
1447 | done && | |
1448 | ||
4d1cfc13 | 1449 | ensure_not_expanded reset --mixed base && |
20ec2d03 VD |
1450 | ensure_not_expanded reset --hard update-deep && |
1451 | ensure_not_expanded reset --keep base && | |
1452 | ensure_not_expanded reset --merge update-deep && | |
1453 | ensure_not_expanded reset --hard && | |
1454 | ||
4d1cfc13 VD |
1455 | ensure_not_expanded reset base -- deep/a && |
1456 | ensure_not_expanded reset base -- nonexistent-file && | |
1457 | ensure_not_expanded reset deepest -- deep && | |
1458 | ||
1459 | # Although folder1 is outside the sparse definition, it exists as a | |
1460 | # directory entry in the index, so the pathspec will not force the | |
1461 | # index to be expanded. | |
1462 | ensure_not_expanded reset deepest -- folder1 && | |
1463 | ensure_not_expanded reset deepest -- folder1/ && | |
1464 | ||
1465 | # Wildcard identifies only in-cone files, no index expansion | |
1466 | ensure_not_expanded reset deepest -- deep/\* && | |
1467 | ||
1468 | # Wildcard identifies only full sparse directories, no index expansion | |
1469 | ensure_not_expanded reset deepest -- folder\* && | |
1470 | ||
1e9e10e0 VD |
1471 | ensure_not_expanded clean -fd && |
1472 | ||
a3380639 DS |
1473 | ensure_not_expanded checkout -f update-deep && |
1474 | test_config -C sparse-index pull.twohead ort && | |
1475 | ( | |
1476 | sane_unset GIT_TEST_MERGE_ALGORITHM && | |
516680ba DS |
1477 | for OPERATION in "merge -m merge" cherry-pick rebase |
1478 | do | |
1479 | ensure_not_expanded merge -m merge update-folder1 && | |
1480 | ensure_not_expanded merge -m merge update-folder2 || return 1 | |
1481 | done | |
a3380639 | 1482 | ) |
0938e6ff DS |
1483 | ' |
1484 | ||
69576367 DS |
1485 | test_expect_success 'sparse-index is not expanded: merge conflict in cone' ' |
1486 | init_repos && | |
1487 | ||
1488 | for side in right left | |
1489 | do | |
1490 | git -C sparse-index checkout -b expand-$side base && | |
1491 | echo $side >sparse-index/deep/a && | |
1492 | git -C sparse-index commit -a -m "$side" || return 1 | |
1493 | done && | |
1494 | ||
1495 | ( | |
1496 | sane_unset GIT_TEST_MERGE_ALGORITHM && | |
1497 | git -C sparse-index config pull.twohead ort && | |
1498 | ensure_not_expanded ! merge -m merged expand-right | |
1499 | ) | |
1500 | ' | |
1501 | ||
3a58792a VD |
1502 | test_expect_success 'sparse-index is not expanded: stash' ' |
1503 | init_repos && | |
1504 | ||
1505 | echo >>sparse-index/a && | |
1506 | ensure_not_expanded stash && | |
1507 | ensure_not_expanded stash list && | |
1508 | ensure_not_expanded stash show stash@{0} && | |
874cf2a6 | 1509 | ensure_not_expanded stash apply stash@{0} && |
3a58792a VD |
1510 | ensure_not_expanded stash drop stash@{0} && |
1511 | ||
1512 | echo >>sparse-index/deep/new && | |
491df5f6 | 1513 | ensure_not_expanded stash -u && |
3a58792a VD |
1514 | ( |
1515 | WITHOUT_UNTRACKED_TXT=1 && | |
0f329b9a | 1516 | ensure_not_expanded stash pop |
3a58792a VD |
1517 | ) && |
1518 | ||
1519 | ensure_not_expanded stash create && | |
1520 | oid=$(git -C sparse-index stash create) && | |
1521 | ensure_not_expanded stash store -m "test" $oid && | |
1522 | ensure_not_expanded reset --hard && | |
874cf2a6 | 1523 | ensure_not_expanded stash pop |
3a58792a VD |
1524 | ' |
1525 | ||
748b8d66 RN |
1526 | test_expect_success 'describe tested on all' ' |
1527 | init_repos && | |
1528 | ||
1529 | # Add tag to be read by describe | |
1530 | ||
1531 | run_on_all git tag -a v1.0 -m "Version 1" && | |
1532 | test_all_match git describe --dirty && | |
1533 | run_on_all rm g && | |
1534 | test_all_match git describe --dirty | |
1535 | ' | |
1536 | ||
1537 | ||
1538 | test_expect_success 'sparse-index is not expanded: describe' ' | |
1539 | init_repos && | |
1540 | ||
1541 | # Add tag to be read by describe | |
1542 | ||
1543 | git -C sparse-index tag -a v1.0 -m "Version 1" && | |
1544 | ||
1545 | ensure_not_expanded describe --dirty && | |
1546 | echo "test" >>sparse-index/g && | |
1547 | ensure_not_expanded describe --dirty && | |
1548 | ensure_not_expanded describe | |
1549 | ' | |
1550 | ||
51ba65b5 LD |
1551 | test_expect_success 'sparse index is not expanded: diff' ' |
1552 | init_repos && | |
1553 | ||
1554 | write_script edit-contents <<-\EOF && | |
1555 | echo text >>$1 | |
1556 | EOF | |
1557 | ||
1558 | # Add file within cone | |
1559 | test_sparse_match git sparse-checkout set deep && | |
1560 | run_on_all ../edit-contents deep/testfile && | |
1561 | test_all_match git add deep/testfile && | |
1562 | run_on_all ../edit-contents deep/testfile && | |
1563 | ||
1564 | test_all_match git diff && | |
1565 | test_all_match git diff --cached && | |
1566 | ensure_not_expanded diff && | |
1567 | ensure_not_expanded diff --cached && | |
1568 | ||
1569 | # Add file outside cone | |
1570 | test_all_match git reset --hard && | |
1571 | run_on_all mkdir newdirectory && | |
1572 | run_on_all ../edit-contents newdirectory/testfile && | |
1573 | test_sparse_match git sparse-checkout set newdirectory && | |
1574 | test_all_match git add newdirectory/testfile && | |
1575 | run_on_all ../edit-contents newdirectory/testfile && | |
1576 | test_sparse_match git sparse-checkout set && | |
1577 | ||
1578 | test_all_match git diff && | |
1579 | test_all_match git diff --cached && | |
1580 | ensure_not_expanded diff && | |
1581 | ensure_not_expanded diff --cached && | |
1582 | ||
1583 | # Merge conflict outside cone | |
1584 | # The sparse checkout will report a warning that is not in the | |
1585 | # full checkout, so we use `run_on_all` instead of | |
1586 | # `test_all_match` | |
1587 | run_on_all git reset --hard && | |
1588 | test_all_match git checkout merge-left && | |
1589 | test_all_match test_must_fail git merge merge-right && | |
1590 | ||
1591 | test_all_match git diff && | |
1592 | test_all_match git diff --cached && | |
1593 | ensure_not_expanded diff && | |
1594 | ensure_not_expanded diff --cached | |
1595 | ' | |
1596 | ||
124b05b2 | 1597 | test_expect_success 'sparse index is not expanded: show and rev-parse' ' |
a37d1442 DS |
1598 | init_repos && |
1599 | ||
1600 | ensure_not_expanded show :a && | |
124b05b2 DS |
1601 | ensure_not_expanded show :deep/a && |
1602 | ensure_not_expanded rev-parse :a && | |
1603 | ensure_not_expanded rev-parse :deep/a | |
a37d1442 DS |
1604 | ' |
1605 | ||
c35e9f5e VD |
1606 | test_expect_success 'sparse index is not expanded: update-index' ' |
1607 | init_repos && | |
1608 | ||
1609 | deep_a_oid=$(git -C full-checkout rev-parse update-deep:deep/a) && | |
1610 | ensure_not_expanded update-index --cacheinfo 100644 $deep_a_oid deep/a && | |
1611 | ||
1612 | echo "test" >sparse-index/README.md && | |
1613 | echo "test2" >sparse-index/a && | |
1614 | rm -f sparse-index/deep/a && | |
1615 | ||
1616 | ensure_not_expanded update-index --add README.md && | |
1617 | ensure_not_expanded update-index a && | |
b9ca5e26 VD |
1618 | ensure_not_expanded update-index --remove deep/a && |
1619 | ||
1620 | ensure_not_expanded reset --soft update-deep && | |
1621 | ensure_not_expanded update-index --add --remove --again | |
c35e9f5e VD |
1622 | ' |
1623 | ||
add4c864 LD |
1624 | test_expect_success 'sparse index is not expanded: blame' ' |
1625 | init_repos && | |
1626 | ||
1627 | for file in a \ | |
1628 | deep/a \ | |
1629 | deep/deeper1/a \ | |
1630 | deep/deeper1/deepest/a | |
1631 | do | |
0e66bc1b | 1632 | ensure_not_expanded blame $file || return 1 |
add4c864 LD |
1633 | done |
1634 | ' | |
1635 | ||
5a4e0547 DS |
1636 | test_expect_success 'sparse index is not expanded: fetch/pull' ' |
1637 | init_repos && | |
1638 | ||
1639 | git -C sparse-index remote add full "file://$(pwd)/full-checkout" && | |
1640 | ensure_not_expanded fetch full && | |
1641 | git -C full-checkout commit --allow-empty -m "for pull merge" && | |
1642 | git -C sparse-index commit --allow-empty -m "for pull merge" && | |
1643 | ensure_not_expanded pull full base | |
1644 | ' | |
1645 | ||
2c66a7c8 VD |
1646 | test_expect_success 'sparse index is not expanded: read-tree' ' |
1647 | init_repos && | |
1648 | ||
1649 | ensure_not_expanded checkout -b test-branch update-folder1 && | |
f27c170f VD |
1650 | for MERGE_TREES in "base HEAD update-folder2" \ |
1651 | "base HEAD rename-base" \ | |
1652 | "base update-folder2" \ | |
ab81047a VD |
1653 | "base rename-base" \ |
1654 | "update-folder2" | |
2c66a7c8 VD |
1655 | do |
1656 | ensure_not_expanded read-tree -mu $MERGE_TREES && | |
1657 | ensure_not_expanded reset --hard || return 1 | |
74970392 VD |
1658 | done && |
1659 | ||
1660 | rm -rf sparse-index/deep/deeper2 && | |
1661 | ensure_not_expanded add . && | |
1662 | ensure_not_expanded commit -m "test" && | |
1663 | ||
1664 | ensure_not_expanded read-tree --prefix=deep/deeper2 -u deepest | |
2c66a7c8 VD |
1665 | ' |
1666 | ||
78087097 DS |
1667 | test_expect_success 'ls-files' ' |
1668 | init_repos && | |
1669 | ||
1670 | # Use a smaller sparse-checkout for reduced output | |
1671 | test_sparse_match git sparse-checkout set && | |
1672 | ||
1673 | # Behavior agrees by default. Sparse index is expanded. | |
1674 | test_all_match git ls-files && | |
1675 | ||
1676 | # With --sparse, the sparse index data changes behavior. | |
1677 | git -C sparse-index ls-files --sparse >actual && | |
1678 | ||
1679 | cat >expect <<-\EOF && | |
1680 | a | |
c3a9cecc | 1681 | before/ |
78087097 DS |
1682 | deep/ |
1683 | e | |
1684 | folder1- | |
1685 | folder1.x | |
1686 | folder1/ | |
1687 | folder10 | |
1688 | folder2/ | |
1689 | g | |
1690 | x/ | |
1691 | z | |
1692 | EOF | |
1693 | ||
1694 | test_cmp expect actual && | |
1695 | ||
1696 | # With --sparse and no sparse index, nothing changes. | |
1697 | git -C sparse-checkout ls-files >dense && | |
1698 | git -C sparse-checkout ls-files --sparse >sparse && | |
1699 | test_cmp dense sparse && | |
1700 | ||
1701 | # Set up a strange condition of having a file edit | |
af6a5187 EN |
1702 | # outside of the sparse-checkout cone. We want to verify |
1703 | # that all modes handle this the same, and detect the | |
1704 | # modification. | |
78087097 | 1705 | write_script edit-content <<-\EOF && |
af6a5187 | 1706 | mkdir -p folder1 && |
78087097 DS |
1707 | echo content >>folder1/a |
1708 | EOF | |
af6a5187 | 1709 | run_on_all ../edit-content && |
78087097 | 1710 | |
af6a5187 | 1711 | test_all_match git ls-files --modified && |
78087097 DS |
1712 | |
1713 | git -C sparse-index ls-files --sparse --modified >sparse-index-out && | |
af6a5187 EN |
1714 | cat >expect <<-\EOF && |
1715 | folder1/a | |
1716 | EOF | |
1717 | test_cmp expect sparse-index-out && | |
78087097 DS |
1718 | |
1719 | # Add folder1 to the sparse-checkout cone and | |
1720 | # check that ls-files shows the expanded files. | |
1721 | test_sparse_match git sparse-checkout add folder1 && | |
af6a5187 | 1722 | test_all_match git ls-files --modified && |
78087097 DS |
1723 | |
1724 | test_all_match git ls-files && | |
1725 | git -C sparse-index ls-files --sparse >actual && | |
1726 | ||
1727 | cat >expect <<-\EOF && | |
1728 | a | |
c3a9cecc | 1729 | before/ |
78087097 DS |
1730 | deep/ |
1731 | e | |
1732 | folder1- | |
1733 | folder1.x | |
1734 | folder1/0/0/0 | |
1735 | folder1/0/1 | |
1736 | folder1/a | |
1737 | folder10 | |
1738 | folder2/ | |
1739 | g | |
1740 | x/ | |
1741 | z | |
1742 | EOF | |
1743 | ||
1744 | test_cmp expect actual && | |
1745 | ||
1746 | # Double-check index expansion is avoided | |
1747 | ensure_not_expanded ls-files --sparse | |
1748 | ' | |
1749 | ||
598b1e7d DS |
1750 | test_expect_success 'sparse index is not expanded: sparse-checkout' ' |
1751 | init_repos && | |
1752 | ||
1753 | ensure_not_expanded sparse-checkout set deep/deeper2 && | |
1754 | ensure_not_expanded sparse-checkout set deep/deeper1 && | |
1755 | ensure_not_expanded sparse-checkout set deep && | |
1756 | ensure_not_expanded sparse-checkout add folder1 && | |
1757 | ensure_not_expanded sparse-checkout set deep/deeper1 && | |
1758 | ensure_not_expanded sparse-checkout set folder2 && | |
1759 | ||
1760 | # Demonstrate that the checks that "folder1/a" is a file | |
1761 | # do not cause a sparse-index expansion (since it is in the | |
1762 | # sparse-checkout cone). | |
1763 | echo >>sparse-index/folder2/a && | |
1764 | git -C sparse-index add folder2/a && | |
1765 | ||
1766 | ensure_not_expanded sparse-checkout add folder1 && | |
1767 | ||
1768 | # Skip checks here, since deep/deeper1 is inside a sparse directory | |
1769 | # that must be expanded to check whether `deep/deeper1` is a file | |
1770 | # or not. | |
1771 | ensure_not_expanded sparse-checkout set --skip-checks deep/deeper1 && | |
1772 | ensure_not_expanded sparse-checkout set | |
1773 | ' | |
1774 | ||
e5ca2910 DS |
1775 | # NEEDSWORK: a sparse-checkout behaves differently from a full checkout |
1776 | # in this scenario, but it shouldn't. | |
fe0d5761 DS |
1777 | test_expect_success 'reset mixed and checkout orphan' ' |
1778 | init_repos && | |
1779 | ||
1780 | test_all_match git checkout rename-out-to-in && | |
1781 | ||
1782 | # Sparse checkouts do not agree with full checkouts about | |
1783 | # how to report a directory/file conflict during a reset. | |
1784 | # This command would fail with test_all_match because the | |
1785 | # full checkout reports "T folder1/0/1" while a sparse | |
1786 | # checkout reports "D folder1/0/1". This matches because | |
1787 | # the sparse checkouts skip "adding" the other side of | |
1788 | # the conflict. | |
1789 | test_sparse_match git reset --mixed HEAD~1 && | |
3a9a6ac5 | 1790 | test_sparse_match git ls-files --stage && |
fe0d5761 DS |
1791 | test_sparse_match git status --porcelain=v2 && |
1792 | ||
1793 | # At this point, sparse-checkouts behave differently | |
1794 | # from the full-checkout. | |
1795 | test_sparse_match git checkout --orphan new-branch && | |
3a9a6ac5 | 1796 | test_sparse_match git ls-files --stage && |
fe0d5761 DS |
1797 | test_sparse_match git status --porcelain=v2 |
1798 | ' | |
1799 | ||
1800 | test_expect_success 'add everything with deep new file' ' | |
1801 | init_repos && | |
1802 | ||
1803 | run_on_sparse git sparse-checkout set deep/deeper1/deepest && | |
1804 | ||
1805 | run_on_all touch deep/deeper1/x && | |
1806 | test_all_match git add . && | |
1807 | test_all_match git status --porcelain=v2 | |
1808 | ' | |
1809 | ||
70569fad DS |
1810 | # NEEDSWORK: 'git checkout' behaves incorrectly in the case of |
1811 | # directory/file conflicts, even without sparse-checkout. Use this | |
1812 | # test only as a documentation of the incorrect behavior, not a | |
1813 | # measure of how it _should_ behave. | |
1814 | test_expect_success 'checkout behaves oddly with df-conflict-1' ' | |
1815 | init_repos && | |
1816 | ||
1817 | test_sparse_match git sparse-checkout disable && | |
1818 | ||
1819 | write_script edit-content <<-\EOF && | |
1820 | echo content >>folder1/larger-content | |
1821 | git add folder1 | |
1822 | EOF | |
1823 | ||
1824 | run_on_all ../edit-content && | |
1825 | test_all_match git status --porcelain=v2 && | |
1826 | ||
1827 | git -C sparse-checkout sparse-checkout init --cone && | |
1828 | git -C sparse-index sparse-checkout init --cone --sparse-index && | |
1829 | ||
1830 | test_all_match git status --porcelain=v2 && | |
1831 | ||
1832 | # This checkout command should fail, because we have a staged | |
1833 | # change to folder1/larger-content, but the destination changes | |
1834 | # folder1 to a file. | |
1835 | git -C full-checkout checkout df-conflict-1 \ | |
1836 | 1>full-checkout-out \ | |
1837 | 2>full-checkout-err && | |
1838 | git -C sparse-checkout checkout df-conflict-1 \ | |
1839 | 1>sparse-checkout-out \ | |
1840 | 2>sparse-checkout-err && | |
e05cdb17 | 1841 | git -C sparse-index checkout df-conflict-1 \ |
70569fad DS |
1842 | 1>sparse-index-out \ |
1843 | 2>sparse-index-err && | |
1844 | ||
1845 | # Instead, the checkout deletes the folder1 file and adds the | |
1846 | # folder1/larger-content file, leaving all other paths that were | |
1847 | # in folder1/ as deleted (without any warning). | |
1848 | cat >expect <<-EOF && | |
1849 | D folder1 | |
1850 | A folder1/larger-content | |
1851 | EOF | |
1852 | test_cmp expect full-checkout-out && | |
1853 | test_cmp expect sparse-checkout-out && | |
1854 | ||
e05cdb17 DS |
1855 | # The sparse-index reports no output |
1856 | test_must_be_empty sparse-index-out && | |
1857 | ||
70569fad | 1858 | # stderr: Switched to branch df-conflict-1 |
e05cdb17 | 1859 | test_cmp full-checkout-err sparse-checkout-err && |
70569fad DS |
1860 | test_cmp full-checkout-err sparse-checkout-err |
1861 | ' | |
1862 | ||
1863 | # NEEDSWORK: 'git checkout' behaves incorrectly in the case of | |
1864 | # directory/file conflicts, even without sparse-checkout. Use this | |
1865 | # test only as a documentation of the incorrect behavior, not a | |
1866 | # measure of how it _should_ behave. | |
1867 | test_expect_success 'checkout behaves oddly with df-conflict-2' ' | |
1868 | init_repos && | |
1869 | ||
1870 | test_sparse_match git sparse-checkout disable && | |
1871 | ||
1872 | write_script edit-content <<-\EOF && | |
1873 | echo content >>folder2/larger-content | |
1874 | git add folder2 | |
1875 | EOF | |
1876 | ||
1877 | run_on_all ../edit-content && | |
1878 | test_all_match git status --porcelain=v2 && | |
1879 | ||
1880 | git -C sparse-checkout sparse-checkout init --cone && | |
1881 | git -C sparse-index sparse-checkout init --cone --sparse-index && | |
1882 | ||
1883 | test_all_match git status --porcelain=v2 && | |
1884 | ||
1885 | # This checkout command should fail, because we have a staged | |
1886 | # change to folder1/larger-content, but the destination changes | |
1887 | # folder1 to a file. | |
1888 | git -C full-checkout checkout df-conflict-2 \ | |
1889 | 1>full-checkout-out \ | |
1890 | 2>full-checkout-err && | |
1891 | git -C sparse-checkout checkout df-conflict-2 \ | |
1892 | 1>sparse-checkout-out \ | |
1893 | 2>sparse-checkout-err && | |
e05cdb17 | 1894 | git -C sparse-index checkout df-conflict-2 \ |
70569fad DS |
1895 | 1>sparse-index-out \ |
1896 | 2>sparse-index-err && | |
1897 | ||
1898 | # The full checkout deviates from the df-conflict-1 case here! | |
1899 | # It drops the change to folder1/larger-content and leaves the | |
e05cdb17 | 1900 | # folder1 path as-is on disk. The sparse-index behaves the same. |
70569fad | 1901 | test_must_be_empty full-checkout-out && |
e05cdb17 | 1902 | test_must_be_empty sparse-index-out && |
70569fad DS |
1903 | |
1904 | # In the sparse-checkout case, the checkout deletes the folder1 | |
1905 | # file and adds the folder1/larger-content file, leaving all other | |
1906 | # paths that were in folder1/ as deleted (without any warning). | |
1907 | cat >expect <<-EOF && | |
1908 | D folder2 | |
1909 | A folder2/larger-content | |
1910 | EOF | |
1911 | test_cmp expect sparse-checkout-out && | |
1912 | ||
1913 | # Switched to branch df-conflict-1 | |
e05cdb17 DS |
1914 | test_cmp full-checkout-err sparse-checkout-err && |
1915 | test_cmp full-checkout-err sparse-index-err | |
70569fad DS |
1916 | ' |
1917 | ||
b91a2b65 | 1918 | test_expect_success 'mv directory from out-of-cone to in-cone' ' |
1143cc01 SY |
1919 | init_repos && |
1920 | ||
1921 | # <source> as a sparse directory (or SKIP_WORKTREE_DIR without enabling | |
1922 | # sparse index). | |
1923 | test_all_match git mv --sparse folder1 deep && | |
1924 | test_all_match git status --porcelain=v2 && | |
1925 | test_sparse_match git ls-files -t && | |
1926 | git -C sparse-checkout ls-files -t >actual && | |
1927 | grep -e "H deep/folder1/0/0/0" actual && | |
1928 | grep -e "H deep/folder1/0/1" actual && | |
1929 | grep -e "H deep/folder1/a" actual && | |
1930 | ||
1931 | test_all_match git reset --hard && | |
1932 | ||
1933 | # <source> as a directory deeper than sparse index boundary (where | |
1934 | # sparse index will expand). | |
1935 | test_sparse_match git mv --sparse folder1/0 deep && | |
1936 | test_sparse_match git status --porcelain=v2 && | |
1937 | test_sparse_match git ls-files -t && | |
1938 | git -C sparse-checkout ls-files -t >actual && | |
1939 | grep -e "H deep/0/0/0" actual && | |
1940 | grep -e "H deep/0/1" actual | |
1941 | ' | |
1942 | ||
ba808251 SY |
1943 | test_expect_success 'rm pathspec inside sparse definition' ' |
1944 | init_repos && | |
1945 | ||
1946 | test_all_match git rm deep/a && | |
1947 | test_all_match git status --porcelain=v2 && | |
1948 | ||
1949 | # test wildcard | |
1950 | run_on_all git reset --hard && | |
1951 | test_all_match git rm deep/* && | |
1952 | test_all_match git status --porcelain=v2 && | |
1953 | ||
1954 | # test recursive rm | |
1955 | run_on_all git reset --hard && | |
1956 | test_all_match git rm -r deep && | |
1957 | test_all_match git status --porcelain=v2 | |
1958 | ' | |
1959 | ||
ede241c7 | 1960 | test_expect_success 'rm pathspec outside sparse definition' ' |
ba808251 SY |
1961 | init_repos && |
1962 | ||
1963 | for file in folder1/a folder1/0/1 | |
1964 | do | |
1965 | test_sparse_match test_must_fail git rm $file && | |
1966 | test_sparse_match test_must_fail git rm --cached $file && | |
1967 | test_sparse_match git rm --sparse $file && | |
0e66bc1b | 1968 | test_sparse_match git status --porcelain=v2 || return 1 |
ba808251 SY |
1969 | done && |
1970 | ||
1971 | cat >folder1-full <<-EOF && | |
1972 | rm ${SQ}folder1/0/0/0${SQ} | |
1973 | rm ${SQ}folder1/0/1${SQ} | |
1974 | rm ${SQ}folder1/a${SQ} | |
1975 | EOF | |
1976 | ||
1977 | cat >folder1-sparse <<-EOF && | |
1978 | rm ${SQ}folder1/${SQ} | |
1979 | EOF | |
1980 | ||
1981 | # test wildcard | |
1982 | run_on_sparse git reset --hard && | |
1983 | run_on_sparse git sparse-checkout reapply && | |
1984 | test_sparse_match test_must_fail git rm folder1/* && | |
1985 | run_on_sparse git rm --sparse folder1/* && | |
1986 | test_cmp folder1-full sparse-checkout-out && | |
1987 | test_cmp folder1-sparse sparse-index-out && | |
1988 | test_sparse_match git status --porcelain=v2 && | |
1989 | ||
1990 | # test recursive rm | |
1991 | run_on_sparse git reset --hard && | |
1992 | run_on_sparse git sparse-checkout reapply && | |
1993 | test_sparse_match test_must_fail git rm --sparse folder1 && | |
1994 | run_on_sparse git rm --sparse -r folder1 && | |
1995 | test_cmp folder1-full sparse-checkout-out && | |
1996 | test_cmp folder1-sparse sparse-index-out && | |
1997 | test_sparse_match git status --porcelain=v2 | |
1998 | ' | |
1999 | ||
ede241c7 | 2000 | test_expect_success 'rm pathspec expands index when necessary' ' |
bcf96cfc SY |
2001 | init_repos && |
2002 | ||
2003 | # in-cone pathspec (do not expand) | |
2004 | ensure_not_expanded rm "deep/deep*" && | |
2005 | test_must_be_empty sparse-index-err && | |
2006 | ||
2007 | # out-of-cone pathspec (expand) | |
2008 | ! ensure_not_expanded rm --sparse "folder1/a*" && | |
2009 | test_must_be_empty sparse-index-err && | |
2010 | ||
2011 | # pathspec that should expand index | |
2012 | ! ensure_not_expanded rm "*/a" && | |
2013 | test_must_be_empty sparse-index-err && | |
2014 | ||
2015 | ! ensure_not_expanded rm "**a" && | |
2016 | test_must_be_empty sparse-index-err | |
2017 | ' | |
2018 | ||
ede241c7 SY |
2019 | test_expect_success 'sparse index is not expanded: rm' ' |
2020 | init_repos && | |
2021 | ||
2022 | ensure_not_expanded rm deep/a && | |
2023 | ||
2024 | # test in-cone wildcard | |
2025 | git -C sparse-index reset --hard && | |
2026 | ensure_not_expanded rm deep/* && | |
2027 | ||
2028 | # test recursive rm | |
2029 | git -C sparse-index reset --hard && | |
2030 | ensure_not_expanded rm -r deep | |
2031 | ' | |
2032 | ||
7cae7627 SY |
2033 | test_expect_success 'grep with and --cached' ' |
2034 | init_repos && | |
2035 | ||
2036 | test_all_match git grep --cached a && | |
2037 | test_all_match git grep --cached a -- "folder1/*" | |
2038 | ' | |
2039 | ||
2040 | test_expect_success 'grep is not expanded' ' | |
2041 | init_repos && | |
2042 | ||
2043 | ensure_not_expanded grep a && | |
2044 | ensure_not_expanded grep a -- deep/* && | |
2045 | ||
2046 | # All files within the folder1/* pathspec are sparse, | |
2047 | # so this command does not find any matches | |
2048 | ensure_not_expanded ! grep a -- folder1/* && | |
2049 | ||
2050 | # test out-of-cone pathspec with or without wildcard | |
2051 | ensure_not_expanded grep --cached a -- "folder1/a" && | |
2052 | ensure_not_expanded grep --cached a -- "folder1/*" && | |
2053 | ||
2054 | # test in-cone pathspec with or without wildcard | |
2055 | ensure_not_expanded grep --cached a -- "deep/a" && | |
2056 | ensure_not_expanded grep --cached a -- "deep/*" | |
2057 | ' | |
2058 | ||
2059 | # NEEDSWORK: when running `grep` in the superproject with --recurse-submodules, | |
2060 | # Git expands the index of the submodules unexpectedly. Even though `grep` | |
2061 | # builtin is marked as "command_requires_full_index = 0", this config is only | |
2062 | # useful for the superproject. Namely, the submodules have their own configs, | |
2063 | # which are _not_ populated by the one-time sparse-index feature switch. | |
2064 | test_expect_failure 'grep within submodules is not expanded' ' | |
2065 | init_repos_as_submodules && | |
2066 | ||
2067 | # do not use ensure_not_expanded() here, becasue `grep` should be | |
2068 | # run in the superproject, not in "./sparse-index" | |
2069 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ | |
2070 | git grep --cached --recurse-submodules a -- "*/folder1/*" && | |
2071 | test_region ! index ensure_full_index trace2.txt | |
2072 | ' | |
2073 | ||
2074 | # NEEDSWORK: this test is not actually testing the code. The design purpose | |
2075 | # of this test is to verify the grep result when the submodules are using a | |
2076 | # sparse-index. Namely, we want "folder1/" as a tree (a sparse directory); but | |
2077 | # because of the index expansion, we are now grepping the "folder1/a" blob. | |
2078 | # Because of the problem stated above 'grep within submodules is not expanded', | |
2079 | # we don't have the ideal test environment yet. | |
2080 | test_expect_success 'grep sparse directory within submodules' ' | |
2081 | init_repos_as_submodules && | |
2082 | ||
2083 | cat >expect <<-\EOF && | |
2084 | full-checkout/folder1/a:a | |
2085 | sparse-checkout/folder1/a:a | |
2086 | sparse-index/folder1/a:a | |
2087 | EOF | |
2088 | git grep --cached --recurse-submodules a -- "*/folder1/*" >actual && | |
2089 | test_cmp actual expect | |
2090 | ' | |
2091 | ||
6e210175 | 2092 | test_expect_success 'write-tree' ' |
1a65b41b SL |
2093 | init_repos && |
2094 | ||
6e210175 SL |
2095 | test_all_match git write-tree && |
2096 | ||
1a65b41b SL |
2097 | write_script edit-contents <<-\EOF && |
2098 | echo text >>"$1" | |
2099 | EOF | |
2100 | ||
6e210175 | 2101 | # make a change inside the sparse cone |
1a65b41b | 2102 | run_on_all ../edit-contents deep/a && |
6e210175 | 2103 | test_all_match git update-index deep/a && |
1a65b41b | 2104 | test_all_match git write-tree && |
6e210175 | 2105 | test_all_match git status --porcelain=v2 && |
1a65b41b | 2106 | |
6e210175 | 2107 | # make a change outside the sparse cone |
1a65b41b SL |
2108 | run_on_all mkdir -p folder1 && |
2109 | run_on_all cp a folder1/a && | |
2110 | run_on_all ../edit-contents folder1/a && | |
6e210175 SL |
2111 | test_all_match git update-index folder1/a && |
2112 | test_all_match git write-tree && | |
2113 | test_all_match git status --porcelain=v2 && | |
2114 | ||
2115 | # check that SKIP_WORKTREE files are not materialized | |
2116 | test_path_is_missing sparse-checkout/folder2/a && | |
2117 | test_path_is_missing sparse-index/folder2/a | |
1a65b41b SL |
2118 | ' |
2119 | ||
2120 | test_expect_success 'sparse-index is not expanded: write-tree' ' | |
2121 | init_repos && | |
2122 | ||
2123 | ensure_not_expanded write-tree && | |
2124 | ||
2125 | echo "test1" >>sparse-index/a && | |
2126 | git -C sparse-index update-index a && | |
2127 | ensure_not_expanded write-tree | |
2128 | ' | |
2129 | ||
0aba1a98 SL |
2130 | test_expect_success 'diff-files with pathspec inside sparse definition' ' |
2131 | init_repos && | |
2132 | ||
2133 | write_script edit-contents <<-\EOF && | |
2134 | echo text >>"$1" | |
2135 | EOF | |
2136 | ||
2137 | run_on_all ../edit-contents deep/a && | |
2138 | ||
2139 | test_all_match git diff-files && | |
2140 | ||
2141 | test_all_match git diff-files -- deep/a && | |
2142 | ||
2143 | # test wildcard | |
2144 | test_all_match git diff-files -- "deep/*" | |
2145 | ' | |
2146 | ||
2147 | test_expect_success 'diff-files with pathspec outside sparse definition' ' | |
2148 | init_repos && | |
2149 | ||
2150 | test_sparse_match git diff-files -- folder2/a && | |
2151 | ||
2152 | write_script edit-contents <<-\EOF && | |
2153 | echo text >>"$1" | |
2154 | EOF | |
2155 | ||
2156 | # The directory "folder1" is outside the cone of interest | |
2157 | # and will not exist in the sparse checkout repositories. | |
2158 | # Create it as needed, add file "folder1/a" there with | |
2159 | # contents that is different from the staged version. | |
2160 | run_on_all mkdir -p folder1 && | |
2161 | run_on_all cp a folder1/a && | |
2162 | ||
2163 | run_on_all ../edit-contents folder1/a && | |
2164 | test_all_match git diff-files && | |
2165 | test_all_match git diff-files -- folder1/a && | |
2166 | test_all_match git diff-files -- "folder*/a" | |
2167 | ' | |
2168 | ||
8c30be91 SL |
2169 | test_expect_success 'sparse index is not expanded: diff-files' ' |
2170 | init_repos && | |
2171 | ||
2172 | write_script edit-contents <<-\EOF && | |
2173 | echo text >>"$1" | |
2174 | EOF | |
2175 | ||
2176 | run_on_all ../edit-contents deep/a && | |
2177 | ||
2178 | ensure_not_expanded diff-files && | |
2179 | ensure_not_expanded diff-files -- deep/a && | |
2180 | ensure_not_expanded diff-files -- "deep/*" | |
2181 | ' | |
2182 | ||
48c5fbfb SL |
2183 | test_expect_success 'diff-tree' ' |
2184 | init_repos && | |
2185 | ||
2186 | # Test change inside sparse cone | |
2187 | tree1=$(git -C sparse-index rev-parse HEAD^{tree}) && | |
2188 | tree2=$(git -C sparse-index rev-parse update-deep^{tree}) && | |
2189 | test_all_match git diff-tree $tree1 $tree2 && | |
2190 | test_all_match git diff-tree $tree1 $tree2 -- deep/a && | |
2191 | test_all_match git diff-tree HEAD update-deep && | |
2192 | test_all_match git diff-tree HEAD update-deep -- deep/a && | |
2193 | ||
2194 | # Test change outside sparse cone | |
2195 | tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) && | |
2196 | test_all_match git diff-tree $tree1 $tree3 && | |
2197 | test_all_match git diff-tree $tree1 $tree3 -- folder1/a && | |
2198 | test_all_match git diff-tree HEAD update-folder1 && | |
2199 | test_all_match git diff-tree HEAD update-folder1 -- folder1/a && | |
2200 | ||
2201 | # Check that SKIP_WORKTREE files are not materialized | |
2202 | test_path_is_missing sparse-checkout/folder1/a && | |
2203 | test_path_is_missing sparse-index/folder1/a && | |
2204 | test_path_is_missing sparse-checkout/folder2/a && | |
2205 | test_path_is_missing sparse-index/folder2/a | |
2206 | ' | |
2207 | ||
2208 | test_expect_success 'sparse-index is not expanded: diff-tree' ' | |
2209 | init_repos && | |
2210 | ||
2211 | tree1=$(git -C sparse-index rev-parse HEAD^{tree}) && | |
2212 | tree2=$(git -C sparse-index rev-parse update-deep^{tree}) && | |
2213 | tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) && | |
2214 | ||
2215 | ensure_not_expanded diff-tree $tree1 $tree2 && | |
2216 | ensure_not_expanded diff-tree $tree1 $tree2 -- deep/a && | |
2217 | ensure_not_expanded diff-tree HEAD update-deep && | |
2218 | ensure_not_expanded diff-tree HEAD update-deep -- deep/a && | |
2219 | ensure_not_expanded diff-tree $tree1 $tree3 && | |
2220 | ensure_not_expanded diff-tree $tree1 $tree3 -- folder1/a && | |
2221 | ensure_not_expanded diff-tree HEAD update-folder1 && | |
2222 | ensure_not_expanded diff-tree HEAD update-folder1 -- folder1/a | |
2223 | ' | |
2224 | ||
8fac776f SL |
2225 | test_expect_success 'worktree' ' |
2226 | init_repos && | |
2227 | ||
2228 | write_script edit-contents <<-\EOF && | |
2229 | echo text >>"$1" | |
2230 | EOF | |
2231 | ||
2232 | for repo in full-checkout sparse-checkout sparse-index | |
2233 | do | |
2234 | worktree=${repo}-wt && | |
2235 | git -C $repo worktree add ../$worktree && | |
2236 | ||
2237 | # Compare worktree content with "ls" | |
2238 | (cd $repo && ls) >worktree_contents && | |
2239 | (cd $worktree && ls) >new_worktree_contents && | |
2240 | test_cmp worktree_contents new_worktree_contents && | |
2241 | ||
2242 | # Compare index content with "ls-files --sparse" | |
2243 | git -C $repo ls-files --sparse >index_contents && | |
2244 | git -C $worktree ls-files --sparse >new_index_contents && | |
2245 | test_cmp index_contents new_index_contents && | |
2246 | ||
2247 | git -C $repo worktree remove ../$worktree || return 1 | |
2248 | done && | |
2249 | ||
2250 | test_all_match git worktree add .worktrees/hotfix && | |
2251 | run_on_all ../edit-contents .worktrees/hotfix/deep/a && | |
2252 | test_all_match test_must_fail git worktree remove .worktrees/hotfix | |
2253 | ' | |
2254 | ||
2255 | test_expect_success 'worktree is not expanded' ' | |
2256 | init_repos && | |
2257 | ||
2258 | ensure_not_expanded worktree add .worktrees/hotfix && | |
2259 | ensure_not_expanded worktree remove .worktrees/hotfix | |
2260 | ' | |
2261 | ||
fd4faf7a SL |
2262 | test_expect_success 'check-attr with pathspec inside sparse definition' ' |
2263 | init_repos && | |
2264 | ||
2265 | echo "a -crlf myAttr" >>.gitattributes && | |
2266 | run_on_all cp ../.gitattributes ./deep && | |
2267 | ||
2268 | test_all_match git check-attr -a -- deep/a && | |
2269 | ||
2270 | test_all_match git add deep/.gitattributes && | |
2271 | test_all_match git check-attr -a --cached -- deep/a | |
2272 | ' | |
2273 | ||
4723ae10 | 2274 | test_expect_success 'check-attr with pathspec outside sparse definition' ' |
fd4faf7a SL |
2275 | init_repos && |
2276 | ||
2277 | echo "a -crlf myAttr" >>.gitattributes && | |
2278 | run_on_sparse mkdir folder1 && | |
2279 | run_on_all cp ../.gitattributes ./folder1 && | |
2280 | run_on_all cp a folder1/a && | |
2281 | ||
2282 | test_all_match git check-attr -a -- folder1/a && | |
2283 | ||
2284 | git -C full-checkout add folder1/.gitattributes && | |
2285 | test_sparse_match git add --sparse folder1/.gitattributes && | |
2286 | test_all_match git commit -m "add .gitattributes" && | |
2287 | test_sparse_match git sparse-checkout reapply && | |
2288 | test_all_match git check-attr -a --cached -- folder1/a | |
2289 | ' | |
2290 | ||
4723ae10 SL |
2291 | # NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due |
2292 | # to an underlying issue in oneway_diff() within diff-lib.c. | |
2293 | # 'do_oneway_diff()' is not called as expected for paths that could match | |
2294 | # inside of a sparse directory. Specifically, the 'ce_path_match()' function | |
2295 | # fails to recognize files inside a sparse directory (e.g., when 'folder1/' | |
2296 | # is a sparse directory, 'folder1/a' cannot be recognized). The goal is to | |
2297 | # proceed with 'do_oneway_diff()' if the pathspec could match inside of a | |
2298 | # sparse directory. | |
fd4faf7a SL |
2299 | test_expect_failure 'diff --check with pathspec outside sparse definition' ' |
2300 | init_repos && | |
2301 | ||
2302 | write_script edit-contents <<-\EOF && | |
2303 | echo "a " >"$1" | |
2304 | EOF | |
2305 | ||
2306 | test_all_match git config core.whitespace -trailing-space,-space-before-tab && | |
2307 | ||
2308 | echo "a whitespace=trailing-space,space-before-tab" >>.gitattributes && | |
2309 | run_on_all mkdir -p folder1 && | |
2310 | run_on_all cp ../.gitattributes ./folder1 && | |
2311 | test_all_match git add --sparse folder1/.gitattributes && | |
2312 | run_on_all ../edit-contents folder1/a && | |
2313 | test_all_match git add --sparse folder1/a && | |
2314 | ||
2315 | test_sparse_match git sparse-checkout reapply && | |
2316 | test_all_match test_must_fail git diff --check --cached -- folder1/a | |
2317 | ' | |
2318 | ||
f9815878 SL |
2319 | test_expect_success 'sparse-index is not expanded: check-attr' ' |
2320 | init_repos && | |
2321 | ||
2322 | echo "a -crlf myAttr" >>.gitattributes && | |
2323 | mkdir ./sparse-index/folder1 && | |
2324 | cp ./sparse-index/a ./sparse-index/folder1/a && | |
2325 | cp .gitattributes ./sparse-index/deep && | |
2326 | cp .gitattributes ./sparse-index/folder1 && | |
2327 | ||
2328 | git -C sparse-index add deep/.gitattributes && | |
2329 | git -C sparse-index add --sparse folder1/.gitattributes && | |
2330 | ensure_not_expanded check-attr -a --cached -- deep/a && | |
2331 | ensure_not_expanded check-attr -a --cached -- folder1/a | |
2332 | ' | |
2333 | ||
19a0acc8 | 2334 | test_done |