1#!/bin/sh 2 3test_description='compare full workdir to sparse workdir' 4 5GIT_TEST_SPLIT_INDEX=0 6GIT_TEST_SPARSE_INDEX= 7 8. ./test-lib.sh 9 10test_expect_success 'setup' ' 11 git init initial-repo && 12 ( 13 GIT_TEST_SPARSE_INDEX=0 && 14 cd initial-repo && 15 echo a >a && 16 echo "after deep" >e && 17 echo "after folder1" >g && 18 echo "after x" >z && 19 mkdir folder1 folder2 deep x && 20 mkdir deep/deeper1 deep/deeper2 deep/before deep/later && 21 mkdir deep/deeper1/deepest && 22 echo "after deeper1" >deep/e && 23 echo "after deepest" >deep/deeper1/e && 24 cp a folder1 && 25 cp a folder2 && 26 cp a x && 27 cp a deep && 28 cp a deep/before && 29 cp a deep/deeper1 && 30 cp a deep/deeper2 && 31 cp a deep/later && 32 cp a deep/deeper1/deepest && 33 cp -r deep/deeper1/deepest deep/deeper2 && 34 mkdir deep/deeper1/0 && 35 mkdir deep/deeper1/0/0 && 36 touch deep/deeper1/0/1 && 37 touch deep/deeper1/0/0/0 && 38 >folder1- && 39 >folder1.x && 40 >folder10 && 41 cp -r deep/deeper1/0 folder1 && 42 cp -r deep/deeper1/0 folder2 && 43 echo >>folder1/0/0/0 && 44 echo >>folder2/0/1 && 45 git add . && 46 git commit -m "initial commit" && 47 git checkout -b base && 48 for dir in folder1 folder2 deep 49 do 50 git checkout -b update-$dir base && 51 echo "updated $dir" >$dir/a && 52 git commit -a -m "update $dir" || return 1 53 done && 54 55 git checkout -b rename-base base && 56 cat >folder1/larger-content <<-\EOF && 57 matching 58 lines 59 help 60 inexact 61 renames 62 EOF 63 cp folder1/larger-content folder2/ && 64 cp folder1/larger-content deep/deeper1/ && 65 git add . && 66 git commit -m "add interesting rename content" && 67 68 git checkout -b rename-out-to-out rename-base && 69 mv folder1/a folder2/b && 70 mv folder1/larger-content folder2/edited-content && 71 echo >>folder2/edited-content && 72 echo >>folder2/0/1 && 73 echo stuff >>deep/deeper1/a && 74 git add . && 75 git commit -m "rename folder1/... to folder2/..." && 76 77 git checkout -b rename-out-to-in rename-base && 78 mv folder1/a deep/deeper1/b && 79 echo more stuff >>deep/deeper1/a && 80 rm folder2/0/1 && 81 mkdir folder2/0/1 && 82 echo >>folder2/0/1/1 && 83 mv folder1/larger-content deep/deeper1/edited-content && 84 echo >>deep/deeper1/edited-content && 85 git add . && 86 git commit -m "rename folder1/... to deep/deeper1/..." && 87 88 git checkout -b rename-in-to-out rename-base && 89 mv deep/deeper1/a folder1/b && 90 echo >>folder2/0/1 && 91 rm -rf folder1/0/0 && 92 echo >>folder1/0/0 && 93 mv deep/deeper1/larger-content folder1/edited-content && 94 echo >>folder1/edited-content && 95 git add . && 96 git commit -m "rename deep/deeper1/... to folder1/..." && 97 98 git checkout -b df-conflict-1 base && 99 rm -rf folder1 && 100 echo content >folder1 && 101 git add . && 102 git commit -m "dir to file" && 103 104 git checkout -b df-conflict-2 base && 105 rm -rf folder2 && 106 echo content >folder2 && 107 git add . && 108 git commit -m "dir to file" && 109 110 git checkout -b fd-conflict base && 111 rm a && 112 mkdir a && 113 echo content >a/a && 114 git add . && 115 git commit -m "file to dir" && 116 117 for side in left right 118 do 119 git checkout -b merge-$side base && 120 echo $side >>deep/deeper2/a && 121 echo $side >>folder1/a && 122 echo $side >>folder2/a && 123 git add . && 124 git commit -m "$side" || return 1 125 done && 126 127 git checkout -b deepest base && 128 echo "updated deepest" >deep/deeper1/deepest/a && 129 git commit -a -m "update deepest" && 130 131 git checkout -f base && 132 git reset --hard 133 ) 134' 135 136init_repos () { 137 rm -rf full-checkout sparse-checkout sparse-index && 138 139 # create repos in initial state 140 cp -r initial-repo full-checkout && 141 git -C full-checkout reset --hard && 142 143 cp -r initial-repo sparse-checkout && 144 git -C sparse-checkout reset --hard && 145 146 cp -r initial-repo sparse-index && 147 git -C sparse-index reset --hard && 148 149 # initialize sparse-checkout definitions 150 git -C sparse-checkout sparse-checkout init --cone && 151 git -C sparse-checkout sparse-checkout set deep && 152 git -C sparse-index sparse-checkout init --cone --sparse-index && 153 test_cmp_config -C sparse-index true index.sparse && 154 git -C sparse-index sparse-checkout set deep 155} 156 157run_on_sparse () { 158 ( 159 cd sparse-checkout && 160 GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err 161 ) && 162 ( 163 cd sparse-index && 164 GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err 165 ) 166} 167 168run_on_all () { 169 ( 170 cd full-checkout && 171 GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err 172 ) && 173 run_on_sparse "$@" 174} 175 176test_all_match () { 177 run_on_all "$@" && 178 test_cmp full-checkout-out sparse-checkout-out && 179 test_cmp full-checkout-out sparse-index-out && 180 test_cmp full-checkout-err sparse-checkout-err && 181 test_cmp full-checkout-err sparse-index-err 182} 183 184test_sparse_match () { 185 run_on_sparse "$@" && 186 test_cmp sparse-checkout-out sparse-index-out && 187 test_cmp sparse-checkout-err sparse-index-err 188} 189 190test_sparse_unstaged () { 191 file=$1 && 192 for repo in sparse-checkout sparse-index 193 do 194 # Skip "unmerged" paths 195 git -C $repo diff --staged --diff-filter=u -- "$file" >diff && 196 test_must_be_empty diff || return 1 197 done 198} 199 200test_expect_success 'sparse-index contents' ' 201 init_repos && 202 203 test-tool -C sparse-index read-cache --table >cache && 204 for dir in folder1 folder2 x 205 do 206 TREE=$(git -C sparse-index rev-parse HEAD:$dir) && 207 grep "040000 tree $TREE $dir/" cache \ 208 || return 1 209 done && 210 211 git -C sparse-index sparse-checkout set folder1 && 212 213 test-tool -C sparse-index read-cache --table >cache && 214 for dir in deep folder2 x 215 do 216 TREE=$(git -C sparse-index rev-parse HEAD:$dir) && 217 grep "040000 tree $TREE $dir/" cache \ 218 || return 1 219 done && 220 221 git -C sparse-index sparse-checkout set deep/deeper1 && 222 223 test-tool -C sparse-index read-cache --table >cache && 224 for dir in deep/deeper2 folder1 folder2 x 225 do 226 TREE=$(git -C sparse-index rev-parse HEAD:$dir) && 227 grep "040000 tree $TREE $dir/" cache \ 228 || return 1 229 done && 230 231 # Disabling the sparse-index removes tree entries with full ones 232 git -C sparse-index sparse-checkout init --no-sparse-index && 233 234 test-tool -C sparse-index read-cache --table >cache && 235 ! grep "040000 tree" cache && 236 test_sparse_match test-tool read-cache --table 237' 238 239test_expect_success 'expanded in-memory index matches full index' ' 240 init_repos && 241 test_sparse_match test-tool read-cache --expand --table 242' 243 244test_expect_success 'status with options' ' 245 init_repos && 246 test_sparse_match ls && 247 test_all_match git status --porcelain=v2 && 248 test_all_match git status --porcelain=v2 -z -u && 249 test_all_match git status --porcelain=v2 -uno && 250 run_on_all touch README.md && 251 test_all_match git status --porcelain=v2 && 252 test_all_match git status --porcelain=v2 -z -u && 253 test_all_match git status --porcelain=v2 -uno && 254 test_all_match git add README.md && 255 test_all_match git status --porcelain=v2 && 256 test_all_match git status --porcelain=v2 -z -u && 257 test_all_match git status --porcelain=v2 -uno 258' 259 260test_expect_success 'status reports sparse-checkout' ' 261 init_repos && 262 git -C sparse-checkout status >full && 263 git -C sparse-index status >sparse && 264 test_i18ngrep "You are in a sparse checkout with " full && 265 test_i18ngrep "You are in a sparse checkout." sparse 266' 267 268test_expect_success 'add, commit, checkout' ' 269 init_repos && 270 271 write_script edit-contents <<-\EOF && 272 echo text >>$1 273 EOF 274 run_on_all ../edit-contents README.md && 275 276 test_all_match git add README.md && 277 test_all_match git status --porcelain=v2 && 278 test_all_match git commit -m "Add README.md" && 279 280 test_all_match git checkout HEAD~1 && 281 test_all_match git checkout - && 282 283 run_on_all ../edit-contents README.md && 284 285 test_all_match git add -A && 286 test_all_match git status --porcelain=v2 && 287 test_all_match git commit -m "Extend README.md" && 288 289 test_all_match git checkout HEAD~1 && 290 test_all_match git checkout - && 291 292 run_on_all ../edit-contents deep/newfile && 293 294 test_all_match git status --porcelain=v2 -uno && 295 test_all_match git status --porcelain=v2 && 296 test_all_match git add . && 297 test_all_match git status --porcelain=v2 && 298 test_all_match git commit -m "add deep/newfile" && 299 300 test_all_match git checkout HEAD~1 && 301 test_all_match git checkout - 302' 303 304test_expect_success 'add outside sparse cone' ' 305 init_repos && 306 307 run_on_sparse mkdir folder1 && 308 run_on_sparse ../edit-contents folder1/a && 309 run_on_sparse ../edit-contents folder1/newfile && 310 test_sparse_match test_must_fail git add folder1/a && 311 grep "Disable or modify the sparsity rules" sparse-checkout-err && 312 test_sparse_unstaged folder1/a && 313 test_sparse_match test_must_fail git add folder1/newfile && 314 grep "Disable or modify the sparsity rules" sparse-checkout-err && 315 test_sparse_unstaged folder1/newfile 316' 317 318test_expect_success 'commit including unstaged changes' ' 319 init_repos && 320 321 write_script edit-file <<-\EOF && 322 echo $1 >$2 323 EOF 324 325 run_on_all ../edit-file 1 a && 326 run_on_all ../edit-file 1 deep/a && 327 328 test_all_match git commit -m "-a" -a && 329 test_all_match git status --porcelain=v2 && 330 331 run_on_all ../edit-file 2 a && 332 run_on_all ../edit-file 2 deep/a && 333 334 test_all_match git commit -m "--include" --include deep/a && 335 test_all_match git status --porcelain=v2 && 336 test_all_match git commit -m "--include" --include a && 337 test_all_match git status --porcelain=v2 && 338 339 run_on_all ../edit-file 3 a && 340 run_on_all ../edit-file 3 deep/a && 341 342 test_all_match git commit -m "--amend" -a --amend && 343 test_all_match git status --porcelain=v2 344' 345 346test_expect_success 'status/add: outside sparse cone' ' 347 init_repos && 348 349 # folder1 is at HEAD, but outside the sparse cone 350 run_on_sparse mkdir folder1 && 351 cp initial-repo/folder1/a sparse-checkout/folder1/a && 352 cp initial-repo/folder1/a sparse-index/folder1/a && 353 354 test_sparse_match git status && 355 356 write_script edit-contents <<-\EOF && 357 echo text >>$1 358 EOF 359 run_on_sparse ../edit-contents folder1/a && 360 run_on_all ../edit-contents folder1/new && 361 362 test_sparse_match git status --porcelain=v2 && 363 364 # Adding the path outside of the sparse-checkout cone should fail. 365 test_sparse_match test_must_fail git add folder1/a && 366 grep "Disable or modify the sparsity rules" sparse-checkout-err && 367 test_sparse_unstaged folder1/a && 368 test_sparse_match test_must_fail git add --refresh folder1/a && 369 grep "Disable or modify the sparsity rules" sparse-checkout-err && 370 test_sparse_unstaged folder1/a && 371 test_sparse_match test_must_fail git add folder1/new && 372 grep "Disable or modify the sparsity rules" sparse-checkout-err && 373 test_sparse_unstaged folder1/new && 374 test_sparse_match git add --sparse folder1/a && 375 test_sparse_match git add --sparse folder1/new && 376 377 test_all_match git add --sparse . && 378 test_all_match git status --porcelain=v2 && 379 test_all_match git commit -m folder1/new && 380 test_all_match git rev-parse HEAD^{tree} && 381 382 run_on_all ../edit-contents folder1/newer && 383 test_all_match git add --sparse folder1/ && 384 test_all_match git status --porcelain=v2 && 385 test_all_match git commit -m folder1/newer && 386 test_all_match git rev-parse HEAD^{tree} 387' 388 389test_expect_success 'checkout and reset --hard' ' 390 init_repos && 391 392 test_all_match git checkout update-folder1 && 393 test_all_match git status --porcelain=v2 && 394 395 test_all_match git checkout update-deep && 396 test_all_match git status --porcelain=v2 && 397 398 test_all_match git checkout -b reset-test && 399 test_all_match git reset --hard deepest && 400 test_all_match git reset --hard update-folder1 && 401 test_all_match git reset --hard update-folder2 402' 403 404test_expect_success 'diff --staged' ' 405 init_repos && 406 407 write_script edit-contents <<-\EOF && 408 echo text >>README.md 409 EOF 410 run_on_all ../edit-contents && 411 412 test_all_match git diff && 413 test_all_match git diff --staged && 414 test_all_match git add README.md && 415 test_all_match git diff && 416 test_all_match git diff --staged 417' 418 419# NEEDSWORK: sparse-checkout behaves differently from full-checkout when 420# running this test with 'df-conflict-2' after 'df-conflict-1'. 421test_expect_success 'diff with renames and conflicts' ' 422 init_repos && 423 424 for branch in rename-out-to-out \ 425 rename-out-to-in \ 426 rename-in-to-out \ 427 df-conflict-1 \ 428 fd-conflict 429 do 430 test_all_match git checkout rename-base && 431 test_all_match git checkout $branch -- . && 432 test_all_match git status --porcelain=v2 && 433 test_all_match git diff --staged --no-renames && 434 test_all_match git diff --staged --find-renames || return 1 435 done 436' 437 438test_expect_success 'diff with directory/file conflicts' ' 439 init_repos && 440 441 for branch in rename-out-to-out \ 442 rename-out-to-in \ 443 rename-in-to-out \ 444 df-conflict-1 \ 445 df-conflict-2 \ 446 fd-conflict 447 do 448 git -C full-checkout reset --hard && 449 test_sparse_match git reset --hard && 450 test_all_match git checkout $branch && 451 test_all_match git checkout rename-base -- . && 452 test_all_match git status --porcelain=v2 && 453 test_all_match git diff --staged --no-renames && 454 test_all_match git diff --staged --find-renames || return 1 455 done 456' 457 458test_expect_success 'log with pathspec outside sparse definition' ' 459 init_repos && 460 461 test_all_match git log -- a && 462 test_all_match git log -- folder1/a && 463 test_all_match git log -- folder2/a && 464 test_all_match git log -- deep/a && 465 test_all_match git log -- deep/deeper1/a && 466 test_all_match git log -- deep/deeper1/deepest/a && 467 468 test_all_match git checkout update-folder1 && 469 test_all_match git log -- folder1/a 470' 471 472test_expect_success 'blame with pathspec inside sparse definition' ' 473 init_repos && 474 475 test_all_match git blame a && 476 test_all_match git blame deep/a && 477 test_all_match git blame deep/deeper1/a && 478 test_all_match git blame deep/deeper1/deepest/a 479' 480 481# TODO: blame currently does not support blaming files outside of the 482# sparse definition. It complains that the file doesn't exist locally. 483test_expect_failure 'blame with pathspec outside sparse definition' ' 484 init_repos && 485 486 test_all_match git blame folder1/a && 487 test_all_match git blame folder2/a && 488 test_all_match git blame deep/deeper2/a && 489 test_all_match git blame deep/deeper2/deepest/a 490' 491 492# NEEDSWORK: a sparse-checkout behaves differently from a full checkout 493# in this scenario, but it shouldn't. 494test_expect_failure 'checkout and reset (mixed)' ' 495 init_repos && 496 497 test_all_match git checkout -b reset-test update-deep && 498 test_all_match git reset deepest && 499 test_all_match git reset update-folder1 && 500 test_all_match git reset update-folder2 501' 502 503# NEEDSWORK: a sparse-checkout behaves differently from a full checkout 504# in this scenario, but it shouldn't. 505test_expect_success 'checkout and reset (mixed) [sparse]' ' 506 init_repos && 507 508 test_sparse_match git checkout -b reset-test update-deep && 509 test_sparse_match git reset deepest && 510 test_sparse_match git reset update-folder1 && 511 test_sparse_match git reset update-folder2 512' 513 514test_expect_success 'merge, cherry-pick, and rebase' ' 515 init_repos && 516 517 for OPERATION in "merge -m merge" cherry-pick "rebase --apply" "rebase --merge" 518 do 519 test_all_match git checkout -B temp update-deep && 520 test_all_match git $OPERATION update-folder1 && 521 test_all_match git rev-parse HEAD^{tree} && 522 test_all_match git $OPERATION update-folder2 && 523 test_all_match git rev-parse HEAD^{tree} || return 1 524 done 525' 526 527test_expect_success 'merge with conflict outside cone' ' 528 init_repos && 529 530 test_all_match git checkout -b merge-tip merge-left && 531 test_all_match git status --porcelain=v2 && 532 test_all_match test_must_fail git merge -m merge merge-right && 533 test_all_match git status --porcelain=v2 && 534 535 # Resolve the conflict in different ways: 536 # 1. Revert to the base 537 test_all_match git checkout base -- deep/deeper2/a && 538 test_all_match git status --porcelain=v2 && 539 540 # 2. Add the file with conflict markers 541 test_sparse_match test_must_fail git add folder1/a && 542 grep "Disable or modify the sparsity rules" sparse-checkout-err && 543 test_sparse_unstaged folder1/a && 544 test_all_match git add --sparse folder1/a && 545 test_all_match git status --porcelain=v2 && 546 547 # 3. Rename the file to another sparse filename and 548 # accept conflict markers as resolved content. 549 run_on_all mv folder2/a folder2/z && 550 test_sparse_match test_must_fail git add folder2 && 551 grep "Disable or modify the sparsity rules" sparse-checkout-err && 552 test_sparse_unstaged folder2/z && 553 test_all_match git add --sparse folder2 && 554 test_all_match git status --porcelain=v2 && 555 556 test_all_match git merge --continue && 557 test_all_match git status --porcelain=v2 && 558 test_all_match git rev-parse HEAD^{tree} 559' 560 561test_expect_success 'cherry-pick/rebase with conflict outside cone' ' 562 init_repos && 563 564 for OPERATION in cherry-pick rebase 565 do 566 test_all_match git checkout -B tip && 567 test_all_match git reset --hard merge-left && 568 test_all_match git status --porcelain=v2 && 569 test_all_match test_must_fail git $OPERATION merge-right && 570 test_all_match git status --porcelain=v2 && 571 572 # Resolve the conflict in different ways: 573 # 1. Revert to the base 574 test_all_match git checkout base -- deep/deeper2/a && 575 test_all_match git status --porcelain=v2 && 576 577 # 2. Add the file with conflict markers 578 # NEEDSWORK: Even though the merge conflict removed the 579 # SKIP_WORKTREE bit from the index entry for folder1/a, we should 580 # warn that this is a problematic add. 581 test_sparse_match test_must_fail git add folder1/a && 582 grep "Disable or modify the sparsity rules" sparse-checkout-err && 583 test_sparse_unstaged folder1/a && 584 test_all_match git add --sparse folder1/a && 585 test_all_match git status --porcelain=v2 && 586 587 # 3. Rename the file to another sparse filename and 588 # accept conflict markers as resolved content. 589 # NEEDSWORK: This mode now fails, because folder2/z is 590 # outside of the sparse-checkout cone and does not match an 591 # existing index entry with the SKIP_WORKTREE bit cleared. 592 run_on_all mv folder2/a folder2/z && 593 test_sparse_match test_must_fail git add folder2 && 594 grep "Disable or modify the sparsity rules" sparse-checkout-err && 595 test_sparse_unstaged folder2/z && 596 test_all_match git add --sparse folder2 && 597 test_all_match git status --porcelain=v2 && 598 599 test_all_match git $OPERATION --continue && 600 test_all_match git status --porcelain=v2 && 601 test_all_match git rev-parse HEAD^{tree} || return 1 602 done 603' 604 605test_expect_success 'merge with outside renames' ' 606 init_repos && 607 608 for type in out-to-out out-to-in in-to-out 609 do 610 test_all_match git reset --hard && 611 test_all_match git checkout -f -b merge-$type update-deep && 612 test_all_match git merge -m "$type" rename-$type && 613 test_all_match git rev-parse HEAD^{tree} || return 1 614 done 615' 616 617# Sparse-index fails to convert the index in the 618# final 'git cherry-pick' command. 619test_expect_success 'cherry-pick with conflicts' ' 620 init_repos && 621 622 write_script edit-conflict <<-\EOF && 623 echo $1 >conflict 624 EOF 625 626 test_all_match git checkout -b to-cherry-pick && 627 run_on_all ../edit-conflict ABC && 628 test_all_match git add conflict && 629 test_all_match git commit -m "conflict to pick" && 630 631 test_all_match git checkout -B base HEAD~1 && 632 run_on_all ../edit-conflict DEF && 633 test_all_match git add conflict && 634 test_all_match git commit -m "conflict in base" && 635 636 test_all_match test_must_fail git cherry-pick to-cherry-pick 637' 638 639test_expect_success 'clean' ' 640 init_repos && 641 642 echo bogus >>.gitignore && 643 run_on_all cp ../.gitignore . && 644 test_all_match git add .gitignore && 645 test_all_match git commit -m "ignore bogus files" && 646 647 run_on_sparse mkdir folder1 && 648 run_on_all touch folder1/bogus && 649 650 test_all_match git status --porcelain=v2 && 651 test_all_match git clean -f && 652 test_all_match git status --porcelain=v2 && 653 test_sparse_match ls && 654 test_sparse_match ls folder1 && 655 656 test_all_match git clean -xf && 657 test_all_match git status --porcelain=v2 && 658 test_sparse_match ls && 659 test_sparse_match ls folder1 && 660 661 test_all_match git clean -xdf && 662 test_all_match git status --porcelain=v2 && 663 test_sparse_match ls && 664 test_sparse_match ls folder1 && 665 666 test_sparse_match test_path_is_dir folder1 667' 668 669test_expect_success 'submodule handling' ' 670 init_repos && 671 672 test_sparse_match git sparse-checkout add modules && 673 test_all_match mkdir modules && 674 test_all_match touch modules/a && 675 test_all_match git add modules && 676 test_all_match git commit -m "add modules directory" && 677 678 run_on_all git submodule add "$(pwd)/initial-repo" modules/sub && 679 test_all_match git commit -m "add submodule" && 680 681 # having a submodule prevents "modules" from collapse 682 test_sparse_match git sparse-checkout set deep/deeper1 && 683 test-tool -C sparse-index read-cache --table >cache && 684 grep "100644 blob .* modules/a" cache && 685 grep "160000 commit $(git -C initial-repo rev-parse HEAD) modules/sub" cache 686' 687 688test_expect_success 'sparse-index is expanded and converted back' ' 689 init_repos && 690 691 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ 692 git -C sparse-index -c core.fsmonitor="" reset --hard && 693 test_region index convert_to_sparse trace2.txt && 694 test_region index ensure_full_index trace2.txt 695' 696 697ensure_not_expanded () { 698 rm -f trace2.txt && 699 echo >>sparse-index/untracked.txt && 700 701 if test "$1" = "!" 702 then 703 shift && 704 test_must_fail env \ 705 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ 706 git -C sparse-index "$@" || return 1 707 else 708 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ 709 git -C sparse-index "$@" || return 1 710 fi && 711 test_region ! index ensure_full_index trace2.txt 712} 713 714test_expect_success 'sparse-index is not expanded' ' 715 init_repos && 716 717 ensure_not_expanded status && 718 ensure_not_expanded commit --allow-empty -m empty && 719 echo >>sparse-index/a && 720 ensure_not_expanded commit -a -m a && 721 echo >>sparse-index/a && 722 ensure_not_expanded commit --include a -m a && 723 echo >>sparse-index/deep/deeper1/a && 724 ensure_not_expanded commit --include deep/deeper1/a -m deeper && 725 ensure_not_expanded checkout rename-out-to-out && 726 ensure_not_expanded checkout - && 727 ensure_not_expanded switch rename-out-to-out && 728 ensure_not_expanded switch - && 729 git -C sparse-index reset --hard && 730 ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 && 731 git -C sparse-index reset --hard && 732 ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 && 733 734 echo >>sparse-index/README.md && 735 ensure_not_expanded add -A && 736 echo >>sparse-index/extra.txt && 737 ensure_not_expanded add extra.txt && 738 echo >>sparse-index/untracked.txt && 739 ensure_not_expanded add . && 740 741 ensure_not_expanded checkout -f update-deep && 742 test_config -C sparse-index pull.twohead ort && 743 ( 744 sane_unset GIT_TEST_MERGE_ALGORITHM && 745 for OPERATION in "merge -m merge" cherry-pick rebase 746 do 747 ensure_not_expanded merge -m merge update-folder1 && 748 ensure_not_expanded merge -m merge update-folder2 || return 1 749 done 750 ) 751' 752 753test_expect_success 'sparse-index is not expanded: merge conflict in cone' ' 754 init_repos && 755 756 for side in right left 757 do 758 git -C sparse-index checkout -b expand-$side base && 759 echo $side >sparse-index/deep/a && 760 git -C sparse-index commit -a -m "$side" || return 1 761 done && 762 763 ( 764 sane_unset GIT_TEST_MERGE_ALGORITHM && 765 git -C sparse-index config pull.twohead ort && 766 ensure_not_expanded ! merge -m merged expand-right 767 ) 768' 769 770# NEEDSWORK: a sparse-checkout behaves differently from a full checkout 771# in this scenario, but it shouldn't. 772test_expect_success 'reset mixed and checkout orphan' ' 773 init_repos && 774 775 test_all_match git checkout rename-out-to-in && 776 777 # Sparse checkouts do not agree with full checkouts about 778 # how to report a directory/file conflict during a reset. 779 # This command would fail with test_all_match because the 780 # full checkout reports "T folder1/0/1" while a sparse 781 # checkout reports "D folder1/0/1". This matches because 782 # the sparse checkouts skip "adding" the other side of 783 # the conflict. 784 test_sparse_match git reset --mixed HEAD~1 && 785 test_sparse_match test-tool read-cache --table --expand && 786 test_sparse_match git status --porcelain=v2 && 787 788 # At this point, sparse-checkouts behave differently 789 # from the full-checkout. 790 test_sparse_match git checkout --orphan new-branch && 791 test_sparse_match test-tool read-cache --table --expand && 792 test_sparse_match git status --porcelain=v2 793' 794 795test_expect_success 'add everything with deep new file' ' 796 init_repos && 797 798 run_on_sparse git sparse-checkout set deep/deeper1/deepest && 799 800 run_on_all touch deep/deeper1/x && 801 test_all_match git add . && 802 test_all_match git status --porcelain=v2 803' 804 805# NEEDSWORK: 'git checkout' behaves incorrectly in the case of 806# directory/file conflicts, even without sparse-checkout. Use this 807# test only as a documentation of the incorrect behavior, not a 808# measure of how it _should_ behave. 809test_expect_success 'checkout behaves oddly with df-conflict-1' ' 810 init_repos && 811 812 test_sparse_match git sparse-checkout disable && 813 814 write_script edit-content <<-\EOF && 815 echo content >>folder1/larger-content 816 git add folder1 817 EOF 818 819 run_on_all ../edit-content && 820 test_all_match git status --porcelain=v2 && 821 822 git -C sparse-checkout sparse-checkout init --cone && 823 git -C sparse-index sparse-checkout init --cone --sparse-index && 824 825 test_all_match git status --porcelain=v2 && 826 827 # This checkout command should fail, because we have a staged 828 # change to folder1/larger-content, but the destination changes 829 # folder1 to a file. 830 git -C full-checkout checkout df-conflict-1 \ 831 1>full-checkout-out \ 832 2>full-checkout-err && 833 git -C sparse-checkout checkout df-conflict-1 \ 834 1>sparse-checkout-out \ 835 2>sparse-checkout-err && 836 git -C sparse-index checkout df-conflict-1 \ 837 1>sparse-index-out \ 838 2>sparse-index-err && 839 840 # Instead, the checkout deletes the folder1 file and adds the 841 # folder1/larger-content file, leaving all other paths that were 842 # in folder1/ as deleted (without any warning). 843 cat >expect <<-EOF && 844 D folder1 845 A folder1/larger-content 846 EOF 847 test_cmp expect full-checkout-out && 848 test_cmp expect sparse-checkout-out && 849 850 # The sparse-index reports no output 851 test_must_be_empty sparse-index-out && 852 853 # stderr: Switched to branch df-conflict-1 854 test_cmp full-checkout-err sparse-checkout-err && 855 test_cmp full-checkout-err sparse-checkout-err 856' 857 858# NEEDSWORK: 'git checkout' behaves incorrectly in the case of 859# directory/file conflicts, even without sparse-checkout. Use this 860# test only as a documentation of the incorrect behavior, not a 861# measure of how it _should_ behave. 862test_expect_success 'checkout behaves oddly with df-conflict-2' ' 863 init_repos && 864 865 test_sparse_match git sparse-checkout disable && 866 867 write_script edit-content <<-\EOF && 868 echo content >>folder2/larger-content 869 git add folder2 870 EOF 871 872 run_on_all ../edit-content && 873 test_all_match git status --porcelain=v2 && 874 875 git -C sparse-checkout sparse-checkout init --cone && 876 git -C sparse-index sparse-checkout init --cone --sparse-index && 877 878 test_all_match git status --porcelain=v2 && 879 880 # This checkout command should fail, because we have a staged 881 # change to folder1/larger-content, but the destination changes 882 # folder1 to a file. 883 git -C full-checkout checkout df-conflict-2 \ 884 1>full-checkout-out \ 885 2>full-checkout-err && 886 git -C sparse-checkout checkout df-conflict-2 \ 887 1>sparse-checkout-out \ 888 2>sparse-checkout-err && 889 git -C sparse-index checkout df-conflict-2 \ 890 1>sparse-index-out \ 891 2>sparse-index-err && 892 893 # The full checkout deviates from the df-conflict-1 case here! 894 # It drops the change to folder1/larger-content and leaves the 895 # folder1 path as-is on disk. The sparse-index behaves the same. 896 test_must_be_empty full-checkout-out && 897 test_must_be_empty sparse-index-out && 898 899 # In the sparse-checkout case, the checkout deletes the folder1 900 # file and adds the folder1/larger-content file, leaving all other 901 # paths that were in folder1/ as deleted (without any warning). 902 cat >expect <<-EOF && 903 D folder2 904 A folder2/larger-content 905 EOF 906 test_cmp expect sparse-checkout-out && 907 908 # Switched to branch df-conflict-1 909 test_cmp full-checkout-err sparse-checkout-err && 910 test_cmp full-checkout-err sparse-index-err 911' 912 913test_done 914