1#!/bin/sh 2 3test_description="recursive merge with directory renames" 4# includes checking of many corner cases, with a similar methodology to: 5# t6042: corner cases with renames but not criss-cross merges 6# t6036: corner cases with both renames and criss-cross merges 7# 8# The setup for all of them, pictorially, is: 9# 10# A 11# o 12# / \ 13# O o ? 14# \ / 15# o 16# B 17# 18# To help make it easier to follow the flow of tests, they have been 19# divided into sections and each test will start with a quick explanation 20# of what commits O, A, and B contain. 21# 22# Notation: 23# z/{b,c} means files z/b and z/c both exist 24# x/d_1 means file x/d exists with content d1. (Purpose of the 25# underscore notation is to differentiate different 26# files that might be renamed into each other's paths.) 27 28. ./test-lib.sh 29 30 31########################################################################### 32# SECTION 1: Basic cases we should be able to handle 33########################################################################### 34 35# Testcase 1a, Basic directory rename. 36# Commit O: z/{b,c} 37# Commit A: y/{b,c} 38# Commit B: z/{b,c,d,e/f} 39# Expected: y/{b,c,d,e/f} 40 41test_expect_success '1a-setup: Simple directory rename detection'' 42 test_create_repo 1a && 43 ( 44 cd 1a && 45 46 mkdir z && 47 echo b >z/b && 48 echo c >z/c && 49 git add z && 50 test_tick && 51 git commit -m "O" && 52 53 git branch O && 54 git branch A && 55 git branch B && 56 57 git checkout A && 58 git mv z y && 59 test_tick && 60 git commit -m "A" && 61 62 git checkout B && 63 echo d >z/d && 64 mkdir z/e && 65 echo f >z/e/f && 66 git add z/d z/e/f && 67 test_tick && 68 git commit -m "B" 69 ) 70' 71 72test_expect_failure '1a-check: Simple directory rename detection'' 73 ( 74 cd 1a && 75 76 git checkout A^0 && 77 78 git merge -s recursive B^0 && 79 80 git ls-files -s >out && 81 test_line_count = 4 out && 82 83 git rev-parse >actual \ 84 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e/f && 85 git rev-parse >expect \ 86 O:z/b O:z/c B:z/d B:z/e/f && 87 test_cmp expect actual && 88 89 git hash-object y/d >actual && 90 git rev-parse B:z/d >expect && 91 test_cmp expect actual && 92 93 test_must_fail git rev-parse HEAD:z/d && 94 test_must_fail git rev-parse HEAD:z/e/f && 95 test_path_is_missing z/d && 96 test_path_is_missing z/e/f 97 ) 98' 99 100# Testcase 1b, Merge a directory with another 101# Commit O: z/{b,c}, y/d 102# Commit A: z/{b,c,e}, y/d 103# Commit B: y/{b,c,d} 104# Expected: y/{b,c,d,e} 105 106test_expect_success '1b-setup: Merge a directory with another'' 107 test_create_repo 1b && 108 ( 109 cd 1b && 110 111 mkdir z && 112 echo b >z/b && 113 echo c >z/c && 114 mkdir y && 115 echo d >y/d && 116 git add z y && 117 test_tick && 118 git commit -m "O" && 119 120 git branch O && 121 git branch A && 122 git branch B && 123 124 git checkout A && 125 echo e >z/e && 126 git add z/e && 127 test_tick && 128 git commit -m "A" && 129 130 git checkout B && 131 git mv z/b y && 132 git mv z/c y && 133 rmdir z && 134 test_tick && 135 git commit -m "B" 136 ) 137' 138 139test_expect_failure '1b-check: Merge a directory with another'' 140 ( 141 cd 1b && 142 143 git checkout A^0 && 144 145 git merge -s recursive B^0 && 146 147 git ls-files -s >out && 148 test_line_count = 4 out && 149 150 git rev-parse >actual \ 151 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e && 152 git rev-parse >expect \ 153 O:z/b O:z/c O:y/d A:z/e && 154 test_cmp expect actual && 155 test_must_fail git rev-parse HEAD:z/e 156 ) 157' 158 159# Testcase 1c, Transitive renaming 160# (Related to testcases 3a and 6d -- when should a transitive rename apply?) 161# (Related to testcases 9c and 9d -- can transitivity repeat?) 162# Commit O: z/{b,c}, x/d 163# Commit A: y/{b,c}, x/d 164# Commit B: z/{b,c,d} 165# Expected: y/{b,c,d} (because x/d -> z/d -> y/d) 166 167test_expect_success '1c-setup: Transitive renaming'' 168 test_create_repo 1c && 169 ( 170 cd 1c && 171 172 mkdir z && 173 echo b >z/b && 174 echo c >z/c && 175 mkdir x && 176 echo d >x/d && 177 git add z x && 178 test_tick && 179 git commit -m "O" && 180 181 git branch O && 182 git branch A && 183 git branch B && 184 185 git checkout A && 186 git mv z y && 187 test_tick && 188 git commit -m "A" && 189 190 git checkout B && 191 git mv x/d z/d && 192 test_tick && 193 git commit -m "B" 194 ) 195' 196 197test_expect_failure '1c-check: Transitive renaming'' 198 ( 199 cd 1c && 200 201 git checkout A^0 && 202 203 git merge -s recursive B^0 && 204 205 git ls-files -s >out && 206 test_line_count = 3 out && 207 208 git rev-parse >actual \ 209 HEAD:y/b HEAD:y/c HEAD:y/d && 210 git rev-parse >expect \ 211 O:z/b O:z/c O:x/d && 212 test_cmp expect actual && 213 test_must_fail git rev-parse HEAD:x/d && 214 test_must_fail git rev-parse HEAD:z/d && 215 test_path_is_missing z/d 216 ) 217' 218 219# Testcase 1d, Directory renames (merging two directories into one new one) 220# cause a rename/rename(2to1) conflict 221# (Related to testcases 1c and 7b) 222# Commit O. z/{b,c}, y/{d,e} 223# Commit A. x/{b,c}, y/{d,e,m,wham_1} 224# Commit B. z/{b,c,n,wham_2}, x/{d,e} 225# Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham) 226# Note: y/m & z/n should definitely move into x. By the same token, both 227# y/wham_1 & z/wham_2 should too...giving us a conflict. 228 229test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict'' 230 test_create_repo 1d && 231 ( 232 cd 1d && 233 234 mkdir z && 235 echo b >z/b && 236 echo c >z/c && 237 mkdir y && 238 echo d >y/d && 239 echo e >y/e && 240 git add z y && 241 test_tick && 242 git commit -m "O" && 243 244 git branch O && 245 git branch A && 246 git branch B && 247 248 git checkout A && 249 git mv z x && 250 echo m >y/m && 251 echo wham1 >y/wham && 252 git add y && 253 test_tick && 254 git commit -m "A" && 255 256 git checkout B && 257 git mv y x && 258 echo n >z/n && 259 echo wham2 >z/wham && 260 git add z && 261 test_tick && 262 git commit -m "B" 263 ) 264' 265 266test_expect_failure '1d-check: Directory renames cause a rename/rename(2to1) conflict'' 267 ( 268 cd 1d && 269 270 git checkout A^0 && 271 272 test_must_fail git merge -s recursive B^0 >out && 273 test_i18ngrep "CONFLICT (rename/rename)" out && 274 275 git ls-files -s >out && 276 test_line_count = 8 out && 277 git ls-files -u >out && 278 test_line_count = 2 out && 279 git ls-files -o >out && 280 test_line_count = 3 out && 281 282 git rev-parse >actual \ 283 :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n && 284 git rev-parse >expect \ 285 O:z/b O:z/c O:y/d O:y/e A:y/m B:z/n && 286 test_cmp expect actual && 287 288 test_must_fail git rev-parse :0:x/wham && 289 git rev-parse >actual \ 290 :2:x/wham :3:x/wham && 291 git rev-parse >expect \ 292 A:y/wham B:z/wham && 293 test_cmp expect actual && 294 295 test_path_is_missing x/wham && 296 test_path_is_file x/wham~HEAD && 297 test_path_is_file x/wham~B^0 && 298 299 git hash-object >actual \ 300 x/wham~HEAD x/wham~B^0 && 301 git rev-parse >expect \ 302 A:y/wham B:z/wham && 303 test_cmp expect actual 304 ) 305' 306 307# Testcase 1e, Renamed directory, with all filenames being renamed too 308# Commit O: z/{oldb,oldc} 309# Commit A: y/{newb,newc} 310# Commit B: z/{oldb,oldc,d} 311# Expected: y/{newb,newc,d} 312 313test_expect_success '1e-setup: Renamed directory, with all files being renamed too'' 314 test_create_repo 1e && 315 ( 316 cd 1e && 317 318 mkdir z && 319 echo b >z/oldb && 320 echo c >z/oldc && 321 git add z && 322 test_tick && 323 git commit -m "O" && 324 325 git branch O && 326 git branch A && 327 git branch B && 328 329 git checkout A && 330 mkdir y && 331 git mv z/oldb y/newb && 332 git mv z/oldc y/newc && 333 test_tick && 334 git commit -m "A" && 335 336 git checkout B && 337 echo d >z/d && 338 git add z/d && 339 test_tick && 340 git commit -m "B" 341 ) 342' 343 344test_expect_failure '1e-check: Renamed directory, with all files being renamed too'' 345 ( 346 cd 1e && 347 348 git checkout A^0 && 349 350 git merge -s recursive B^0 && 351 352 git ls-files -s >out && 353 test_line_count = 3 out && 354 355 git rev-parse >actual \ 356 HEAD:y/newb HEAD:y/newc HEAD:y/d && 357 git rev-parse >expect \ 358 O:z/oldb O:z/oldc B:z/d && 359 test_cmp expect actual && 360 test_must_fail git rev-parse HEAD:z/d 361 ) 362' 363 364# Testcase 1f, Split a directory into two other directories 365# (Related to testcases 3a, all of section 2, and all of section 4) 366# Commit O: z/{b,c,d,e,f} 367# Commit A: z/{b,c,d,e,f,g} 368# Commit B: y/{b,c}, x/{d,e,f} 369# Expected: y/{b,c}, x/{d,e,f,g} 370 371test_expect_success '1f-setup: Split a directory into two other directories'' 372 test_create_repo 1f && 373 ( 374 cd 1f && 375 376 mkdir z && 377 echo b >z/b && 378 echo c >z/c && 379 echo d >z/d && 380 echo e >z/e && 381 echo f >z/f && 382 git add z && 383 test_tick && 384 git commit -m "O" && 385 386 git branch O && 387 git branch A && 388 git branch B && 389 390 git checkout A && 391 echo g >z/g && 392 git add z/g && 393 test_tick && 394 git commit -m "A" && 395 396 git checkout B && 397 mkdir y && 398 mkdir x && 399 git mv z/b y/ && 400 git mv z/c y/ && 401 git mv z/d x/ && 402 git mv z/e x/ && 403 git mv z/f x/ && 404 rmdir z && 405 test_tick && 406 git commit -m "B" 407 ) 408' 409 410test_expect_failure '1f-check: Split a directory into two other directories'' 411 ( 412 cd 1f && 413 414 git checkout A^0 && 415 416 git merge -s recursive B^0 && 417 418 git ls-files -s >out && 419 test_line_count = 6 out && 420 421 git rev-parse >actual \ 422 HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g && 423 git rev-parse >expect \ 424 O:z/b O:z/c O:z/d O:z/e O:z/f A:z/g && 425 test_cmp expect actual && 426 test_path_is_missing z/g && 427 test_must_fail git rev-parse HEAD:z/g 428 ) 429' 430 431########################################################################### 432# Rules suggested by testcases in section 1: 433# 434# We should still detect the directory rename even if it wasn't just 435# the directory renamed, but the files within it. (see 1b) 436# 437# If renames split a directory into two or more others, the directory 438# with the most renames, "wins" (see 1c). However, see the testcases 439# in section 2, plus testcases 3a and 4a. 440########################################################################### 441 442 443########################################################################### 444# SECTION 2: Split into multiple directories, with equal number of paths 445# 446# Explore the splitting-a-directory rules a bit; what happens in the 447# edge cases? 448# 449# Note that there is a closely related case of a directory not being 450# split on either side of history, but being renamed differently on 451# each side. See testcase 8e for that. 452########################################################################### 453 454# Testcase 2a, Directory split into two on one side, with equal numbers of paths 455# Commit O: z/{b,c} 456# Commit A: y/b, w/c 457# Commit B: z/{b,c,d} 458# Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict 459test_expect_success '2a-setup: Directory split into two on one side, with equal numbers of paths'' 460 test_create_repo 2a && 461 ( 462 cd 2a && 463 464 mkdir z && 465 echo b >z/b && 466 echo c >z/c && 467 git add z && 468 test_tick && 469 git commit -m "O" && 470 471 git branch O && 472 git branch A && 473 git branch B && 474 475 git checkout A && 476 mkdir y && 477 mkdir w && 478 git mv z/b y/ && 479 git mv z/c w/ && 480 test_tick && 481 git commit -m "A" && 482 483 git checkout B && 484 echo d >z/d && 485 git add z/d && 486 test_tick && 487 git commit -m "B" 488 ) 489' 490 491test_expect_failure '2a-check: Directory split into two on one side, with equal numbers of paths'' 492 ( 493 cd 2a && 494 495 git checkout A^0 && 496 497 test_must_fail git merge -s recursive B^0 >out && 498 test_i18ngrep "CONFLICT.*directory rename split" out && 499 500 git ls-files -s >out && 501 test_line_count = 3 out && 502 git ls-files -u >out && 503 test_line_count = 0 out && 504 git ls-files -o >out && 505 test_line_count = 1 out && 506 507 git rev-parse >actual \ 508 :0:y/b :0:w/c :0:z/d && 509 git rev-parse >expect \ 510 O:z/b O:z/c B:z/d && 511 test_cmp expect actual 512 ) 513' 514 515# Testcase 2b, Directory split into two on one side, with equal numbers of paths 516# Commit O: z/{b,c} 517# Commit A: y/b, w/c 518# Commit B: z/{b,c}, x/d 519# Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict 520test_expect_success '2b-setup: Directory split into two on one side, with equal numbers of paths'' 521 test_create_repo 2b && 522 ( 523 cd 2b && 524 525 mkdir z && 526 echo b >z/b && 527 echo c >z/c && 528 git add z && 529 test_tick && 530 git commit -m "O" && 531 532 git branch O && 533 git branch A && 534 git branch B && 535 536 git checkout A && 537 mkdir y && 538 mkdir w && 539 git mv z/b y/ && 540 git mv z/c w/ && 541 test_tick && 542 git commit -m "A" && 543 544 git checkout B && 545 mkdir x && 546 echo d >x/d && 547 git add x/d && 548 test_tick && 549 git commit -m "B" 550 ) 551' 552 553test_expect_success '2b-check: Directory split into two on one side, with equal numbers of paths'' 554 ( 555 cd 2b && 556 557 git checkout A^0 && 558 559 git merge -s recursive B^0 >out && 560 561 git ls-files -s >out && 562 test_line_count = 3 out && 563 git ls-files -u >out && 564 test_line_count = 0 out && 565 git ls-files -o >out && 566 test_line_count = 1 out && 567 568 git rev-parse >actual \ 569 :0:y/b :0:w/c :0:x/d && 570 git rev-parse >expect \ 571 O:z/b O:z/c B:x/d && 572 test_cmp expect actual && 573 test_i18ngrep ! "CONFLICT.*directory rename split" out 574 ) 575' 576 577########################################################################### 578# Rules suggested by section 2: 579# 580# None; the rule was already covered in section 1. These testcases are 581# here just to make sure the conflict resolution and necessary warning 582# messages are handled correctly. 583########################################################################### 584 585 586########################################################################### 587# SECTION 3: Path in question is the source path for some rename already 588# 589# Combining cases from Section 1 and trying to handle them could lead to 590# directory renaming detection being over-applied. So, this section 591# provides some good testcases to check that the implementation doesn't go 592# too far. 593########################################################################### 594 595# Testcase 3a, Avoid implicit rename if involved as source on other side 596# (Related to testcases 1c and 1f) 597# Commit O: z/{b,c,d} 598# Commit A: z/{b,c,d} (no change) 599# Commit B: y/{b,c}, x/d 600# Expected: y/{b,c}, x/d 601test_expect_success '3a-setup: Avoid implicit rename if involved as source on other side'' 602 test_create_repo 3a && 603 ( 604 cd 3a && 605 606 mkdir z && 607 echo b >z/b && 608 echo c >z/c && 609 echo d >z/d && 610 git add z && 611 test_tick && 612 git commit -m "O" && 613 614 git branch O && 615 git branch A && 616 git branch B && 617 618 git checkout A && 619 test_tick && 620 git commit --allow-empty -m "A" && 621 622 git checkout B && 623 mkdir y && 624 mkdir x && 625 git mv z/b y/ && 626 git mv z/c y/ && 627 git mv z/d x/ && 628 rmdir z && 629 test_tick && 630 git commit -m "B" 631 ) 632' 633 634test_expect_success '3a-check: Avoid implicit rename if involved as source on other side'' 635 ( 636 cd 3a && 637 638 git checkout A^0 && 639 640 git merge -s recursive B^0 && 641 642 git ls-files -s >out && 643 test_line_count = 3 out && 644 645 git rev-parse >actual \ 646 HEAD:y/b HEAD:y/c HEAD:x/d && 647 git rev-parse >expect \ 648 O:z/b O:z/c O:z/d && 649 test_cmp expect actual 650 ) 651' 652 653# Testcase 3b, Avoid implicit rename if involved as source on other side 654# (Related to testcases 5c and 7c, also kind of 1e and 1f) 655# Commit O: z/{b,c,d} 656# Commit A: y/{b,c}, x/d 657# Commit B: z/{b,c}, w/d 658# Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d) 659# NOTE: We're particularly checking that since z/d is already involved as 660# a source in a file rename on the same side of history, that we don't 661# get it involved in directory rename detection. If it were, we might 662# end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a 663# rename/rename/rename(1to3) conflict, which is just weird. 664test_expect_success '3b-setup: Avoid implicit rename if involved as source on current side'' 665 test_create_repo 3b && 666 ( 667 cd 3b && 668 669 mkdir z && 670 echo b >z/b && 671 echo c >z/c && 672 echo d >z/d && 673 git add z && 674 test_tick && 675 git commit -m "O" && 676 677 git branch O && 678 git branch A && 679 git branch B && 680 681 git checkout A && 682 mkdir y && 683 mkdir x && 684 git mv z/b y/ && 685 git mv z/c y/ && 686 git mv z/d x/ && 687 rmdir z && 688 test_tick && 689 git commit -m "A" && 690 691 git checkout B && 692 mkdir w && 693 git mv z/d w/ && 694 test_tick && 695 git commit -m "B" 696 ) 697' 698 699test_expect_success '3b-check: Avoid implicit rename if involved as source on current side'' 700 ( 701 cd 3b && 702 703 git checkout A^0 && 704 705 test_must_fail git merge -s recursive B^0 >out && 706 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out && 707 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out && 708 709 git ls-files -s >out && 710 test_line_count = 5 out && 711 git ls-files -u >out && 712 test_line_count = 3 out && 713 git ls-files -o >out && 714 test_line_count = 1 out && 715 716 git rev-parse >actual \ 717 :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d && 718 git rev-parse >expect \ 719 O:z/b O:z/c O:z/d O:z/d O:z/d && 720 test_cmp expect actual && 721 722 test_path_is_missing z/d && 723 git hash-object >actual \ 724 x/d w/d && 725 git rev-parse >expect \ 726 O:z/d O:z/d && 727 test_cmp expect actual 728 ) 729' 730 731########################################################################### 732# Rules suggested by section 3: 733# 734# Avoid directory-rename-detection for a path, if that path is the source 735# of a rename on either side of a merge. 736########################################################################### 737 738 739########################################################################### 740# SECTION 4: Partially renamed directory; still exists on both sides of merge 741# 742# What if we were to attempt to do directory rename detection when someone 743# "mostly" moved a directory but still left some files around, or, 744# equivalently, fully renamed a directory in one commmit and then recreated 745# that directory in a later commit adding some new files and then tried to 746# merge? 747# 748# It's hard to divine user intent in these cases, because you can make an 749# argument that, depending on the intermediate history of the side being 750# merged, that some users will want files in that directory to 751# automatically be detected and renamed, while users with a different 752# intermediate history wouldn't want that rename to happen. 753# 754# I think that it is best to simply not have directory rename detection 755# apply to such cases. My reasoning for this is four-fold: (1) it's 756# easiest for users in general to figure out what happened if we don't 757# apply directory rename detection in any such case, (2) it's an easy rule 758# to explain ["We don't do directory rename detection if the directory 759# still exists on both sides of the merge"], (3) we can get some hairy 760# edge/corner cases that would be really confusing and possibly not even 761# representable in the index if we were to even try, and [related to 3] (4) 762# attempting to resolve this issue of divining user intent by examining 763# intermediate history goes against the spirit of three-way merges and is a 764# path towards crazy corner cases that are far more complex than what we're 765# already dealing with. 766# 767# Note that the wording of the rule ("We don't do directory rename 768# detection if the directory still exists on both sides of the merge.") 769# also excludes "renaming" of a directory into a subdirectory of itself 770# (e.g. /some/dir/* -> /some/dir/subdir/*). It may be possible to carve 771# out an exception for "renaming"-beneath-itself cases without opening 772# weird edge/corner cases for other partial directory renames, but for now 773# we are keeping the rule simple. 774# 775# This section contains a test for a partially-renamed-directory case. 776########################################################################### 777 778# Testcase 4a, Directory split, with original directory still present 779# (Related to testcase 1f) 780# Commit O: z/{b,c,d,e} 781# Commit A: y/{b,c,d}, z/e 782# Commit B: z/{b,c,d,e,f} 783# Expected: y/{b,c,d}, z/{e,f} 784# NOTE: Even though most files from z moved to y, we don't want f to follow. 785 786test_expect_success '4a-setup: Directory split, with original directory still present'' 787 test_create_repo 4a && 788 ( 789 cd 4a && 790 791 mkdir z && 792 echo b >z/b && 793 echo c >z/c && 794 echo d >z/d && 795 echo e >z/e && 796 git add z && 797 test_tick && 798 git commit -m "O" && 799 800 git branch O && 801 git branch A && 802 git branch B && 803 804 git checkout A && 805 mkdir y && 806 git mv z/b y/ && 807 git mv z/c y/ && 808 git mv z/d y/ && 809 test_tick && 810 git commit -m "A" && 811 812 git checkout B && 813 echo f >z/f && 814 git add z/f && 815 test_tick && 816 git commit -m "B" 817 ) 818' 819 820test_expect_success '4a-check: Directory split, with original directory still present'' 821 ( 822 cd 4a && 823 824 git checkout A^0 && 825 826 git merge -s recursive B^0 && 827 828 git ls-files -s >out && 829 test_line_count = 5 out && 830 git ls-files -u >out && 831 test_line_count = 0 out && 832 git ls-files -o >out && 833 test_line_count = 1 out && 834 835 git rev-parse >actual \ 836 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f && 837 git rev-parse >expect \ 838 O:z/b O:z/c O:z/d O:z/e B:z/f && 839 test_cmp expect actual 840 ) 841' 842 843########################################################################### 844# Rules suggested by section 4: 845# 846# Directory-rename-detection should be turned off for any directories (as 847# a source for renames) that exist on both sides of the merge. (The "as 848# a source for renames" clarification is due to cases like 1c where 849# the target directory exists on both sides and we do want the rename 850# detection.) But, sadly, see testcase 8b. 851########################################################################### 852 853test_done