Git fork
at reftables-rust 1099 lines 38 kB view raw
1# Create a submodule layout used for all tests below. 2# 3# The following use cases are covered: 4# - New submodule (no_submodule => add_sub1) 5# - Removed submodule (add_sub1 => remove_sub1) 6# - Updated submodule (add_sub1 => modify_sub1) 7# - Updated submodule recursively (add_nested_sub => modify_sub1_recursively) 8# - Submodule updated to invalid commit (add_sub1 => invalid_sub1) 9# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1) 10# - Submodule replaced by tracked files in directory (add_sub1 => 11# replace_sub1_with_directory) 12# - Directory containing tracked files replaced by submodule 13# (replace_sub1_with_directory => replace_directory_with_sub1) 14# - Submodule replaced by tracked file with the same name (add_sub1 => 15# replace_sub1_with_file) 16# - Tracked file replaced by submodule (replace_sub1_with_file => 17# replace_file_with_sub1) 18# 19# ----O 20# / ^ 21# / remove_sub1 22# / 23# add_sub1 /-------O---------O--------O modify_sub1_recursively 24# | / ^ add_nested_sub 25# | / modify_sub1 26# v/ 27# O------O-----------O---------O 28# ^ \ ^ replace_directory_with_sub1 29# | \ replace_sub1_with_directory 30# no_submodule \ 31# --------O---------O 32# \ ^ replace_file_with_sub1 33# \ replace_sub1_with_file 34# \ 35# ----O---------O 36# ^ valid_sub1 37# invalid_sub1 38# 39 40create_lib_submodule_repo () { 41 git init submodule_update_sub1 && 42 ( 43 cd submodule_update_sub1 && 44 echo "expect" >>.gitignore && 45 echo "actual" >>.gitignore && 46 echo "x" >file1 && 47 echo "y" >file2 && 48 git add .gitignore file1 file2 && 49 git commit -m "Base inside first submodule" && 50 git branch "no_submodule" 51 ) && 52 git init submodule_update_sub2 && 53 ( 54 cd submodule_update_sub2 55 echo "expect" >>.gitignore && 56 echo "actual" >>.gitignore && 57 echo "x" >file1 && 58 echo "y" >file2 && 59 git add .gitignore file1 file2 && 60 git commit -m "nested submodule base" && 61 git branch "no_submodule" 62 ) && 63 git init submodule_update_repo && 64 ( 65 cd submodule_update_repo && 66 branch=$(git symbolic-ref --short HEAD) && 67 echo "expect" >>.gitignore && 68 echo "actual" >>.gitignore && 69 echo "x" >file1 && 70 echo "y" >file2 && 71 git add .gitignore file1 file2 && 72 git commit -m "Base" && 73 git branch "no_submodule" && 74 75 git checkout -b "add_sub1" && 76 git submodule add ../submodule_update_sub1 sub1 && 77 git submodule add ../submodule_update_sub1 uninitialized_sub && 78 git config -f .gitmodules submodule.sub1.ignore all && 79 git config submodule.sub1.ignore all && 80 git add .gitmodules && 81 git commit -m "Add sub1" && 82 83 git checkout -b remove_sub1 add_sub1 && 84 git revert HEAD && 85 86 git checkout -b modify_sub1 add_sub1 && 87 git submodule update && 88 ( 89 cd sub1 && 90 git fetch && 91 git checkout -b "modifications" && 92 echo "z" >file2 && 93 echo "x" >file3 && 94 git add file2 file3 && 95 git commit -m "modified file2 and added file3" && 96 git push origin modifications 97 ) && 98 git add sub1 && 99 git commit -m "Modify sub1" && 100 101 git checkout -b add_nested_sub modify_sub1 && 102 git -C sub1 checkout -b "add_nested_sub" && 103 git -C sub1 submodule add --branch no_submodule ../submodule_update_sub2 sub2 && 104 git -C sub1 commit -a -m "add a nested submodule" && 105 git add sub1 && 106 git commit -a -m "update submodule, that updates a nested submodule" && 107 git checkout -b modify_sub1_recursively && 108 git -C sub1 checkout -b modify_sub1_recursively && 109 git -C sub1/sub2 checkout -b modify_sub1_recursively && 110 echo change >sub1/sub2/file3 && 111 git -C sub1/sub2 add file3 && 112 git -C sub1/sub2 commit -m "make a change in nested sub" && 113 git -C sub1 add sub2 && 114 git -C sub1 commit -m "update nested sub" && 115 git add sub1 && 116 git commit -m "update sub1, that updates nested sub" && 117 git -C sub1 push origin modify_sub1_recursively && 118 git -C sub1/sub2 push origin modify_sub1_recursively && 119 git -C sub1 submodule deinit -f --all && 120 121 git checkout -b replace_sub1_with_directory add_sub1 && 122 git submodule update && 123 git -C sub1 checkout modifications && 124 git rm --cached sub1 && 125 rm sub1/.git* && 126 git config -f .gitmodules --remove-section "submodule.sub1" && 127 git add .gitmodules sub1/* && 128 git commit -m "Replace sub1 with directory" && 129 130 git checkout -b replace_directory_with_sub1 && 131 git revert HEAD && 132 133 git checkout -b replace_sub1_with_file add_sub1 && 134 git rm sub1 && 135 echo "content" >sub1 && 136 git add sub1 && 137 git commit -m "Replace sub1 with file" && 138 139 git checkout -b replace_file_with_sub1 && 140 git revert HEAD && 141 142 git checkout -b invalid_sub1 add_sub1 && 143 git update-index --cacheinfo 160000 $(test_oid numeric) sub1 && 144 git commit -m "Invalid sub1 commit" && 145 git checkout -b valid_sub1 && 146 git revert HEAD && 147 148 git checkout "$branch" 149 ) 150} 151 152# Helper function to replace gitfile with .git directory 153replace_gitfile_with_git_dir () { 154 ( 155 cd "$1" && 156 git_dir="$(git rev-parse --git-dir)" && 157 rm -f .git && 158 cp -R "$git_dir" .git && 159 GIT_WORK_TREE=. git config --unset core.worktree 160 ) 161} 162 163# Test that the .git directory in the submodule is unchanged (except for the 164# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config). 165# Call this function before test_submodule_content as the latter might 166# write the index file leading to false positive index differences. 167# 168# Note that this only supports submodules at the root level of the 169# superproject, with the default name, i.e. same as its path. 170test_git_directory_is_unchanged () { 171 # does core.worktree point at the right place? 172 echo "../../../$1" >expect && 173 git -C ".git/modules/$1" config core.worktree >actual && 174 test_cmp expect actual && 175 # remove it temporarily before comparing, as 176 # "$1/.git/config" lacks it... 177 git -C ".git/modules/$1" config --unset core.worktree && 178 diff -r ".git/modules/$1" "$1/.git" && 179 # ... and then restore. 180 git -C ".git/modules/$1" config core.worktree "../../../$1" 181} 182 183test_git_directory_exists () { 184 test -e ".git/modules/$1" && 185 if test -f sub1/.git 186 then 187 # does core.worktree point at the right place? 188 echo "../../../$1" >expect && 189 git -C ".git/modules/$1" config core.worktree >actual && 190 test_cmp expect actual 191 fi 192} 193 194# Helper function to be executed at the start of every test below, it sets up 195# the submodule repo if it doesn't exist and configures the most problematic 196# settings for diff.ignoreSubmodules. 197prolog () { 198 test_config_global protocol.file.allow always && 199 (test -d submodule_update_repo || create_lib_submodule_repo) && 200 test_config_global diff.ignoreSubmodules all && 201 test_config diff.ignoreSubmodules all 202} 203 204# Helper function to bring work tree back into the state given by the 205# commit. This includes trying to populate sub1 accordingly if it exists and 206# should be updated to an existing commit. 207reset_work_tree_to () { 208 rm -rf submodule_update && 209 git clone --template= submodule_update_repo submodule_update && 210 ( 211 cd submodule_update && 212 rm -rf sub1 && 213 git checkout -f "$1" && 214 git status -u -s >actual && 215 test_must_be_empty actual && 216 hash=$(git rev-parse --revs-only HEAD:sub1) && 217 if test -n "$hash" && 218 test $(cd "../submodule_update_sub1" && git rev-parse --verify "$hash^{commit}") 219 then 220 git submodule update --init --recursive "sub1" 221 fi 222 ) 223} 224 225reset_work_tree_to_interested () { 226 reset_work_tree_to $1 && 227 # make the submodule git dirs available 228 if ! test -d submodule_update/.git/modules/sub1 229 then 230 mkdir -p submodule_update/.git/modules && 231 cp -r submodule_update_repo/.git/modules/sub1 submodule_update/.git/modules/sub1 232 GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1 config --unset core.worktree 233 fi && 234 if ! test -d submodule_update/.git/modules/sub1/modules/sub2 235 then 236 mkdir -p submodule_update/.git/modules/sub1/modules && 237 cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 238 # core.worktree is unset for sub2 as it is not checked out 239 fi && 240 # indicate we are interested in the submodule: 241 git -C submodule_update config submodule.sub1.url "bogus" && 242 # sub1 might not be checked out, so use the git dir 243 git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus" 244} 245 246# Test that the superproject contains the content according to commit "$1" 247# (the work tree must match the index for everything but submodules but the 248# index must exactly match the given commit including any submodule SHA-1s). 249test_superproject_content () { 250 git diff-index --cached "$1" >actual && 251 test_must_be_empty actual && 252 git diff-files --ignore-submodules >actual && 253 test_must_be_empty actual 254} 255 256# Test that the given submodule at path "$1" contains the content according 257# to the submodule commit recorded in the superproject's commit "$2" 258test_submodule_content () { 259 if test x"$1" = "x-C" 260 then 261 cd "$2" 262 shift; shift; 263 fi 264 if test $# != 2 265 then 266 echo "test_submodule_content needs two arguments" 267 return 1 268 fi && 269 submodule="$1" && 270 commit="$2" && 271 test -d "$submodule"/ && 272 if ! test -f "$submodule"/.git && ! test -d "$submodule"/.git 273 then 274 echo "Submodule $submodule is not populated" 275 return 1 276 fi && 277 sha1=$(git rev-parse --verify "$commit:$submodule") && 278 if test -z "$sha1" 279 then 280 echo "Couldn't retrieve SHA-1 of $submodule for $commit" 281 return 1 282 fi && 283 ( 284 cd "$submodule" && 285 git status -u -s >actual && 286 test_must_be_empty actual && 287 git diff "$sha1" >actual && 288 test_must_be_empty actual 289 ) 290} 291 292# Test that the following transitions are correctly handled: 293# - Updated submodule 294# - New submodule 295# - Removed submodule 296# - Directory containing tracked files replaced by submodule 297# - Submodule replaced by tracked files in directory 298# - Submodule replaced by tracked file with the same name 299# - Tracked file replaced by submodule 300# 301# The default is that submodule contents aren't changed until "git submodule 302# update" is run. And even then that command doesn't delete the work tree of 303# a removed submodule. 304# 305# The first argument of the callback function will be the name of the submodule. 306# 307# Removing a submodule containing a .git directory must fail even when forced 308# to protect the history! If we are testing this case, the second argument of 309# the callback function will be 'test_must_fail', else it will be the empty 310# string. 311# 312 313# Internal function; use test_submodule_switch_func(), test_submodule_switch(), 314# or test_submodule_forced_switch() instead. 315test_submodule_switch_common () { 316 command="$1" 317 ######################### Appearing submodule ######################### 318 # Switching to a commit letting a submodule appear creates empty dir ... 319 test_expect_success "$command: added submodule creates empty directory" ' 320 prolog && 321 reset_work_tree_to no_submodule && 322 ( 323 cd submodule_update && 324 git branch -t add_sub1 origin/add_sub1 && 325 $command add_sub1 && 326 test_superproject_content origin/add_sub1 && 327 test_dir_is_empty sub1 && 328 git submodule update --init --recursive && 329 test_submodule_content sub1 origin/add_sub1 330 ) 331 ' 332 # ... and doesn't care if it already exists. 333 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1 334 then 335 # Restoring stash fails to restore submodule index entry 336 RESULT="failure" 337 else 338 RESULT="success" 339 fi 340 test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" ' 341 prolog && 342 reset_work_tree_to no_submodule && 343 ( 344 cd submodule_update && 345 mkdir sub1 && 346 git branch -t add_sub1 origin/add_sub1 && 347 $command add_sub1 && 348 test_superproject_content origin/add_sub1 && 349 test_dir_is_empty sub1 && 350 git submodule update --init --recursive && 351 test_submodule_content sub1 origin/add_sub1 352 ) 353 ' 354 # Replacing a tracked file with a submodule produces an empty 355 # directory ... 356 test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" ' 357 prolog && 358 reset_work_tree_to replace_sub1_with_file && 359 ( 360 cd submodule_update && 361 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && 362 $command replace_file_with_sub1 && 363 test_superproject_content origin/replace_file_with_sub1 && 364 test_dir_is_empty sub1 && 365 git submodule update --init --recursive && 366 test_submodule_content sub1 origin/replace_file_with_sub1 367 ) 368 ' 369 # ... as does removing a directory with tracked files with a 370 # submodule. 371 if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1 372 then 373 # Non fast-forward merges fail with "Directory sub1 doesn't 374 # exist. sub1" because the empty submodule directory is not 375 # created 376 RESULT="failure" 377 else 378 RESULT="success" 379 fi 380 test_expect_$RESULT "$command: replace directory with submodule" ' 381 prolog && 382 reset_work_tree_to replace_sub1_with_directory && 383 ( 384 cd submodule_update && 385 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && 386 $command replace_directory_with_sub1 && 387 test_superproject_content origin/replace_directory_with_sub1 && 388 test_dir_is_empty sub1 && 389 git submodule update --init --recursive && 390 test_submodule_content sub1 origin/replace_directory_with_sub1 391 ) 392 ' 393 394 ######################## Disappearing submodule ####################### 395 # Removing a submodule doesn't remove its work tree ... 396 if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1 397 then 398 RESULT="failure" 399 else 400 RESULT="success" 401 fi 402 test_expect_$RESULT "$command: removed submodule leaves submodule directory and its contents in place" ' 403 prolog && 404 reset_work_tree_to add_sub1 && 405 ( 406 cd submodule_update && 407 git branch -t remove_sub1 origin/remove_sub1 && 408 $command remove_sub1 && 409 test_superproject_content origin/remove_sub1 && 410 test_submodule_content sub1 origin/add_sub1 411 ) 412 ' 413 # ... especially when it contains a .git directory. 414 test_expect_$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" ' 415 prolog && 416 reset_work_tree_to add_sub1 && 417 ( 418 cd submodule_update && 419 git branch -t remove_sub1 origin/remove_sub1 && 420 replace_gitfile_with_git_dir sub1 && 421 $command remove_sub1 && 422 test_superproject_content origin/remove_sub1 && 423 test_git_directory_is_unchanged sub1 && 424 test_submodule_content sub1 origin/add_sub1 425 ) 426 ' 427 # Replacing a submodule with files in a directory must fail as the 428 # submodule work tree isn't removed ... 429 if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1 430 then 431 # Non fast-forward merges attempt to merge the former 432 # submodule files with the newly checked out ones in the 433 # directory of the same name while it shouldn't. 434 RESULT="failure" 435 elif test "$KNOWN_FAILURE_FORCED_SWITCH_TESTS" = 1 436 then 437 # All existing tests that use test_submodule_forced_switch() 438 # require this. 439 RESULT="failure" 440 else 441 RESULT="success" 442 fi 443 test_expect_$RESULT "$command: replace submodule with a directory must fail" ' 444 prolog && 445 reset_work_tree_to add_sub1 && 446 ( 447 cd submodule_update && 448 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 449 $command replace_sub1_with_directory test_must_fail && 450 test_superproject_content origin/add_sub1 && 451 test_submodule_content sub1 origin/add_sub1 452 ) 453 ' 454 # ... especially when it contains a .git directory. 455 test_expect_$RESULT "$command: replace submodule containing a .git directory with a directory must fail" ' 456 prolog && 457 reset_work_tree_to add_sub1 && 458 ( 459 cd submodule_update && 460 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 461 replace_gitfile_with_git_dir sub1 && 462 $command replace_sub1_with_directory test_must_fail && 463 test_superproject_content origin/add_sub1 && 464 test_git_directory_is_unchanged sub1 && 465 test_submodule_content sub1 origin/add_sub1 466 ) 467 ' 468 # Replacing it with a file must fail as it could throw away any local 469 # work tree changes ... 470 test_expect_failure "$command: replace submodule with a file must fail" ' 471 prolog && 472 reset_work_tree_to add_sub1 && 473 ( 474 cd submodule_update && 475 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 476 $command replace_sub1_with_file test_must_fail && 477 test_superproject_content origin/add_sub1 && 478 test_submodule_content sub1 origin/add_sub1 479 ) 480 ' 481 # ... or even destroy unpushed parts of submodule history if that 482 # still uses a .git directory. 483 test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" ' 484 prolog && 485 reset_work_tree_to add_sub1 && 486 ( 487 cd submodule_update && 488 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 489 replace_gitfile_with_git_dir sub1 && 490 $command replace_sub1_with_file test_must_fail && 491 test_superproject_content origin/add_sub1 && 492 test_git_directory_is_unchanged sub1 && 493 test_submodule_content sub1 origin/add_sub1 494 ) 495 ' 496 497 ########################## Modified submodule ######################### 498 # Updating a submodule sha1 doesn't update the submodule's work tree 499 if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1 500 then 501 # When cherry picking a SHA-1 update for an ignored submodule 502 # the commit incorrectly fails with "The previous cherry-pick 503 # is now empty, possibly due to conflict resolution." 504 RESULT="failure" 505 else 506 RESULT="success" 507 fi 508 test_expect_$RESULT "$command: modified submodule does not update submodule work tree" ' 509 prolog && 510 reset_work_tree_to add_sub1 && 511 ( 512 cd submodule_update && 513 git branch -t modify_sub1 origin/modify_sub1 && 514 $command modify_sub1 && 515 test_superproject_content origin/modify_sub1 && 516 test_submodule_content sub1 origin/add_sub1 && 517 git submodule update && 518 test_submodule_content sub1 origin/modify_sub1 519 ) 520 ' 521 # Updating a submodule to an invalid sha1 doesn't update the 522 # submodule's work tree, subsequent update will fail 523 test_expect_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" ' 524 prolog && 525 reset_work_tree_to add_sub1 && 526 ( 527 cd submodule_update && 528 git branch -t invalid_sub1 origin/invalid_sub1 && 529 $command invalid_sub1 && 530 test_superproject_content origin/invalid_sub1 && 531 test_submodule_content sub1 origin/add_sub1 && 532 test_must_fail git submodule update && 533 test_submodule_content sub1 origin/add_sub1 534 ) 535 ' 536 # Updating a submodule from an invalid sha1 doesn't update the 537 # submodule's work tree, subsequent update will succeed 538 test_expect_$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" ' 539 prolog && 540 reset_work_tree_to invalid_sub1 && 541 ( 542 cd submodule_update && 543 git branch -t valid_sub1 origin/valid_sub1 && 544 $command valid_sub1 && 545 test_superproject_content origin/valid_sub1 && 546 test_dir_is_empty sub1 && 547 git submodule update --init --recursive && 548 test_submodule_content sub1 origin/valid_sub1 549 ) 550 ' 551} 552 553# Declares and invokes several tests that, in various situations, checks that 554# the provided transition function: 555# - succeeds in updating the worktree and index of a superproject to a target 556# commit, or fails atomically (depending on the test situation) 557# - if succeeds, the contents of submodule directories are unchanged 558# - if succeeds, once "git submodule update" is invoked, the contents of 559# submodule directories are updated 560# 561# If the command under test is known to not work with submodules in certain 562# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests 563# below to 1. 564# 565# The first argument of the callback function will be the name of the submodule. 566# 567# Removing a submodule containing a .git directory must fail even when forced 568# to protect the history! If we are testing this case, the second argument of 569# the callback function will be 'test_must_fail', else it will be the empty 570# string. 571# 572# The following example uses `git some-command` as an example command to be 573# tested. It updates the worktree and index to match a target, but not any 574# submodule directories. 575# 576# my_func () { 577# ...prepare for `git some-command` to be run... 578# $2 git some-command "$1" && 579# if test -n "$2" 580# then 581# return 582# fi && 583# ...check the state after git some-command is run... 584# } 585# test_submodule_switch_func "my_func" 586test_submodule_switch_func () { 587 command="$1" 588 test_submodule_switch_common "$command" 589 590 # An empty directory does not prevent the creation of a submodule of 591 # the same name, but a file does. 592 test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" ' 593 prolog && 594 reset_work_tree_to no_submodule && 595 ( 596 cd submodule_update && 597 git branch -t add_sub1 origin/add_sub1 && 598 >sub1 && 599 $command add_sub1 test_must_fail && 600 test_superproject_content origin/no_submodule && 601 test_must_be_empty sub1 602 ) 603 ' 604} 605 606# Ensures that the that the arg either contains "test_must_fail" or is empty. 607may_only_be_test_must_fail () { 608 test -z "$1" || test "$1" = test_must_fail || die 609} 610 611git_test_func () { 612 may_only_be_test_must_fail "$2" && 613 $2 git $gitcmd "$1" 614} 615 616test_submodule_switch () { 617 gitcmd="$1" 618 test_submodule_switch_func "git_test_func" 619} 620 621# Same as test_submodule_switch(), except that throwing away local changes in 622# the superproject is allowed. 623test_submodule_forced_switch () { 624 gitcmd="$1" 625 command="git_test_func" 626 KNOWN_FAILURE_FORCED_SWITCH_TESTS=1 627 test_submodule_switch_common "$command" 628 629 # When forced, a file in the superproject does not prevent creating a 630 # submodule of the same name. 631 test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" ' 632 prolog && 633 reset_work_tree_to no_submodule && 634 ( 635 cd submodule_update && 636 git branch -t add_sub1 origin/add_sub1 && 637 >sub1 && 638 $command add_sub1 && 639 test_superproject_content origin/add_sub1 && 640 test_dir_is_empty sub1 641 ) 642 ' 643} 644 645# Test that submodule contents are correctly updated when switching 646# between commits that change a submodule. 647# Test that the following transitions are correctly handled: 648# (These tests are also above in the case where we expect no change 649# in the submodule) 650# - Updated submodule 651# - New submodule 652# - Removed submodule 653# - Directory containing tracked files replaced by submodule 654# - Submodule replaced by tracked files in directory 655# - Submodule replaced by tracked file with the same name 656# - Tracked file replaced by submodule 657# 658# New test cases 659# - Removing a submodule with a git directory absorbs the submodules 660# git directory first into the superproject. 661# - Switching from no submodule to nested submodules 662# - Switching from nested submodules to no submodule 663 664# Internal function; use test_submodule_switch_recursing_with_args() or 665# test_submodule_forced_switch_recursing_with_args() instead. 666test_submodule_recursing_with_args_common () { 667 command="$1 --recurse-submodules" 668 669 ######################### Appearing submodule ######################### 670 # Switching to a commit letting a submodule appear checks it out ... 671 test_expect_success "$command: added submodule is checked out" ' 672 prolog && 673 reset_work_tree_to_interested no_submodule && 674 ( 675 cd submodule_update && 676 git branch -t add_sub1 origin/add_sub1 && 677 $command add_sub1 && 678 test_superproject_content origin/add_sub1 && 679 test_submodule_content sub1 origin/add_sub1 680 ) 681 ' 682 # ... ignoring an empty existing directory. 683 test_expect_success "$command: added submodule is checked out in empty dir" ' 684 prolog && 685 reset_work_tree_to_interested no_submodule && 686 ( 687 cd submodule_update && 688 mkdir sub1 && 689 git branch -t add_sub1 origin/add_sub1 && 690 $command add_sub1 && 691 test_superproject_content origin/add_sub1 && 692 test_submodule_content sub1 origin/add_sub1 693 ) 694 ' 695 696 # Replacing a tracked file with a submodule produces a checked out submodule 697 test_expect_success "$command: replace tracked file with submodule checks out submodule" ' 698 prolog && 699 reset_work_tree_to_interested replace_sub1_with_file && 700 ( 701 cd submodule_update && 702 git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && 703 $command replace_file_with_sub1 && 704 test_superproject_content origin/replace_file_with_sub1 && 705 test_submodule_content sub1 origin/replace_file_with_sub1 706 ) 707 ' 708 # ... as does removing a directory with tracked files with a submodule. 709 test_expect_success "$command: replace directory with submodule" ' 710 prolog && 711 reset_work_tree_to_interested replace_sub1_with_directory && 712 ( 713 cd submodule_update && 714 git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && 715 $command replace_directory_with_sub1 && 716 test_superproject_content origin/replace_directory_with_sub1 && 717 test_submodule_content sub1 origin/replace_directory_with_sub1 718 ) 719 ' 720 # Switching to a commit with nested submodules recursively checks them out 721 test_expect_success "$command: nested submodules are checked out" ' 722 prolog && 723 reset_work_tree_to_interested no_submodule && 724 ( 725 cd submodule_update && 726 git branch -t modify_sub1_recursively origin/modify_sub1_recursively && 727 $command modify_sub1_recursively && 728 test_superproject_content origin/modify_sub1_recursively && 729 test_submodule_content sub1 origin/modify_sub1_recursively && 730 test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively 731 ) 732 ' 733 734 ######################## Disappearing submodule ####################### 735 # Removing a submodule removes its work tree ... 736 test_expect_success "$command: removed submodule removes submodules working tree" ' 737 prolog && 738 reset_work_tree_to_interested add_sub1 && 739 ( 740 cd submodule_update && 741 git branch -t remove_sub1 origin/remove_sub1 && 742 $command remove_sub1 && 743 test_superproject_content origin/remove_sub1 && 744 ! test -e sub1 && 745 test_must_fail git config -f .git/modules/sub1/config core.worktree 746 ) 747 ' 748 # ... absorbing a .git directory along the way. 749 test_expect_success "$command: removed submodule absorbs submodules .git directory" ' 750 prolog && 751 reset_work_tree_to_interested add_sub1 && 752 ( 753 cd submodule_update && 754 git branch -t remove_sub1 origin/remove_sub1 && 755 replace_gitfile_with_git_dir sub1 && 756 rm -rf .git/modules && 757 $command remove_sub1 && 758 test_superproject_content origin/remove_sub1 && 759 ! test -e sub1 && 760 test_git_directory_exists sub1 761 ) 762 ' 763 764 # Replacing it with a file ... 765 test_expect_success "$command: replace submodule with a file" ' 766 prolog && 767 reset_work_tree_to_interested add_sub1 && 768 ( 769 cd submodule_update && 770 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 771 $command replace_sub1_with_file && 772 test_superproject_content origin/replace_sub1_with_file && 773 test -f sub1 774 ) 775 ' 776 RESULTDS=success 777 if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1 778 then 779 RESULTDS=failure 780 fi 781 # ... must check its local work tree for untracked files 782 test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" ' 783 prolog && 784 reset_work_tree_to_interested add_sub1 && 785 ( 786 cd submodule_update && 787 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 788 : >sub1/untrackedfile && 789 test_must_fail $command replace_sub1_with_file && 790 test_superproject_content origin/add_sub1 && 791 test_submodule_content sub1 origin/add_sub1 && 792 test -f sub1/untracked_file 793 ) 794 ' 795 796 # Switching to a commit without nested submodules removes their worktrees 797 test_expect_success "$command: worktrees of nested submodules are removed" ' 798 prolog && 799 reset_work_tree_to_interested add_nested_sub && 800 ( 801 cd submodule_update && 802 git branch -t no_submodule origin/no_submodule && 803 $command no_submodule && 804 test_superproject_content origin/no_submodule && 805 test_path_is_missing sub1 && 806 test_must_fail git config -f .git/modules/sub1/config core.worktree && 807 test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree 808 ) 809 ' 810 811 ########################## Modified submodule ######################### 812 # Updating a submodule sha1 updates the submodule's work tree 813 test_expect_success "$command: modified submodule updates submodule work tree" ' 814 prolog && 815 reset_work_tree_to_interested add_sub1 && 816 ( 817 cd submodule_update && 818 git branch -t modify_sub1 origin/modify_sub1 && 819 $command modify_sub1 && 820 test_superproject_content origin/modify_sub1 && 821 test_submodule_content sub1 origin/modify_sub1 822 ) 823 ' 824 # Updating a submodule to an invalid sha1 doesn't update the 825 # superproject nor the submodule's work tree. 826 test_expect_success "$command: updating to a missing submodule commit fails" ' 827 prolog && 828 reset_work_tree_to_interested add_sub1 && 829 ( 830 cd submodule_update && 831 git branch -t invalid_sub1 origin/invalid_sub1 && 832 test_must_fail $command invalid_sub1 2>err && 833 test_grep sub1 err && 834 test_superproject_content origin/add_sub1 && 835 test_submodule_content sub1 origin/add_sub1 836 ) 837 ' 838 # Updating a submodule does not touch the currently checked out branch in the submodule 839 test_expect_success "$command: submodule branch is not changed, detach HEAD instead" ' 840 prolog && 841 reset_work_tree_to_interested add_sub1 && 842 ( 843 cd submodule_update && 844 git -C sub1 checkout -b keep_branch && 845 git -C sub1 rev-parse HEAD >expect && 846 git branch -t modify_sub1 origin/modify_sub1 && 847 $command modify_sub1 && 848 test_superproject_content origin/modify_sub1 && 849 test_submodule_content sub1 origin/modify_sub1 && 850 git -C sub1 rev-parse keep_branch >actual && 851 test_cmp expect actual && 852 test_must_fail git -C sub1 symbolic-ref HEAD 853 ) 854 ' 855} 856 857# Declares and invokes several tests that, in various situations, checks that 858# the provided Git command, when invoked with --recurse-submodules: 859# - succeeds in updating the worktree and index of a superproject to a target 860# commit, or fails atomically (depending on the test situation) 861# - if succeeds, the contents of submodule directories are updated 862# 863# Specify the Git command so that "git $GIT_COMMAND --recurse-submodules" 864# works. 865# 866# If the command under test is known to not work with submodules in certain 867# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests 868# below to 1. 869# 870# Use as follows: 871# 872# test_submodule_switch_recursing_with_args "$GIT_COMMAND" 873test_submodule_switch_recursing_with_args () { 874 cmd_args="$1" 875 command="git $cmd_args" 876 test_submodule_recursing_with_args_common "$command" 877 878 RESULTDS=success 879 if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1 880 then 881 RESULTDS=failure 882 fi 883 RESULTOI=success 884 if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1 885 then 886 RESULTOI=failure 887 fi 888 # Switching to a commit letting a submodule appear cannot override an 889 # untracked file. 890 test_expect_success "$command: added submodule doesn't remove untracked file with same name" ' 891 prolog && 892 reset_work_tree_to_interested no_submodule && 893 ( 894 cd submodule_update && 895 git branch -t add_sub1 origin/add_sub1 && 896 : >sub1 && 897 test_must_fail $command add_sub1 && 898 test_superproject_content origin/no_submodule && 899 test_must_be_empty sub1 900 ) 901 ' 902 # ... but an ignored file is fine. 903 test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" ' 904 test_when_finished "rm -rf submodule_update/.git/info" && 905 prolog && 906 reset_work_tree_to_interested no_submodule && 907 ( 908 cd submodule_update && 909 git branch -t add_sub1 origin/add_sub1 && 910 : >sub1 && 911 mkdir .git/info && 912 echo sub1 >.git/info/exclude && 913 $command add_sub1 && 914 test_superproject_content origin/add_sub1 && 915 test_submodule_content sub1 origin/add_sub1 916 ) 917 ' 918 919 # Replacing a submodule with files in a directory must succeeds 920 # when the submodule is clean 921 test_expect_$RESULTDS "$command: replace submodule with a directory" ' 922 prolog && 923 reset_work_tree_to_interested add_sub1 && 924 ( 925 cd submodule_update && 926 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 927 $command replace_sub1_with_directory && 928 test_superproject_content origin/replace_sub1_with_directory && 929 test_submodule_content sub1 origin/replace_sub1_with_directory 930 ) 931 ' 932 # ... absorbing a .git directory. 933 test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" ' 934 prolog && 935 reset_work_tree_to_interested add_sub1 && 936 ( 937 cd submodule_update && 938 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 939 replace_gitfile_with_git_dir sub1 && 940 rm -rf .git/modules && 941 $command replace_sub1_with_directory && 942 test_superproject_content origin/replace_sub1_with_directory && 943 test_git_directory_exists sub1 944 ) 945 ' 946 947 # ... and ignored files are ignored 948 test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" ' 949 test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" && 950 prolog && 951 reset_work_tree_to_interested add_sub1 && 952 ( 953 cd submodule_update && 954 rm -rf .git/modules/sub1/info && 955 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 956 mkdir .git/modules/sub1/info && 957 echo ignored >.git/modules/sub1/info/exclude && 958 : >sub1/ignored && 959 $command replace_sub1_with_file && 960 test_superproject_content origin/replace_sub1_with_file && 961 test -f sub1 962 ) 963 ' 964 965 test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" ' 966 prolog && 967 reset_work_tree_to_interested add_sub1 && 968 ( 969 cd submodule_update && 970 git branch -t modify_sub1 origin/modify_sub1 && 971 git -c submodule.recurse=true $cmd_args modify_sub1 && 972 test_superproject_content origin/modify_sub1 && 973 test_submodule_content sub1 origin/modify_sub1 974 ) 975 ' 976 977 test_expect_success "$command: modified submodule updates submodule recursively" ' 978 prolog && 979 reset_work_tree_to_interested add_nested_sub && 980 ( 981 cd submodule_update && 982 git branch -t modify_sub1_recursively origin/modify_sub1_recursively && 983 $command modify_sub1_recursively && 984 test_superproject_content origin/modify_sub1_recursively && 985 test_submodule_content sub1 origin/modify_sub1_recursively && 986 test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively 987 ) 988 ' 989} 990 991# Same as test_submodule_switch_recursing_with_args(), except that throwing 992# away local changes in the superproject is allowed. 993test_submodule_forced_switch_recursing_with_args () { 994 cmd_args="$1" 995 command="git $cmd_args" 996 test_submodule_recursing_with_args_common "$command" 997 998 RESULT=success 999 if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1 1000 then 1001 RESULT=failure 1002 fi 1003 # Switching to a commit letting a submodule appear does not care about 1004 # an untracked file. 1005 test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" ' 1006 prolog && 1007 reset_work_tree_to_interested no_submodule && 1008 ( 1009 cd submodule_update && 1010 git branch -t add_sub1 origin/add_sub1 && 1011 >sub1 && 1012 $command add_sub1 && 1013 test_superproject_content origin/add_sub1 && 1014 test_submodule_content sub1 origin/add_sub1 1015 ) 1016 ' 1017 1018 # Replacing a submodule with files in a directory ... 1019 test_expect_success "$command: replace submodule with a directory" ' 1020 prolog && 1021 reset_work_tree_to_interested add_sub1 && 1022 ( 1023 cd submodule_update && 1024 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 1025 $command replace_sub1_with_directory && 1026 test_superproject_content origin/replace_sub1_with_directory 1027 ) 1028 ' 1029 # ... absorbing a .git directory. 1030 test_expect_success "$command: replace submodule containing a .git directory with a directory must fail" ' 1031 prolog && 1032 reset_work_tree_to_interested add_sub1 && 1033 ( 1034 cd submodule_update && 1035 git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && 1036 replace_gitfile_with_git_dir sub1 && 1037 rm -rf .git/modules/sub1 && 1038 $command replace_sub1_with_directory && 1039 test_superproject_content origin/replace_sub1_with_directory && 1040 test_git_directory_exists sub1 1041 ) 1042 ' 1043 1044 # ... even if the submodule contains ignored files 1045 test_expect_success "$command: replace submodule with a file ignoring ignored files" ' 1046 prolog && 1047 reset_work_tree_to_interested add_sub1 && 1048 ( 1049 cd submodule_update && 1050 git branch -t replace_sub1_with_file origin/replace_sub1_with_file && 1051 : >sub1/expect && 1052 $command replace_sub1_with_file && 1053 test_superproject_content origin/replace_sub1_with_file 1054 ) 1055 ' 1056 1057 # Updating a submodule from an invalid sha1 updates 1058 test_expect_success "$command: modified submodule does update submodule work tree from invalid commit" ' 1059 prolog && 1060 reset_work_tree_to_interested invalid_sub1 && 1061 ( 1062 cd submodule_update && 1063 git branch -t valid_sub1 origin/valid_sub1 && 1064 $command valid_sub1 && 1065 test_superproject_content origin/valid_sub1 && 1066 test_submodule_content sub1 origin/valid_sub1 1067 ) 1068 ' 1069 1070 # Old versions of Git were buggy writing the .git link file 1071 # (e.g. before f8eaa0ba98b and then moving the superproject repo 1072 # whose submodules contained absolute paths) 1073 test_expect_success "$command: updating submodules fixes .git links" ' 1074 prolog && 1075 reset_work_tree_to_interested add_sub1 && 1076 ( 1077 cd submodule_update && 1078 git branch -t modify_sub1 origin/modify_sub1 && 1079 echo "gitdir: bogus/path" >sub1/.git && 1080 $command modify_sub1 && 1081 test_superproject_content origin/modify_sub1 && 1082 test_submodule_content sub1 origin/modify_sub1 1083 ) 1084 ' 1085 1086 test_expect_success "$command: changed submodule worktree is reset" ' 1087 prolog && 1088 reset_work_tree_to_interested add_sub1 && 1089 ( 1090 cd submodule_update && 1091 rm sub1/file1 && 1092 : >sub1/new_file && 1093 git -C sub1 add new_file && 1094 $command HEAD && 1095 test_path_is_file sub1/file1 && 1096 test_path_is_missing sub1/new_file 1097 ) 1098 ' 1099}