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_success '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_success '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# (Related to testcase 12b -- joint-transitivity?) 163# Commit O: z/{b,c}, x/d 164# Commit A: y/{b,c}, x/d 165# Commit B: z/{b,c,d} 166# Expected: y/{b,c,d} (because x/d -> z/d -> y/d) 167 168test_expect_success '1c-setup: Transitive renaming'' 169 test_create_repo 1c && 170 ( 171 cd 1c && 172 173 mkdir z && 174 echo b >z/b && 175 echo c >z/c && 176 mkdir x && 177 echo d >x/d && 178 git add z x && 179 test_tick && 180 git commit -m "O" && 181 182 git branch O && 183 git branch A && 184 git branch B && 185 186 git checkout A && 187 git mv z y && 188 test_tick && 189 git commit -m "A" && 190 191 git checkout B && 192 git mv x/d z/d && 193 test_tick && 194 git commit -m "B" 195 ) 196' 197 198test_expect_success '1c-check: Transitive renaming'' 199 ( 200 cd 1c && 201 202 git checkout A^0 && 203 204 git merge -s recursive B^0 && 205 206 git ls-files -s >out && 207 test_line_count = 3 out && 208 209 git rev-parse >actual \ 210 HEAD:y/b HEAD:y/c HEAD:y/d && 211 git rev-parse >expect \ 212 O:z/b O:z/c O:x/d && 213 test_cmp expect actual && 214 test_must_fail git rev-parse HEAD:x/d && 215 test_must_fail git rev-parse HEAD:z/d && 216 test_path_is_missing z/d 217 ) 218' 219 220# Testcase 1d, Directory renames (merging two directories into one new one) 221# cause a rename/rename(2to1) conflict 222# (Related to testcases 1c and 7b) 223# Commit O. z/{b,c}, y/{d,e} 224# Commit A. x/{b,c}, y/{d,e,m,wham_1} 225# Commit B. z/{b,c,n,wham_2}, x/{d,e} 226# Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham) 227# Note: y/m & z/n should definitely move into x. By the same token, both 228# y/wham_1 & z/wham_2 should too...giving us a conflict. 229 230test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict'' 231 test_create_repo 1d && 232 ( 233 cd 1d && 234 235 mkdir z && 236 echo b >z/b && 237 echo c >z/c && 238 mkdir y && 239 echo d >y/d && 240 echo e >y/e && 241 git add z y && 242 test_tick && 243 git commit -m "O" && 244 245 git branch O && 246 git branch A && 247 git branch B && 248 249 git checkout A && 250 git mv z x && 251 echo m >y/m && 252 echo wham1 >y/wham && 253 git add y && 254 test_tick && 255 git commit -m "A" && 256 257 git checkout B && 258 git mv y x && 259 echo n >z/n && 260 echo wham2 >z/wham && 261 git add z && 262 test_tick && 263 git commit -m "B" 264 ) 265' 266 267test_expect_success '1d-check: Directory renames cause a rename/rename(2to1) conflict'' 268 ( 269 cd 1d && 270 271 git checkout A^0 && 272 273 test_must_fail git merge -s recursive B^0 >out && 274 test_i18ngrep "CONFLICT (rename/rename)" out && 275 276 git ls-files -s >out && 277 test_line_count = 8 out && 278 git ls-files -u >out && 279 test_line_count = 2 out && 280 git ls-files -o >out && 281 test_line_count = 3 out && 282 283 git rev-parse >actual \ 284 :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n && 285 git rev-parse >expect \ 286 O:z/b O:z/c O:y/d O:y/e A:y/m B:z/n && 287 test_cmp expect actual && 288 289 test_must_fail git rev-parse :0:x/wham && 290 git rev-parse >actual \ 291 :2:x/wham :3:x/wham && 292 git rev-parse >expect \ 293 A:y/wham B:z/wham && 294 test_cmp expect actual && 295 296 test_path_is_missing x/wham && 297 test_path_is_file x/wham~HEAD && 298 test_path_is_file x/wham~B^0 && 299 300 git hash-object >actual \ 301 x/wham~HEAD x/wham~B^0 && 302 git rev-parse >expect \ 303 A:y/wham B:z/wham && 304 test_cmp expect actual 305 ) 306' 307 308# Testcase 1e, Renamed directory, with all filenames being renamed too 309# (Related to testcases 9f & 9g) 310# Commit O: z/{oldb,oldc} 311# Commit A: y/{newb,newc} 312# Commit B: z/{oldb,oldc,d} 313# Expected: y/{newb,newc,d} 314 315test_expect_success '1e-setup: Renamed directory, with all files being renamed too'' 316 test_create_repo 1e && 317 ( 318 cd 1e && 319 320 mkdir z && 321 echo b >z/oldb && 322 echo c >z/oldc && 323 git add z && 324 test_tick && 325 git commit -m "O" && 326 327 git branch O && 328 git branch A && 329 git branch B && 330 331 git checkout A && 332 mkdir y && 333 git mv z/oldb y/newb && 334 git mv z/oldc y/newc && 335 test_tick && 336 git commit -m "A" && 337 338 git checkout B && 339 echo d >z/d && 340 git add z/d && 341 test_tick && 342 git commit -m "B" 343 ) 344' 345 346test_expect_success '1e-check: Renamed directory, with all files being renamed too'' 347 ( 348 cd 1e && 349 350 git checkout A^0 && 351 352 git merge -s recursive B^0 && 353 354 git ls-files -s >out && 355 test_line_count = 3 out && 356 357 git rev-parse >actual \ 358 HEAD:y/newb HEAD:y/newc HEAD:y/d && 359 git rev-parse >expect \ 360 O:z/oldb O:z/oldc B:z/d && 361 test_cmp expect actual && 362 test_must_fail git rev-parse HEAD:z/d 363 ) 364' 365 366# Testcase 1f, Split a directory into two other directories 367# (Related to testcases 3a, all of section 2, and all of section 4) 368# Commit O: z/{b,c,d,e,f} 369# Commit A: z/{b,c,d,e,f,g} 370# Commit B: y/{b,c}, x/{d,e,f} 371# Expected: y/{b,c}, x/{d,e,f,g} 372 373test_expect_success '1f-setup: Split a directory into two other directories'' 374 test_create_repo 1f && 375 ( 376 cd 1f && 377 378 mkdir z && 379 echo b >z/b && 380 echo c >z/c && 381 echo d >z/d && 382 echo e >z/e && 383 echo f >z/f && 384 git add z && 385 test_tick && 386 git commit -m "O" && 387 388 git branch O && 389 git branch A && 390 git branch B && 391 392 git checkout A && 393 echo g >z/g && 394 git add z/g && 395 test_tick && 396 git commit -m "A" && 397 398 git checkout B && 399 mkdir y && 400 mkdir x && 401 git mv z/b y/ && 402 git mv z/c y/ && 403 git mv z/d x/ && 404 git mv z/e x/ && 405 git mv z/f x/ && 406 rmdir z && 407 test_tick && 408 git commit -m "B" 409 ) 410' 411 412test_expect_success '1f-check: Split a directory into two other directories'' 413 ( 414 cd 1f && 415 416 git checkout A^0 && 417 418 git merge -s recursive B^0 && 419 420 git ls-files -s >out && 421 test_line_count = 6 out && 422 423 git rev-parse >actual \ 424 HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g && 425 git rev-parse >expect \ 426 O:z/b O:z/c O:z/d O:z/e O:z/f A:z/g && 427 test_cmp expect actual && 428 test_path_is_missing z/g && 429 test_must_fail git rev-parse HEAD:z/g 430 ) 431' 432 433########################################################################### 434# Rules suggested by testcases in section 1: 435# 436# We should still detect the directory rename even if it wasn't just 437# the directory renamed, but the files within it. (see 1b) 438# 439# If renames split a directory into two or more others, the directory 440# with the most renames, "wins" (see 1c). However, see the testcases 441# in section 2, plus testcases 3a and 4a. 442########################################################################### 443 444 445########################################################################### 446# SECTION 2: Split into multiple directories, with equal number of paths 447# 448# Explore the splitting-a-directory rules a bit; what happens in the 449# edge cases? 450# 451# Note that there is a closely related case of a directory not being 452# split on either side of history, but being renamed differently on 453# each side. See testcase 8e for that. 454########################################################################### 455 456# Testcase 2a, Directory split into two on one side, with equal numbers of paths 457# Commit O: z/{b,c} 458# Commit A: y/b, w/c 459# Commit B: z/{b,c,d} 460# Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict 461test_expect_success '2a-setup: Directory split into two on one side, with equal numbers of paths'' 462 test_create_repo 2a && 463 ( 464 cd 2a && 465 466 mkdir z && 467 echo b >z/b && 468 echo c >z/c && 469 git add z && 470 test_tick && 471 git commit -m "O" && 472 473 git branch O && 474 git branch A && 475 git branch B && 476 477 git checkout A && 478 mkdir y && 479 mkdir w && 480 git mv z/b y/ && 481 git mv z/c w/ && 482 test_tick && 483 git commit -m "A" && 484 485 git checkout B && 486 echo d >z/d && 487 git add z/d && 488 test_tick && 489 git commit -m "B" 490 ) 491' 492 493test_expect_success '2a-check: Directory split into two on one side, with equal numbers of paths'' 494 ( 495 cd 2a && 496 497 git checkout A^0 && 498 499 test_must_fail git merge -s recursive B^0 >out && 500 test_i18ngrep "CONFLICT.*directory rename split" out && 501 502 git ls-files -s >out && 503 test_line_count = 3 out && 504 git ls-files -u >out && 505 test_line_count = 0 out && 506 git ls-files -o >out && 507 test_line_count = 1 out && 508 509 git rev-parse >actual \ 510 :0:y/b :0:w/c :0:z/d && 511 git rev-parse >expect \ 512 O:z/b O:z/c B:z/d && 513 test_cmp expect actual 514 ) 515' 516 517# Testcase 2b, Directory split into two on one side, with equal numbers of paths 518# Commit O: z/{b,c} 519# Commit A: y/b, w/c 520# Commit B: z/{b,c}, x/d 521# Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict 522test_expect_success '2b-setup: Directory split into two on one side, with equal numbers of paths'' 523 test_create_repo 2b && 524 ( 525 cd 2b && 526 527 mkdir z && 528 echo b >z/b && 529 echo c >z/c && 530 git add z && 531 test_tick && 532 git commit -m "O" && 533 534 git branch O && 535 git branch A && 536 git branch B && 537 538 git checkout A && 539 mkdir y && 540 mkdir w && 541 git mv z/b y/ && 542 git mv z/c w/ && 543 test_tick && 544 git commit -m "A" && 545 546 git checkout B && 547 mkdir x && 548 echo d >x/d && 549 git add x/d && 550 test_tick && 551 git commit -m "B" 552 ) 553' 554 555test_expect_success '2b-check: Directory split into two on one side, with equal numbers of paths'' 556 ( 557 cd 2b && 558 559 git checkout A^0 && 560 561 git merge -s recursive B^0 >out && 562 563 git ls-files -s >out && 564 test_line_count = 3 out && 565 git ls-files -u >out && 566 test_line_count = 0 out && 567 git ls-files -o >out && 568 test_line_count = 1 out && 569 570 git rev-parse >actual \ 571 :0:y/b :0:w/c :0:x/d && 572 git rev-parse >expect \ 573 O:z/b O:z/c B:x/d && 574 test_cmp expect actual && 575 test_i18ngrep ! "CONFLICT.*directory rename split" out 576 ) 577' 578 579########################################################################### 580# Rules suggested by section 2: 581# 582# None; the rule was already covered in section 1. These testcases are 583# here just to make sure the conflict resolution and necessary warning 584# messages are handled correctly. 585########################################################################### 586 587 588########################################################################### 589# SECTION 3: Path in question is the source path for some rename already 590# 591# Combining cases from Section 1 and trying to handle them could lead to 592# directory renaming detection being over-applied. So, this section 593# provides some good testcases to check that the implementation doesn't go 594# too far. 595########################################################################### 596 597# Testcase 3a, Avoid implicit rename if involved as source on other side 598# (Related to testcases 1c, 1f, and 9h) 599# Commit O: z/{b,c,d} 600# Commit A: z/{b,c,d} (no change) 601# Commit B: y/{b,c}, x/d 602# Expected: y/{b,c}, x/d 603test_expect_success '3a-setup: Avoid implicit rename if involved as source on other side'' 604 test_create_repo 3a && 605 ( 606 cd 3a && 607 608 mkdir z && 609 echo b >z/b && 610 echo c >z/c && 611 echo d >z/d && 612 git add z && 613 test_tick && 614 git commit -m "O" && 615 616 git branch O && 617 git branch A && 618 git branch B && 619 620 git checkout A && 621 test_tick && 622 git commit --allow-empty -m "A" && 623 624 git checkout B && 625 mkdir y && 626 mkdir x && 627 git mv z/b y/ && 628 git mv z/c y/ && 629 git mv z/d x/ && 630 rmdir z && 631 test_tick && 632 git commit -m "B" 633 ) 634' 635 636test_expect_success '3a-check: Avoid implicit rename if involved as source on other side'' 637 ( 638 cd 3a && 639 640 git checkout A^0 && 641 642 git merge -s recursive B^0 && 643 644 git ls-files -s >out && 645 test_line_count = 3 out && 646 647 git rev-parse >actual \ 648 HEAD:y/b HEAD:y/c HEAD:x/d && 649 git rev-parse >expect \ 650 O:z/b O:z/c O:z/d && 651 test_cmp expect actual 652 ) 653' 654 655# Testcase 3b, Avoid implicit rename if involved as source on other side 656# (Related to testcases 5c and 7c, also kind of 1e and 1f) 657# Commit O: z/{b,c,d} 658# Commit A: y/{b,c}, x/d 659# Commit B: z/{b,c}, w/d 660# Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d) 661# NOTE: We're particularly checking that since z/d is already involved as 662# a source in a file rename on the same side of history, that we don't 663# get it involved in directory rename detection. If it were, we might 664# end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a 665# rename/rename/rename(1to3) conflict, which is just weird. 666test_expect_success '3b-setup: Avoid implicit rename if involved as source on current side'' 667 test_create_repo 3b && 668 ( 669 cd 3b && 670 671 mkdir z && 672 echo b >z/b && 673 echo c >z/c && 674 echo d >z/d && 675 git add z && 676 test_tick && 677 git commit -m "O" && 678 679 git branch O && 680 git branch A && 681 git branch B && 682 683 git checkout A && 684 mkdir y && 685 mkdir x && 686 git mv z/b y/ && 687 git mv z/c y/ && 688 git mv z/d x/ && 689 rmdir z && 690 test_tick && 691 git commit -m "A" && 692 693 git checkout B && 694 mkdir w && 695 git mv z/d w/ && 696 test_tick && 697 git commit -m "B" 698 ) 699' 700 701test_expect_success '3b-check: Avoid implicit rename if involved as source on current side'' 702 ( 703 cd 3b && 704 705 git checkout A^0 && 706 707 test_must_fail git merge -s recursive B^0 >out && 708 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out && 709 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out && 710 711 git ls-files -s >out && 712 test_line_count = 5 out && 713 git ls-files -u >out && 714 test_line_count = 3 out && 715 git ls-files -o >out && 716 test_line_count = 1 out && 717 718 git rev-parse >actual \ 719 :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d && 720 git rev-parse >expect \ 721 O:z/b O:z/c O:z/d O:z/d O:z/d && 722 test_cmp expect actual && 723 724 test_path_is_missing z/d && 725 git hash-object >actual \ 726 x/d w/d && 727 git rev-parse >expect \ 728 O:z/d O:z/d && 729 test_cmp expect actual 730 ) 731' 732 733########################################################################### 734# Rules suggested by section 3: 735# 736# Avoid directory-rename-detection for a path, if that path is the source 737# of a rename on either side of a merge. 738########################################################################### 739 740 741########################################################################### 742# SECTION 4: Partially renamed directory; still exists on both sides of merge 743# 744# What if we were to attempt to do directory rename detection when someone 745# "mostly" moved a directory but still left some files around, or, 746# equivalently, fully renamed a directory in one commmit and then recreated 747# that directory in a later commit adding some new files and then tried to 748# merge? 749# 750# It's hard to divine user intent in these cases, because you can make an 751# argument that, depending on the intermediate history of the side being 752# merged, that some users will want files in that directory to 753# automatically be detected and renamed, while users with a different 754# intermediate history wouldn't want that rename to happen. 755# 756# I think that it is best to simply not have directory rename detection 757# apply to such cases. My reasoning for this is four-fold: (1) it's 758# easiest for users in general to figure out what happened if we don't 759# apply directory rename detection in any such case, (2) it's an easy rule 760# to explain ["We don't do directory rename detection if the directory 761# still exists on both sides of the merge"], (3) we can get some hairy 762# edge/corner cases that would be really confusing and possibly not even 763# representable in the index if we were to even try, and [related to 3] (4) 764# attempting to resolve this issue of divining user intent by examining 765# intermediate history goes against the spirit of three-way merges and is a 766# path towards crazy corner cases that are far more complex than what we're 767# already dealing with. 768# 769# Note that the wording of the rule ("We don't do directory rename 770# detection if the directory still exists on both sides of the merge.") 771# also excludes "renaming" of a directory into a subdirectory of itself 772# (e.g. /some/dir/* -> /some/dir/subdir/*). It may be possible to carve 773# out an exception for "renaming"-beneath-itself cases without opening 774# weird edge/corner cases for other partial directory renames, but for now 775# we are keeping the rule simple. 776# 777# This section contains a test for a partially-renamed-directory case. 778########################################################################### 779 780# Testcase 4a, Directory split, with original directory still present 781# (Related to testcase 1f) 782# Commit O: z/{b,c,d,e} 783# Commit A: y/{b,c,d}, z/e 784# Commit B: z/{b,c,d,e,f} 785# Expected: y/{b,c,d}, z/{e,f} 786# NOTE: Even though most files from z moved to y, we don't want f to follow. 787 788test_expect_success '4a-setup: Directory split, with original directory still present'' 789 test_create_repo 4a && 790 ( 791 cd 4a && 792 793 mkdir z && 794 echo b >z/b && 795 echo c >z/c && 796 echo d >z/d && 797 echo e >z/e && 798 git add z && 799 test_tick && 800 git commit -m "O" && 801 802 git branch O && 803 git branch A && 804 git branch B && 805 806 git checkout A && 807 mkdir y && 808 git mv z/b y/ && 809 git mv z/c y/ && 810 git mv z/d y/ && 811 test_tick && 812 git commit -m "A" && 813 814 git checkout B && 815 echo f >z/f && 816 git add z/f && 817 test_tick && 818 git commit -m "B" 819 ) 820' 821 822test_expect_success '4a-check: Directory split, with original directory still present'' 823 ( 824 cd 4a && 825 826 git checkout A^0 && 827 828 git merge -s recursive B^0 && 829 830 git ls-files -s >out && 831 test_line_count = 5 out && 832 git ls-files -u >out && 833 test_line_count = 0 out && 834 git ls-files -o >out && 835 test_line_count = 1 out && 836 837 git rev-parse >actual \ 838 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f && 839 git rev-parse >expect \ 840 O:z/b O:z/c O:z/d O:z/e B:z/f && 841 test_cmp expect actual 842 ) 843' 844 845########################################################################### 846# Rules suggested by section 4: 847# 848# Directory-rename-detection should be turned off for any directories (as 849# a source for renames) that exist on both sides of the merge. (The "as 850# a source for renames" clarification is due to cases like 1c where 851# the target directory exists on both sides and we do want the rename 852# detection.) But, sadly, see testcase 8b. 853########################################################################### 854 855 856########################################################################### 857# SECTION 5: Files/directories in the way of subset of to-be-renamed paths 858# 859# Implicitly renaming files due to a detected directory rename could run 860# into problems if there are files or directories in the way of the paths 861# we want to rename. Explore such cases in this section. 862########################################################################### 863 864# Testcase 5a, Merge directories, other side adds files to original and target 865# Commit O: z/{b,c}, y/d 866# Commit A: z/{b,c,e_1,f}, y/{d,e_2} 867# Commit B: y/{b,c,d} 868# Expected: z/e_1, y/{b,c,d,e_2,f} + CONFLICT warning 869# NOTE: While directory rename detection is active here causing z/f to 870# become y/f, we did not apply this for z/e_1 because that would 871# give us an add/add conflict for y/e_1 vs y/e_2. This problem with 872# this add/add, is that both versions of y/e are from the same side 873# of history, giving us no way to represent this conflict in the 874# index. 875 876test_expect_success '5a-setup: Merge directories, other side adds files to original and target'' 877 test_create_repo 5a && 878 ( 879 cd 5a && 880 881 mkdir z && 882 echo b >z/b && 883 echo c >z/c && 884 mkdir y && 885 echo d >y/d && 886 git add z y && 887 test_tick && 888 git commit -m "O" && 889 890 git branch O && 891 git branch A && 892 git branch B && 893 894 git checkout A && 895 echo e1 >z/e && 896 echo f >z/f && 897 echo e2 >y/e && 898 git add z/e z/f y/e && 899 test_tick && 900 git commit -m "A" && 901 902 git checkout B && 903 git mv z/b y/ && 904 git mv z/c y/ && 905 rmdir z && 906 test_tick && 907 git commit -m "B" 908 ) 909' 910 911test_expect_success '5a-check: Merge directories, other side adds files to original and target'' 912 ( 913 cd 5a && 914 915 git checkout A^0 && 916 917 test_must_fail git merge -s recursive B^0 >out && 918 test_i18ngrep "CONFLICT.*implicit dir rename" out && 919 920 git ls-files -s >out && 921 test_line_count = 6 out && 922 git ls-files -u >out && 923 test_line_count = 0 out && 924 git ls-files -o >out && 925 test_line_count = 1 out && 926 927 git rev-parse >actual \ 928 :0:y/b :0:y/c :0:y/d :0:y/e :0:z/e :0:y/f && 929 git rev-parse >expect \ 930 O:z/b O:z/c O:y/d A:y/e A:z/e A:z/f && 931 test_cmp expect actual 932 ) 933' 934 935# Testcase 5b, Rename/delete in order to get add/add/add conflict 936# (Related to testcase 8d; these may appear slightly inconsistent to users; 937# Also related to testcases 7d and 7e) 938# Commit O: z/{b,c,d_1} 939# Commit A: y/{b,c,d_2} 940# Commit B: z/{b,c,d_1,e}, y/d_3 941# Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3) 942# NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as 943# we normaly would since z/ is being renamed to y/, then this would be 944# a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add 945# conflict of y/d_1 vs. y/d_2 vs. y/d_3. Add/add/add is not 946# representable in the index, so the existence of y/d_3 needs to 947# cause us to bail on directory rename detection for that path, falling 948# back to git behavior without the directory rename detection. 949 950test_expect_success '5b-setup: Rename/delete in order to get add/add/add conflict'' 951 test_create_repo 5b && 952 ( 953 cd 5b && 954 955 mkdir z && 956 echo b >z/b && 957 echo c >z/c && 958 echo d1 >z/d && 959 git add z && 960 test_tick && 961 git commit -m "O" && 962 963 git branch O && 964 git branch A && 965 git branch B && 966 967 git checkout A && 968 git rm z/d && 969 git mv z y && 970 echo d2 >y/d && 971 git add y/d && 972 test_tick && 973 git commit -m "A" && 974 975 git checkout B && 976 mkdir y && 977 echo d3 >y/d && 978 echo e >z/e && 979 git add y/d z/e && 980 test_tick && 981 git commit -m "B" 982 ) 983' 984 985test_expect_success '5b-check: Rename/delete in order to get add/add/add conflict'' 986 ( 987 cd 5b && 988 989 git checkout A^0 && 990 991 test_must_fail git merge -s recursive B^0 >out && 992 test_i18ngrep "CONFLICT (add/add).* y/d" out && 993 994 git ls-files -s >out && 995 test_line_count = 5 out && 996 git ls-files -u >out && 997 test_line_count = 2 out && 998 git ls-files -o >out && 999 test_line_count = 1 out &&10001001 git rev-parse >actual \1002 :0:y/b :0:y/c :0:y/e :2:y/d :3:y/d &&1003 git rev-parse >expect \1004 O:z/b O:z/c B:z/e A:y/d B:y/d &&1005 test_cmp expect actual &&10061007 test_must_fail git rev-parse :1:y/d &&1008 test_path_is_file y/d1009 )1010'10111012# Testcase 5c, Transitive rename would cause rename/rename/rename/add/add/add1013# (Directory rename detection would result in transitive rename vs.1014# rename/rename(1to2) and turn it into a rename/rename(1to3). Further,1015# rename paths conflict with separate adds on the other side)1016# (Related to testcases 3b and 7c)1017# Commit O: z/{b,c}, x/d_11018# Commit A: y/{b,c,d_2}, w/d_11019# Commit B: z/{b,c,d_1,e}, w/d_3, y/d_41020# Expected: A mess, but only a rename/rename(1to2)/add/add mess. Use the1021# presence of y/d_4 in B to avoid doing transitive rename of1022# x/d_1 -> z/d_1 -> y/d_1, so that the only paths we have at1023# y/d are y/d_2 and y/d_4. We still do the move from z/e to y/e,1024# though, because it doesn't have anything in the way.10251026test_expect_success '5c-setup: Transitive rename would cause rename/rename/rename/add/add/add''1027 test_create_repo 5c &&1028 (1029 cd 5c &&10301031 mkdir z &&1032 echo b >z/b &&1033 echo c >z/c &&1034 mkdir x &&1035 echo d1 >x/d &&1036 git add z x &&1037 test_tick &&1038 git commit -m "O" &&10391040 git branch O &&1041 git branch A &&1042 git branch B &&10431044 git checkout A &&1045 git mv z y &&1046 echo d2 >y/d &&1047 git add y/d &&1048 git mv x w &&1049 test_tick &&1050 git commit -m "A" &&10511052 git checkout B &&1053 git mv x/d z/ &&1054 mkdir w &&1055 mkdir y &&1056 echo d3 >w/d &&1057 echo d4 >y/d &&1058 echo e >z/e &&1059 git add w/ y/ z/e &&1060 test_tick &&1061 git commit -m "B"1062 )1063'10641065test_expect_success '5c-check: Transitive rename would cause rename/rename/rename/add/add/add''1066 (1067 cd 5c &&10681069 git checkout A^0 &&10701071 test_must_fail git merge -s recursive B^0 >out &&1072 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&1073 test_i18ngrep "CONFLICT (add/add).* y/d" out &&10741075 git ls-files -s >out &&1076 test_line_count = 9 out &&1077 git ls-files -u >out &&1078 test_line_count = 6 out &&1079 git ls-files -o >out &&1080 test_line_count = 3 out &&10811082 git rev-parse >actual \1083 :0:y/b :0:y/c :0:y/e &&1084 git rev-parse >expect \1085 O:z/b O:z/c B:z/e &&1086 test_cmp expect actual &&10871088 test_must_fail git rev-parse :1:y/d &&1089 git rev-parse >actual \1090 :2:w/d :3:w/d :1:x/d :2:y/d :3:y/d :3:z/d &&1091 git rev-parse >expect \1092 O:x/d B:w/d O:x/d A:y/d B:y/d O:x/d &&1093 test_cmp expect actual &&10941095 git hash-object >actual \1096 w/d~HEAD w/d~B^0 z/d &&1097 git rev-parse >expect \1098 O:x/d B:w/d O:x/d &&1099 test_cmp expect actual &&1100 test_path_is_missing x/d &&1101 test_path_is_file y/d &&1102 grep -q "<<<<" y/d # conflict markers should be present1103 )1104'11051106# Testcase 5d, Directory/file/file conflict due to directory rename1107# Commit O: z/{b,c}1108# Commit A: y/{b,c,d_1}1109# Commit B: z/{b,c,d_2,f}, y/d/e1110# Expected: y/{b,c,d/e,f}, z/d_2, CONFLICT(file/directory), y/d_1~HEAD1111# Note: The fact that y/d/ exists in B makes us bail on directory rename1112# detection for z/d_2, but that doesn't prevent us from applying the1113# directory rename detection for z/f -> y/f.11141115test_expect_success '5d-setup: Directory/file/file conflict due to directory rename''1116 test_create_repo 5d &&1117 (1118 cd 5d &&11191120 mkdir z &&1121 echo b >z/b &&1122 echo c >z/c &&1123 git add z &&1124 test_tick &&1125 git commit -m "O" &&11261127 git branch O &&1128 git branch A &&1129 git branch B &&11301131 git checkout A &&1132 git mv z y &&1133 echo d1 >y/d &&1134 git add y/d &&1135 test_tick &&1136 git commit -m "A" &&11371138 git checkout B &&1139 mkdir -p y/d &&1140 echo e >y/d/e &&1141 echo d2 >z/d &&1142 echo f >z/f &&1143 git add y/d/e z/d z/f &&1144 test_tick &&1145 git commit -m "B"1146 )1147'11481149test_expect_success '5d-check: Directory/file/file conflict due to directory rename''1150 (1151 cd 5d &&11521153 git checkout A^0 &&11541155 test_must_fail git merge -s recursive B^0 >out &&1156 test_i18ngrep "CONFLICT (file/directory).*y/d" out &&11571158 git ls-files -s >out &&1159 test_line_count = 6 out &&1160 git ls-files -u >out &&1161 test_line_count = 1 out &&1162 git ls-files -o >out &&1163 test_line_count = 2 out &&11641165 git rev-parse >actual \1166 :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&1167 git rev-parse >expect \1168 O:z/b O:z/c B:z/d B:z/f A:y/d B:y/d/e &&1169 test_cmp expect actual &&11701171 git hash-object y/d~HEAD >actual &&1172 git rev-parse A:y/d >expect &&1173 test_cmp expect actual1174 )1175'11761177###########################################################################1178# Rules suggested by section 5:1179#1180# If a subset of to-be-renamed files have a file or directory in the way,1181# "turn off" the directory rename for those specific sub-paths, falling1182# back to old handling. But, sadly, see testcases 8a and 8b.1183###########################################################################118411851186###########################################################################1187# SECTION 6: Same side of the merge was the one that did the rename1188#1189# It may sound obvious that you only want to apply implicit directory1190# renames to directories if the _other_ side of history did the renaming.1191# If you did make an implementation that didn't explicitly enforce this1192# rule, the majority of cases that would fall under this section would1193# also be solved by following the rules from the above sections. But1194# there are still a few that stick out, so this section covers them just1195# to make sure we also get them right.1196###########################################################################11971198# Testcase 6a, Tricky rename/delete1199# Commit O: z/{b,c,d}1200# Commit A: z/b1201# Commit B: y/{b,c}, z/d1202# Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)1203# Note: We're just checking here that the rename of z/b and z/c to put1204# them under y/ doesn't accidentally catch z/d and make it look like1205# it is also involved in a rename/delete conflict.12061207test_expect_success '6a-setup: Tricky rename/delete''1208 test_create_repo 6a &&1209 (1210 cd 6a &&12111212 mkdir z &&1213 echo b >z/b &&1214 echo c >z/c &&1215 echo d >z/d &&1216 git add z &&1217 test_tick &&1218 git commit -m "O" &&12191220 git branch O &&1221 git branch A &&1222 git branch B &&12231224 git checkout A &&1225 git rm z/c &&1226 git rm z/d &&1227 test_tick &&1228 git commit -m "A" &&12291230 git checkout B &&1231 mkdir y &&1232 git mv z/b y/ &&1233 git mv z/c y/ &&1234 test_tick &&1235 git commit -m "B"1236 )1237'12381239test_expect_success '6a-check: Tricky rename/delete''1240 (1241 cd 6a &&12421243 git checkout A^0 &&12441245 test_must_fail git merge -s recursive B^0 >out &&1246 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&12471248 git ls-files -s >out &&1249 test_line_count = 2 out &&1250 git ls-files -u >out &&1251 test_line_count = 1 out &&1252 git ls-files -o >out &&1253 test_line_count = 1 out &&12541255 git rev-parse >actual \1256 :0:y/b :3:y/c &&1257 git rev-parse >expect \1258 O:z/b O:z/c &&1259 test_cmp expect actual1260 )1261'12621263# Testcase 6b, Same rename done on both sides1264# (Related to testcases 6c and 8e)1265# Commit O: z/{b,c}1266# Commit A: y/{b,c}1267# Commit B: y/{b,c}, z/d1268# Expected: y/{b,c}, z/d1269# Note: If we did directory rename detection here, we'd move z/d into y/,1270# but B did that rename and still decided to put the file into z/,1271# so we probably shouldn't apply directory rename detection for it.12721273test_expect_success '6b-setup: Same rename done on both sides''1274 test_create_repo 6b &&1275 (1276 cd 6b &&12771278 mkdir z &&1279 echo b >z/b &&1280 echo c >z/c &&1281 git add z &&1282 test_tick &&1283 git commit -m "O" &&12841285 git branch O &&1286 git branch A &&1287 git branch B &&12881289 git checkout A &&1290 git mv z y &&1291 test_tick &&1292 git commit -m "A" &&12931294 git checkout B &&1295 git mv z y &&1296 mkdir z &&1297 echo d >z/d &&1298 git add z/d &&1299 test_tick &&1300 git commit -m "B"1301 )1302'13031304test_expect_success '6b-check: Same rename done on both sides''1305 (1306 cd 6b &&13071308 git checkout A^0 &&13091310 git merge -s recursive B^0 &&13111312 git ls-files -s >out &&1313 test_line_count = 3 out &&1314 git ls-files -u >out &&1315 test_line_count = 0 out &&1316 git ls-files -o >out &&1317 test_line_count = 1 out &&13181319 git rev-parse >actual \1320 HEAD:y/b HEAD:y/c HEAD:z/d &&1321 git rev-parse >expect \1322 O:z/b O:z/c B:z/d &&1323 test_cmp expect actual1324 )1325'13261327# Testcase 6c, Rename only done on same side1328# (Related to testcases 6b and 8e)1329# Commit O: z/{b,c}1330# Commit A: z/{b,c} (no change)1331# Commit B: y/{b,c}, z/d1332# Expected: y/{b,c}, z/d1333# NOTE: Seems obvious, but just checking that the implementation doesn't1334# "accidentally detect a rename" and give us y/{b,c,d}.13351336test_expect_success '6c-setup: Rename only done on same side''1337 test_create_repo 6c &&1338 (1339 cd 6c &&13401341 mkdir z &&1342 echo b >z/b &&1343 echo c >z/c &&1344 git add z &&1345 test_tick &&1346 git commit -m "O" &&13471348 git branch O &&1349 git branch A &&1350 git branch B &&13511352 git checkout A &&1353 test_tick &&1354 git commit --allow-empty -m "A" &&13551356 git checkout B &&1357 git mv z y &&1358 mkdir z &&1359 echo d >z/d &&1360 git add z/d &&1361 test_tick &&1362 git commit -m "B"1363 )1364'13651366test_expect_success '6c-check: Rename only done on same side''1367 (1368 cd 6c &&13691370 git checkout A^0 &&13711372 git merge -s recursive B^0 &&13731374 git ls-files -s >out &&1375 test_line_count = 3 out &&1376 git ls-files -u >out &&1377 test_line_count = 0 out &&1378 git ls-files -o >out &&1379 test_line_count = 1 out &&13801381 git rev-parse >actual \1382 HEAD:y/b HEAD:y/c HEAD:z/d &&1383 git rev-parse >expect \1384 O:z/b O:z/c B:z/d &&1385 test_cmp expect actual1386 )1387'13881389# Testcase 6d, We don't always want transitive renaming1390# (Related to testcase 1c)1391# Commit O: z/{b,c}, x/d1392# Commit A: z/{b,c}, x/d (no change)1393# Commit B: y/{b,c}, z/d1394# Expected: y/{b,c}, z/d1395# NOTE: Again, this seems obvious but just checking that the implementation1396# doesn't "accidentally detect a rename" and give us y/{b,c,d}.13971398test_expect_success '6d-setup: We do not always want transitive renaming''1399 test_create_repo 6d &&1400 (1401 cd 6d &&14021403 mkdir z &&1404 echo b >z/b &&1405 echo c >z/c &&1406 mkdir x &&1407 echo d >x/d &&1408 git add z x &&1409 test_tick &&1410 git commit -m "O" &&14111412 git branch O &&1413 git branch A &&1414 git branch B &&14151416 git checkout A &&1417 test_tick &&1418 git commit --allow-empty -m "A" &&14191420 git checkout B &&1421 git mv z y &&1422 git mv x z &&1423 test_tick &&1424 git commit -m "B"1425 )1426'14271428test_expect_success '6d-check: We do not always want transitive renaming''1429 (1430 cd 6d &&14311432 git checkout A^0 &&14331434 git merge -s recursive B^0 &&14351436 git ls-files -s >out &&1437 test_line_count = 3 out &&1438 git ls-files -u >out &&1439 test_line_count = 0 out &&1440 git ls-files -o >out &&1441 test_line_count = 1 out &&14421443 git rev-parse >actual \1444 HEAD:y/b HEAD:y/c HEAD:z/d &&1445 git rev-parse >expect \1446 O:z/b O:z/c O:x/d &&1447 test_cmp expect actual1448 )1449'14501451# Testcase 6e, Add/add from one-side1452# Commit O: z/{b,c}1453# Commit A: z/{b,c} (no change)1454# Commit B: y/{b,c,d_1}, z/d_21455# Expected: y/{b,c,d_1}, z/d_21456# NOTE: Again, this seems obvious but just checking that the implementation1457# doesn't "accidentally detect a rename" and give us y/{b,c} +1458# add/add conflict on y/d_1 vs y/d_2.14591460test_expect_success '6e-setup: Add/add from one side''1461 test_create_repo 6e &&1462 (1463 cd 6e &&14641465 mkdir z &&1466 echo b >z/b &&1467 echo c >z/c &&1468 git add z &&1469 test_tick &&1470 git commit -m "O" &&14711472 git branch O &&1473 git branch A &&1474 git branch B &&14751476 git checkout A &&1477 test_tick &&1478 git commit --allow-empty -m "A" &&14791480 git checkout B &&1481 git mv z y &&1482 echo d1 > y/d &&1483 mkdir z &&1484 echo d2 > z/d &&1485 git add y/d z/d &&1486 test_tick &&1487 git commit -m "B"1488 )1489'14901491test_expect_success '6e-check: Add/add from one side''1492 (1493 cd 6e &&14941495 git checkout A^0 &&14961497 git merge -s recursive B^0 &&14981499 git ls-files -s >out &&1500 test_line_count = 4 out &&1501 git ls-files -u >out &&1502 test_line_count = 0 out &&1503 git ls-files -o >out &&1504 test_line_count = 1 out &&15051506 git rev-parse >actual \1507 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&1508 git rev-parse >expect \1509 O:z/b O:z/c B:y/d B:z/d &&1510 test_cmp expect actual1511 )1512'15131514###########################################################################1515# Rules suggested by section 6:1516#1517# Only apply implicit directory renames to directories if the other1518# side of history is the one doing the renaming.1519###########################################################################152015211522###########################################################################1523# SECTION 7: More involved Edge/Corner cases1524#1525# The ruleset we have generated in the above sections seems to provide1526# well-defined merges. But can we find edge/corner cases that either (a)1527# are harder for users to understand, or (b) have a resolution that is1528# non-intuitive or suboptimal?1529#1530# The testcases in this section dive into cases that I've tried to craft in1531# a way to find some that might be surprising to users or difficult for1532# them to understand (the next section will look at non-intuitive or1533# suboptimal merge results). Some of the testcases are similar to ones1534# from past sections, but have been simplified to try to highlight error1535# messages using a "modified" path (due to the directory rename). Are1536# users okay with these?1537#1538# In my opinion, testcases that are difficult to understand from this1539# section is due to difficulty in the testcase rather than the directory1540# renaming (similar to how t6042 and t6036 have difficult resolutions due1541# to the problem setup itself being complex). And I don't think the1542# error messages are a problem.1543#1544# On the other hand, the testcases in section 8 worry me slightly more...1545###########################################################################15461547# Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file1548# Commit O: z/{b,c}1549# Commit A: y/{b,c}1550# Commit B: w/b, x/c, z/d1551# Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)1552# NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.15531554test_expect_success '7a-setup: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file''1555 test_create_repo 7a &&1556 (1557 cd 7a &&15581559 mkdir z &&1560 echo b >z/b &&1561 echo c >z/c &&1562 git add z &&1563 test_tick &&1564 git commit -m "O" &&15651566 git branch O &&1567 git branch A &&1568 git branch B &&15691570 git checkout A &&1571 git mv z y &&1572 test_tick &&1573 git commit -m "A" &&15741575 git checkout B &&1576 mkdir w &&1577 mkdir x &&1578 git mv z/b w/ &&1579 git mv z/c x/ &&1580 echo d > z/d &&1581 git add z/d &&1582 test_tick &&1583 git commit -m "B"1584 )1585'15861587test_expect_success '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file''1588 (1589 cd 7a &&15901591 git checkout A^0 &&15921593 test_must_fail git merge -s recursive B^0 >out &&1594 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&1595 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&15961597 git ls-files -s >out &&1598 test_line_count = 7 out &&1599 git ls-files -u >out &&1600 test_line_count = 6 out &&1601 git ls-files -o >out &&1602 test_line_count = 1 out &&16031604 git rev-parse >actual \1605 :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&1606 git rev-parse >expect \1607 O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&1608 test_cmp expect actual &&16091610 git hash-object >actual \1611 y/b w/b y/c x/c &&1612 git rev-parse >expect \1613 O:z/b O:z/b O:z/c O:z/c &&1614 test_cmp expect actual1615 )1616'16171618# Testcase 7b, rename/rename(2to1), but only due to transitive rename1619# (Related to testcase 1d)1620# Commit O: z/{b,c}, x/d_1, w/d_21621# Commit A: y/{b,c,d_2}, x/d_11622# Commit B: z/{b,c,d_1}, w/d_21623# Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)16241625test_expect_success '7b-setup: rename/rename(2to1), but only due to transitive rename''1626 test_create_repo 7b &&1627 (1628 cd 7b &&16291630 mkdir z &&1631 mkdir x &&1632 mkdir w &&1633 echo b >z/b &&1634 echo c >z/c &&1635 echo d1 > x/d &&1636 echo d2 > w/d &&1637 git add z x w &&1638 test_tick &&1639 git commit -m "O" &&16401641 git branch O &&1642 git branch A &&1643 git branch B &&16441645 git checkout A &&1646 git mv z y &&1647 git mv w/d y/ &&1648 test_tick &&1649 git commit -m "A" &&16501651 git checkout B &&1652 git mv x/d z/ &&1653 rmdir x &&1654 test_tick &&1655 git commit -m "B"1656 )1657'16581659test_expect_success '7b-check: rename/rename(2to1), but only due to transitive rename''1660 (1661 cd 7b &&16621663 git checkout A^0 &&16641665 test_must_fail git merge -s recursive B^0 >out &&1666 test_i18ngrep "CONFLICT (rename/rename)" out &&16671668 git ls-files -s >out &&1669 test_line_count = 4 out &&1670 git ls-files -u >out &&1671 test_line_count = 2 out &&1672 git ls-files -o >out &&1673 test_line_count = 3 out &&16741675 git rev-parse >actual \1676 :0:y/b :0:y/c :2:y/d :3:y/d &&1677 git rev-parse >expect \1678 O:z/b O:z/c O:w/d O:x/d &&1679 test_cmp expect actual &&16801681 test_path_is_missing y/d &&1682 test_path_is_file y/d~HEAD &&1683 test_path_is_file y/d~B^0 &&16841685 git hash-object >actual \1686 y/d~HEAD y/d~B^0 &&1687 git rev-parse >expect \1688 O:w/d O:x/d &&1689 test_cmp expect actual1690 )1691'16921693# Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity1694# (Related to testcases 3b and 5c)1695# Commit O: z/{b,c}, x/d1696# Commit A: y/{b,c}, w/d1697# Commit B: z/{b,c,d}1698# Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)1699# NOTE: z/ was renamed to y/ so we do want to report1700# neither CONFLICT(x/d -> w/d vs. z/d)1701# nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)17021703test_expect_success '7c-setup: rename/rename(1to...2or3); transitive rename may add complexity''1704 test_create_repo 7c &&1705 (1706 cd 7c &&17071708 mkdir z &&1709 echo b >z/b &&1710 echo c >z/c &&1711 mkdir x &&1712 echo d >x/d &&1713 git add z x &&1714 test_tick &&1715 git commit -m "O" &&17161717 git branch O &&1718 git branch A &&1719 git branch B &&17201721 git checkout A &&1722 git mv z y &&1723 git mv x w &&1724 test_tick &&1725 git commit -m "A" &&17261727 git checkout B &&1728 git mv x/d z/ &&1729 rmdir x &&1730 test_tick &&1731 git commit -m "B"1732 )1733'17341735test_expect_success '7c-check: rename/rename(1to...2or3); transitive rename may add complexity''1736 (1737 cd 7c &&17381739 git checkout A^0 &&17401741 test_must_fail git merge -s recursive B^0 >out &&1742 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&17431744 git ls-files -s >out &&1745 test_line_count = 5 out &&1746 git ls-files -u >out &&1747 test_line_count = 3 out &&1748 git ls-files -o >out &&1749 test_line_count = 1 out &&17501751 git rev-parse >actual \1752 :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&1753 git rev-parse >expect \1754 O:z/b O:z/c O:x/d O:x/d O:x/d &&1755 test_cmp expect actual1756 )1757'17581759# Testcase 7d, transitive rename involved in rename/delete; how is it reported?1760# (Related somewhat to testcases 5b and 8d)1761# Commit O: z/{b,c}, x/d1762# Commit A: y/{b,c}1763# Commit B: z/{b,c,d}1764# Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)1765# NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)17661767test_expect_success '7d-setup: transitive rename involved in rename/delete; how is it reported?''1768 test_create_repo 7d &&1769 (1770 cd 7d &&17711772 mkdir z &&1773 echo b >z/b &&1774 echo c >z/c &&1775 mkdir x &&1776 echo d >x/d &&1777 git add z x &&1778 test_tick &&1779 git commit -m "O" &&17801781 git branch O &&1782 git branch A &&1783 git branch B &&17841785 git checkout A &&1786 git mv z y &&1787 git rm -rf x &&1788 test_tick &&1789 git commit -m "A" &&17901791 git checkout B &&1792 git mv x/d z/ &&1793 rmdir x &&1794 test_tick &&1795 git commit -m "B"1796 )1797'17981799test_expect_success '7d-check: transitive rename involved in rename/delete; how is it reported?''1800 (1801 cd 7d &&18021803 git checkout A^0 &&18041805 test_must_fail git merge -s recursive B^0 >out &&1806 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&18071808 git ls-files -s >out &&1809 test_line_count = 3 out &&1810 git ls-files -u >out &&1811 test_line_count = 1 out &&1812 git ls-files -o >out &&1813 test_line_count = 1 out &&18141815 git rev-parse >actual \1816 :0:y/b :0:y/c :3:y/d &&1817 git rev-parse >expect \1818 O:z/b O:z/c O:x/d &&1819 test_cmp expect actual1820 )1821'18221823# Testcase 7e, transitive rename in rename/delete AND dirs in the way1824# (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)1825# (Also related to testcases 9c and 9d)1826# Commit O: z/{b,c}, x/d_11827# Commit A: y/{b,c,d/g}, x/d/f1828# Commit B: z/{b,c,d_1}1829# Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d1830# y/{b,c,d/g}, y/d_1~B^0, x/d/f18311832# NOTE: The main path of interest here is d_1 and where it ends up, but1833# this is actually a case that has two potential directory renames1834# involved and D/F conflict(s), so it makes sense to walk through1835# each step.1836#1837# Commit A renames z/ -> y/. Thus everything that B adds to z/1838# should be instead moved to y/. This gives us the D/F conflict on1839# y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.1840#1841# Further, commit B renames x/ -> z/, thus everything A adds to x/1842# should instead be moved to z/...BUT we removed z/ and renamed it1843# to y/, so maybe everything should move not from x/ to z/, but1844# from x/ to z/ to y/. Doing so might make sense from the logic so1845# far, but note that commit A had both an x/ and a y/; it did the1846# renaming of z/ to y/ and created x/d/f and it clearly made these1847# things separate, so it doesn't make much sense to push these1848# together. Doing so is what I'd call a doubly transitive rename;1849# see testcases 9c and 9d for further discussion of this issue and1850# how it's resolved.18511852test_expect_success '7e-setup: transitive rename in rename/delete AND dirs in the way''1853 test_create_repo 7e &&1854 (1855 cd 7e &&18561857 mkdir z &&1858 echo b >z/b &&1859 echo c >z/c &&1860 mkdir x &&1861 echo d1 >x/d &&1862 git add z x &&1863 test_tick &&1864 git commit -m "O" &&18651866 git branch O &&1867 git branch A &&1868 git branch B &&18691870 git checkout A &&1871 git mv z y &&1872 git rm x/d &&1873 mkdir -p x/d &&1874 mkdir -p y/d &&1875 echo f >x/d/f &&1876 echo g >y/d/g &&1877 git add x/d/f y/d/g &&1878 test_tick &&1879 git commit -m "A" &&18801881 git checkout B &&1882 git mv x/d z/ &&1883 rmdir x &&1884 test_tick &&1885 git commit -m "B"1886 )1887'18881889test_expect_success '7e-check: transitive rename in rename/delete AND dirs in the way''1890 (1891 cd 7e &&18921893 git checkout A^0 &&18941895 test_must_fail git merge -s recursive B^0 >out &&1896 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&18971898 git ls-files -s >out &&1899 test_line_count = 5 out &&1900 git ls-files -u >out &&1901 test_line_count = 1 out &&1902 git ls-files -o >out &&1903 test_line_count = 2 out &&19041905 git rev-parse >actual \1906 :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&1907 git rev-parse >expect \1908 A:x/d/f A:y/d/g O:z/b O:z/c O:x/d &&1909 test_cmp expect actual &&19101911 git hash-object y/d~B^0 >actual &&1912 git rev-parse O:x/d >expect &&1913 test_cmp expect actual1914 )1915'19161917###########################################################################1918# SECTION 8: Suboptimal merges1919#1920# As alluded to in the last section, the ruleset we have built up for1921# detecting directory renames unfortunately has some special cases where it1922# results in slightly suboptimal or non-intuitive behavior. This section1923# explores these cases.1924#1925# To be fair, we already had non-intuitive or suboptimal behavior for most1926# of these cases in git before introducing implicit directory rename1927# detection, but it'd be nice if there was a modified ruleset out there1928# that handled these cases a bit better.1929###########################################################################19301931# Testcase 8a, Dual-directory rename, one into the others' way1932# Commit O. x/{a,b}, y/{c,d}1933# Commit A. x/{a,b,e}, y/{c,d,f}1934# Commit B. y/{a,b}, z/{c,d}1935#1936# Possible Resolutions:1937# w/o dir-rename detection: y/{a,b,f}, z/{c,d}, x/e1938# Currently expected: y/{a,b,e,f}, z/{c,d}1939# Optimal: y/{a,b,e}, z/{c,d,f}1940#1941# Note: Both x and y got renamed and it'd be nice to detect both, and we do1942# better with directory rename detection than git did without, but the1943# simple rule from section 5 prevents me from handling this as optimally as1944# we potentially could.19451946test_expect_success '8a-setup: Dual-directory rename, one into the others way''1947 test_create_repo 8a &&1948 (1949 cd 8a &&19501951 mkdir x &&1952 mkdir y &&1953 echo a >x/a &&1954 echo b >x/b &&1955 echo c >y/c &&1956 echo d >y/d &&1957 git add x y &&1958 test_tick &&1959 git commit -m "O" &&19601961 git branch O &&1962 git branch A &&1963 git branch B &&19641965 git checkout A &&1966 echo e >x/e &&1967 echo f >y/f &&1968 git add x/e y/f &&1969 test_tick &&1970 git commit -m "A" &&19711972 git checkout B &&1973 git mv y z &&1974 git mv x y &&1975 test_tick &&1976 git commit -m "B"1977 )1978'19791980test_expect_success '8a-check: Dual-directory rename, one into the others way''1981 (1982 cd 8a &&19831984 git checkout A^0 &&19851986 git merge -s recursive B^0 &&19871988 git ls-files -s >out &&1989 test_line_count = 6 out &&1990 git ls-files -u >out &&1991 test_line_count = 0 out &&1992 git ls-files -o >out &&1993 test_line_count = 1 out &&19941995 git rev-parse >actual \1996 HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&1997 git rev-parse >expect \1998 O:x/a O:x/b A:x/e A:y/f O:y/c O:y/d &&1999 test_cmp expect actual2000 )2001'20022003# Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames2004# Commit O. x/{a_1,b_1}, y/{a_2,b_2}2005# Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}2006# Commit B. y/{a_1,b_1}, z/{a_2,b_2}2007#2008# w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_12009# Currently expected: <same>2010# Scary: y/{a_1,b_1}, z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)2011# Optimal: y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}2012#2013# Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and2014# y, both are named 'e'. Without directory rename detection, neither file2015# moves directories. Implement directory rename detection suboptimally, and2016# you get an add/add conflict, but both files were added in commit A, so this2017# is an add/add conflict where one side of history added both files --2018# something we can't represent in the index. Obviously, we'd prefer the last2019# resolution, but our previous rules are too coarse to allow it. Using both2020# the rules from section 4 and section 5 save us from the Scary resolution,2021# making us fall back to pre-directory-rename-detection behavior for both2022# e_1 and e_2.20232024test_expect_success '8b-setup: Dual-directory rename, one into the others way, with conflicting filenames''2025 test_create_repo 8b &&2026 (2027 cd 8b &&20282029 mkdir x &&2030 mkdir y &&2031 echo a1 >x/a &&2032 echo b1 >x/b &&2033 echo a2 >y/a &&2034 echo b2 >y/b &&2035 git add x y &&2036 test_tick &&2037 git commit -m "O" &&20382039 git branch O &&2040 git branch A &&2041 git branch B &&20422043 git checkout A &&2044 echo e1 >x/e &&2045 echo e2 >y/e &&2046 git add x/e y/e &&2047 test_tick &&2048 git commit -m "A" &&20492050 git checkout B &&2051 git mv y z &&2052 git mv x y &&2053 test_tick &&2054 git commit -m "B"2055 )2056'20572058test_expect_success '8b-check: Dual-directory rename, one into the others way, with conflicting filenames''2059 (2060 cd 8b &&20612062 git checkout A^0 &&20632064 git merge -s recursive B^0 &&20652066 git ls-files -s >out &&2067 test_line_count = 6 out &&2068 git ls-files -u >out &&2069 test_line_count = 0 out &&2070 git ls-files -o >out &&2071 test_line_count = 1 out &&20722073 git rev-parse >actual \2074 HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&2075 git rev-parse >expect \2076 O:x/a O:x/b O:y/a O:y/b A:x/e A:y/e &&2077 test_cmp expect actual2078 )2079'20802081# Testcase 8c, modify/delete or rename+modify/delete?2082# (Related to testcases 5b, 8d, and 9h)2083# Commit O: z/{b,c,d}2084# Commit A: y/{b,c}2085# Commit B: z/{b,c,d_modified,e}2086# Expected: y/{b,c,e}, CONFLICT(modify/delete: on z/d)2087#2088# Note: It could easily be argued that the correct resolution here is2089# y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)2090# and that the modifed version of d should be present in y/ after2091# the merge, just marked as conflicted. Indeed, I previously did2092# argue that. But applying directory renames to the side of2093# history where a file is merely modified results in spurious2094# rename/rename(1to2) conflicts -- see testcase 9h. See also2095# notes in 8d.20962097test_expect_success '8c-setup: modify/delete or rename+modify/delete?''2098 test_create_repo 8c &&2099 (2100 cd 8c &&21012102 mkdir z &&2103 echo b >z/b &&2104 echo c >z/c &&2105 test_seq 1 10 >z/d &&2106 git add z &&2107 test_tick &&2108 git commit -m "O" &&21092110 git branch O &&2111 git branch A &&2112 git branch B &&21132114 git checkout A &&2115 git rm z/d &&2116 git mv z y &&2117 test_tick &&2118 git commit -m "A" &&21192120 git checkout B &&2121 echo 11 >z/d &&2122 test_chmod +x z/d &&2123 echo e >z/e &&2124 git add z/d z/e &&2125 test_tick &&2126 git commit -m "B"2127 )2128'21292130test_expect_success '8c-check: modify/delete or rename+modify/delete''2131 (2132 cd 8c &&21332134 git checkout A^0 &&21352136 test_must_fail git merge -s recursive B^0 >out &&2137 test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&21382139 git ls-files -s >out &&2140 test_line_count = 5 out &&2141 git ls-files -u >out &&2142 test_line_count = 2 out &&2143 git ls-files -o >out &&2144 test_line_count = 1 out &&21452146 git rev-parse >actual \2147 :0:y/b :0:y/c :0:y/e :1:z/d :3:z/d &&2148 git rev-parse >expect \2149 O:z/b O:z/c B:z/e O:z/d B:z/d &&2150 test_cmp expect actual &&21512152 test_must_fail git rev-parse :2:z/d &&2153 git ls-files -s z/d | grep ^100755 &&2154 test_path_is_file z/d &&2155 test_path_is_missing y/d2156 )2157'21582159# Testcase 8d, rename/delete...or not?2160# (Related to testcase 5b; these may appear slightly inconsistent to users;2161# Also related to testcases 7d and 7e)2162# Commit O: z/{b,c,d}2163# Commit A: y/{b,c}2164# Commit B: z/{b,c,d,e}2165# Expected: y/{b,c,e}2166#2167# Note: It would also be somewhat reasonable to resolve this as2168# y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)2169#2170# In this case, I'm leaning towards: commit A was the one that deleted z/d2171# and it did the rename of z to y, so the two "conflicts" (rename vs.2172# delete) are both coming from commit A, which is illogical. Conflicts2173# during merging are supposed to be about opposite sides doing things2174# differently.21752176test_expect_success '8d-setup: rename/delete...or not?''2177 test_create_repo 8d &&2178 (2179 cd 8d &&21802181 mkdir z &&2182 echo b >z/b &&2183 echo c >z/c &&2184 test_seq 1 10 >z/d &&2185 git add z &&2186 test_tick &&2187 git commit -m "O" &&21882189 git branch O &&2190 git branch A &&2191 git branch B &&21922193 git checkout A &&2194 git rm z/d &&2195 git mv z y &&2196 test_tick &&2197 git commit -m "A" &&21982199 git checkout B &&2200 echo e >z/e &&2201 git add z/e &&2202 test_tick &&2203 git commit -m "B"2204 )2205'22062207test_expect_success '8d-check: rename/delete...or not?''2208 (2209 cd 8d &&22102211 git checkout A^0 &&22122213 git merge -s recursive B^0 &&22142215 git ls-files -s >out &&2216 test_line_count = 3 out &&22172218 git rev-parse >actual \2219 HEAD:y/b HEAD:y/c HEAD:y/e &&2220 git rev-parse >expect \2221 O:z/b O:z/c B:z/e &&2222 test_cmp expect actual2223 )2224'22252226# Testcase 8e, Both sides rename, one side adds to original directory2227# Commit O: z/{b,c}2228# Commit A: y/{b,c}2229# Commit B: w/{b,c}, z/d2230#2231# Possible Resolutions:2232# w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),2233# CONFLICT(z/c -> y/c vs. w/c)2234# Currently expected: y/d, CONFLICT(z/b -> y/b vs. w/b),2235# CONFLICT(z/c -> y/c vs. w/c)2236# Optimal: ??2237#2238# Notes: In commit A, directory z got renamed to y. In commit B, directory z2239# did NOT get renamed; the directory is still present; instead it is2240# considered to have just renamed a subset of paths in directory z2241# elsewhere. Therefore, the directory rename done in commit A to z/2242# applies to z/d and maps it to y/d.2243#2244# It's possible that users would get confused about this, but what2245# should we do instead? Silently leaving at z/d seems just as bad or2246# maybe even worse. Perhaps we could print a big warning about z/d2247# and how we're moving to y/d in this case, but when I started thinking2248# about the ramifications of doing that, I didn't know how to rule out2249# that opening other weird edge and corner cases so I just punted.22502251test_expect_success '8e-setup: Both sides rename, one side adds to original directory''2252 test_create_repo 8e &&2253 (2254 cd 8e &&22552256 mkdir z &&2257 echo b >z/b &&2258 echo c >z/c &&2259 git add z &&2260 test_tick &&2261 git commit -m "O" &&22622263 git branch O &&2264 git branch A &&2265 git branch B &&22662267 git checkout A &&2268 git mv z y &&2269 test_tick &&2270 git commit -m "A" &&22712272 git checkout B &&2273 git mv z w &&2274 mkdir z &&2275 echo d >z/d &&2276 git add z/d &&2277 test_tick &&2278 git commit -m "B"2279 )2280'22812282test_expect_success '8e-check: Both sides rename, one side adds to original directory''2283 (2284 cd 8e &&22852286 git checkout A^0 &&22872288 test_must_fail git merge -s recursive B^0 >out 2>err &&2289 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&2290 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&22912292 git ls-files -s >out &&2293 test_line_count = 7 out &&2294 git ls-files -u >out &&2295 test_line_count = 6 out &&2296 git ls-files -o >out &&2297 test_line_count = 2 out &&22982299 git rev-parse >actual \2300 :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&2301 git rev-parse >expect \2302 O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&2303 test_cmp expect actual &&23042305 git hash-object >actual \2306 y/b w/b y/c w/c &&2307 git rev-parse >expect \2308 O:z/b O:z/b O:z/c O:z/c &&2309 test_cmp expect actual &&23102311 test_path_is_missing z/b &&2312 test_path_is_missing z/c2313 )2314'23152316###########################################################################2317# SECTION 9: Other testcases2318#2319# This section consists of miscellaneous testcases I thought of during2320# the implementation which round out the testing.2321###########################################################################23222323# Testcase 9a, Inner renamed directory within outer renamed directory2324# (Related to testcase 1f)2325# Commit O: z/{b,c,d/{e,f,g}}2326# Commit A: y/{b,c}, x/w/{e,f,g}2327# Commit B: z/{b,c,d/{e,f,g,h},i}2328# Expected: y/{b,c,i}, x/w/{e,f,g,h}2329# NOTE: The only reason this one is interesting is because when a directory2330# is split into multiple other directories, we determine by the weight2331# of which one had the most paths going to it. A naive implementation2332# of that could take the new file in commit B at z/i to x/w/i or x/i.23332334test_expect_success '9a-setup: Inner renamed directory within outer renamed directory''2335 test_create_repo 9a &&2336 (2337 cd 9a &&23382339 mkdir -p z/d &&2340 echo b >z/b &&2341 echo c >z/c &&2342 echo e >z/d/e &&2343 echo f >z/d/f &&2344 echo g >z/d/g &&2345 git add z &&2346 test_tick &&2347 git commit -m "O" &&23482349 git branch O &&2350 git branch A &&2351 git branch B &&23522353 git checkout A &&2354 mkdir x &&2355 git mv z/d x/w &&2356 git mv z y &&2357 test_tick &&2358 git commit -m "A" &&23592360 git checkout B &&2361 echo h >z/d/h &&2362 echo i >z/i &&2363 git add z &&2364 test_tick &&2365 git commit -m "B"2366 )2367'23682369test_expect_success '9a-check: Inner renamed directory within outer renamed directory''2370 (2371 cd 9a &&23722373 git checkout A^0 &&23742375 git merge -s recursive B^0 &&23762377 git ls-files -s >out &&2378 test_line_count = 7 out &&2379 git ls-files -u >out &&2380 test_line_count = 0 out &&2381 git ls-files -o >out &&2382 test_line_count = 1 out &&23832384 git rev-parse >actual \2385 HEAD:y/b HEAD:y/c HEAD:y/i &&2386 git rev-parse >expect \2387 O:z/b O:z/c B:z/i &&2388 test_cmp expect actual &&23892390 git rev-parse >actual \2391 HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&2392 git rev-parse >expect \2393 O:z/d/e O:z/d/f O:z/d/g B:z/d/h &&2394 test_cmp expect actual2395 )2396'23972398# Testcase 9b, Transitive rename with content merge2399# (Related to testcase 1c)2400# Commit O: z/{b,c}, x/d_12401# Commit A: y/{b,c}, x/d_22402# Commit B: z/{b,c,d_3}2403# Expected: y/{b,c,d_merged}24042405test_expect_success '9b-setup: Transitive rename with content merge''2406 test_create_repo 9b &&2407 (2408 cd 9b &&24092410 mkdir z &&2411 echo b >z/b &&2412 echo c >z/c &&2413 mkdir x &&2414 test_seq 1 10 >x/d &&2415 git add z x &&2416 test_tick &&2417 git commit -m "O" &&24182419 git branch O &&2420 git branch A &&2421 git branch B &&24222423 git checkout A &&2424 git mv z y &&2425 test_seq 1 11 >x/d &&2426 git add x/d &&2427 test_tick &&2428 git commit -m "A" &&24292430 git checkout B &&2431 test_seq 0 10 >x/d &&2432 git mv x/d z/d &&2433 git add z/d &&2434 test_tick &&2435 git commit -m "B"2436 )2437'24382439test_expect_success '9b-check: Transitive rename with content merge''2440 (2441 cd 9b &&24422443 git checkout A^0 &&24442445 git merge -s recursive B^0 &&24462447 git ls-files -s >out &&2448 test_line_count = 3 out &&24492450 test_seq 0 11 >expected &&2451 test_cmp expected y/d &&2452 git add expected &&2453 git rev-parse >actual \2454 HEAD:y/b HEAD:y/c HEAD:y/d &&2455 git rev-parse >expect \2456 O:z/b O:z/c :0:expected &&2457 test_cmp expect actual &&2458 test_must_fail git rev-parse HEAD:x/d &&2459 test_must_fail git rev-parse HEAD:z/d &&2460 test_path_is_missing z/d &&24612462 test$(git rev-parse HEAD:y/d)!=$(git rev-parse O:x/d)&&2463 test$(git rev-parse HEAD:y/d)!=$(git rev-parse A:x/d)&&2464 test$(git rev-parse HEAD:y/d)!=$(git rev-parse B:z/d)2465 )2466'24672468# Testcase 9c, Doubly transitive rename?2469# (Related to testcase 1c, 7e, and 9d)2470# Commit O: z/{b,c}, x/{d,e}, w/f2471# Commit A: y/{b,c}, x/{d,e,f,g}2472# Commit B: z/{b,c,d,e}, w/f2473# Expected: y/{b,c,d,e}, x/{f,g}2474#2475# NOTE: x/f and x/g may be slightly confusing here. The rename from w/f to2476# x/f is clear. Let's look beyond that. Here's the logic:2477# Commit B renamed x/ -> z/2478# Commit A renamed z/ -> y/2479# So, we could possibly further rename x/f to z/f to y/f, a doubly2480# transient rename. However, where does it end? We can chain these2481# indefinitely (see testcase 9d). What if there is a D/F conflict2482# at z/f/ or y/f/? Or just another file conflict at one of those2483# paths? In the case of an N-long chain of transient renamings,2484# where do we "abort" the rename at? Can the user make sense of2485# the resulting conflict and resolve it?2486#2487# To avoid this confusion I use the simple rule that if the other side2488# of history did a directory rename to a path that your side renamed2489# away, then ignore that particular rename from the other side of2490# history for any implicit directory renames.24912492test_expect_success '9c-setup: Doubly transitive rename?''2493 test_create_repo 9c &&2494 (2495 cd 9c &&24962497 mkdir z &&2498 echo b >z/b &&2499 echo c >z/c &&2500 mkdir x &&2501 echo d >x/d &&2502 echo e >x/e &&2503 mkdir w &&2504 echo f >w/f &&2505 git add z x w &&2506 test_tick &&2507 git commit -m "O" &&25082509 git branch O &&2510 git branch A &&2511 git branch B &&25122513 git checkout A &&2514 git mv z y &&2515 git mv w/f x/ &&2516 echo g >x/g &&2517 git add x/g &&2518 test_tick &&2519 git commit -m "A" &&25202521 git checkout B &&2522 git mv x/d z/d &&2523 git mv x/e z/e &&2524 test_tick &&2525 git commit -m "B"2526 )2527'25282529test_expect_success '9c-check: Doubly transitive rename?''2530 (2531 cd 9c &&25322533 git checkout A^0 &&25342535 git merge -s recursive B^0 >out &&2536 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&25372538 git ls-files -s >out &&2539 test_line_count = 6 out &&2540 git ls-files -o >out &&2541 test_line_count = 1 out &&25422543 git rev-parse >actual \2544 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&2545 git rev-parse >expect \2546 O:z/b O:z/c O:x/d O:x/e O:w/f A:x/g &&2547 test_cmp expect actual2548 )2549'25502551# Testcase 9d, N-fold transitive rename?2552# (Related to testcase 9c...and 1c and 7e)2553# Commit O: z/a, y/b, x/c, w/d, v/e, u/f2554# Commit A: y/{a,b}, w/{c,d}, u/{e,f}2555# Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f2556# Expected: <see NOTE first>2557#2558# NOTE: z/ -> y/ (in commit A)2559# y/ -> x/ (in commit B)2560# x/ -> w/ (in commit A)2561# w/ -> v/ (in commit B)2562# v/ -> u/ (in commit A)2563# So, if we add a file to z, say z/t, where should it end up? In u?2564# What if there's another file or directory named 't' in one of the2565# intervening directories and/or in u itself? Also, shouldn't the2566# same logic that places 't' in u/ also move ALL other files to u/?2567# What if there are file or directory conflicts in any of them? If2568# we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames2569# like this, would the user have any hope of understanding any2570# conflicts or how their working tree ended up? I think not, so I'm2571# ruling out N-ary transitive renames for N>1.2572#2573# Therefore our expected result is:2574# z/t, y/a, x/b, w/c, u/d, u/e, u/f2575# The reason that v/d DOES get transitively renamed to u/d is that u/ isn't2576# renamed somewhere. A slightly sub-optimal result, but it uses fairly2577# simple rules that are consistent with what we need for all the other2578# testcases and simplifies things for the user.25792580test_expect_success '9d-setup: N-way transitive rename?''2581 test_create_repo 9d &&2582 (2583 cd 9d &&25842585 mkdir z y x w v u &&2586 echo a >z/a &&2587 echo b >y/b &&2588 echo c >x/c &&2589 echo d >w/d &&2590 echo e >v/e &&2591 echo f >u/f &&2592 git add z y x w v u &&2593 test_tick &&2594 git commit -m "O" &&25952596 git branch O &&2597 git branch A &&2598 git branch B &&25992600 git checkout A &&2601 git mv z/a y/ &&2602 git mv x/c w/ &&2603 git mv v/e u/ &&2604 test_tick &&2605 git commit -m "A" &&26062607 git checkout B &&2608 echo t >z/t &&2609 git mv y/b x/ &&2610 git mv w/d v/ &&2611 git add z/t &&2612 test_tick &&2613 git commit -m "B"2614 )2615'26162617test_expect_success '9d-check: N-way transitive rename?''2618 (2619 cd 9d &&26202621 git checkout A^0 &&26222623 git merge -s recursive B^0 >out &&2624 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&2625 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&2626 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&2627 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&26282629 git ls-files -s >out &&2630 test_line_count = 7 out &&2631 git ls-files -o >out &&2632 test_line_count = 1 out &&26332634 git rev-parse >actual \2635 HEAD:z/t \2636 HEAD:y/a HEAD:x/b HEAD:w/c \2637 HEAD:u/d HEAD:u/e HEAD:u/f &&2638 git rev-parse >expect \2639 B:z/t \2640 O:z/a O:y/b O:x/c \2641 O:w/d O:v/e A:u/f &&2642 test_cmp expect actual2643 )2644'26452646# Testcase 9e, N-to-1 whammo2647# (Related to testcase 9c...and 1c and 7e)2648# Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}2649# Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}2650# Commit B: combined/{a,b,d,e,g,h,j,k}2651# Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,2652# dir1/yo, dir2/yo, dir3/yo, dirN/yo26532654test_expect_success '9e-setup: N-to-1 whammo''2655 test_create_repo 9e &&2656 (2657 cd 9e &&26582659 mkdir dir1 dir2 dir3 dirN &&2660 echo a >dir1/a &&2661 echo b >dir1/b &&2662 echo d >dir2/d &&2663 echo e >dir2/e &&2664 echo g >dir3/g &&2665 echo h >dir3/h &&2666 echo j >dirN/j &&2667 echo k >dirN/k &&2668 git add dir* &&2669 test_tick &&2670 git commit -m "O" &&26712672 git branch O &&2673 git branch A &&2674 git branch B &&26752676 git checkout A &&2677 echo c >dir1/c &&2678 echo yo >dir1/yo &&2679 echo f >dir2/f &&2680 echo yo >dir2/yo &&2681 echo i >dir3/i &&2682 echo yo >dir3/yo &&2683 echo l >dirN/l &&2684 echo yo >dirN/yo &&2685 git add dir* &&2686 test_tick &&2687 git commit -m "A" &&26882689 git checkout B &&2690 git mv dir1 combined &&2691 git mv dir2/* combined/ &&2692 git mv dir3/* combined/ &&2693 git mv dirN/* combined/ &&2694 test_tick &&2695 git commit -m "B"2696 )2697'26982699test_expect_success C_LOCALE_OUTPUT '9e-check: N-to-1 whammo''2700 (2701 cd 9e &&27022703 git checkout A^0 &&27042705 test_must_fail git merge -s recursive B^0 >out &&2706 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&2707 grep -q dir1/yo error_line &&2708 grep -q dir2/yo error_line &&2709 grep -q dir3/yo error_line &&2710 grep -q dirN/yo error_line &&27112712 git ls-files -s >out &&2713 test_line_count = 16 out &&2714 git ls-files -u >out &&2715 test_line_count = 0 out &&2716 git ls-files -o >out &&2717 test_line_count = 2 out &&27182719 git rev-parse >actual \2720 :0:combined/a :0:combined/b :0:combined/c \2721 :0:combined/d :0:combined/e :0:combined/f \2722 :0:combined/g :0:combined/h :0:combined/i \2723 :0:combined/j :0:combined/k :0:combined/l &&2724 git rev-parse >expect \2725 O:dir1/a O:dir1/b A:dir1/c \2726 O:dir2/d O:dir2/e A:dir2/f \2727 O:dir3/g O:dir3/h A:dir3/i \2728 O:dirN/j O:dirN/k A:dirN/l &&2729 test_cmp expect actual &&27302731 git rev-parse >actual \2732 :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&2733 git rev-parse >expect \2734 A:dir1/yo A:dir2/yo A:dir3/yo A:dirN/yo &&2735 test_cmp expect actual2736 )2737'27382739# Testcase 9f, Renamed directory that only contained immediate subdirs2740# (Related to testcases 1e & 9g)2741# Commit O: goal/{a,b}/$more_files2742# Commit A: priority/{a,b}/$more_files2743# Commit B: goal/{a,b}/$more_files, goal/c2744# Expected: priority/{a,b}/$more_files, priority/c27452746test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs''2747 test_create_repo 9f &&2748 (2749 cd 9f &&27502751 mkdir -p goal/a &&2752 mkdir -p goal/b &&2753 echo foo >goal/a/foo &&2754 echo bar >goal/b/bar &&2755 echo baz >goal/b/baz &&2756 git add goal &&2757 test_tick &&2758 git commit -m "O" &&27592760 git branch O &&2761 git branch A &&2762 git branch B &&27632764 git checkout A &&2765 git mv goal/ priority &&2766 test_tick &&2767 git commit -m "A" &&27682769 git checkout B &&2770 echo c >goal/c &&2771 git add goal/c &&2772 test_tick &&2773 git commit -m "B"2774 )2775'27762777test_expect_success '9f-check: Renamed directory that only contained immediate subdirs''2778 (2779 cd 9f &&27802781 git checkout A^0 &&27822783 git merge -s recursive B^0 &&27842785 git ls-files -s >out &&2786 test_line_count = 4 out &&27872788 git rev-parse >actual \2789 HEAD:priority/a/foo \2790 HEAD:priority/b/bar \2791 HEAD:priority/b/baz \2792 HEAD:priority/c &&2793 git rev-parse >expect \2794 O:goal/a/foo \2795 O:goal/b/bar \2796 O:goal/b/baz \2797 B:goal/c &&2798 test_cmp expect actual &&2799 test_must_fail git rev-parse HEAD:goal/c2800 )2801'28022803# Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed2804# (Related to testcases 1e & 9f)2805# Commit O: goal/{a,b}/$more_files2806# Commit A: priority/{alpha,bravo}/$more_files2807# Commit B: goal/{a,b}/$more_files, goal/c2808# Expected: priority/{alpha,bravo}/$more_files, priority/c28092810test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed''2811 test_create_repo 9g &&2812 (2813 cd 9g &&28142815 mkdir -p goal/a &&2816 mkdir -p goal/b &&2817 echo foo >goal/a/foo &&2818 echo bar >goal/b/bar &&2819 echo baz >goal/b/baz &&2820 git add goal &&2821 test_tick &&2822 git commit -m "O" &&28232824 git branch O &&2825 git branch A &&2826 git branch B &&28272828 git checkout A &&2829 mkdir priority &&2830 git mv goal/a/ priority/alpha &&2831 git mv goal/b/ priority/beta &&2832 rmdir goal/ &&2833 test_tick &&2834 git commit -m "A" &&28352836 git checkout B &&2837 echo c >goal/c &&2838 git add goal/c &&2839 test_tick &&2840 git commit -m "B"2841 )2842'28432844test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed''2845 (2846 cd 9g &&28472848 git checkout A^0 &&28492850 git merge -s recursive B^0 &&28512852 git ls-files -s >out &&2853 test_line_count = 4 out &&28542855 git rev-parse >actual \2856 HEAD:priority/alpha/foo \2857 HEAD:priority/beta/bar \2858 HEAD:priority/beta/baz \2859 HEAD:priority/c &&2860 git rev-parse >expect \2861 O:goal/a/foo \2862 O:goal/b/bar \2863 O:goal/b/baz \2864 B:goal/c &&2865 test_cmp expect actual &&2866 test_must_fail git rev-parse HEAD:goal/c2867 )2868'28692870# Testcase 9h, Avoid implicit rename if involved as source on other side2871# (Extremely closely related to testcase 3a)2872# Commit O: z/{b,c,d_1}2873# Commit A: z/{b,c,d_2}2874# Commit B: y/{b,c}, x/d_12875# Expected: y/{b,c}, x/d_22876# NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with2877# a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)2878test_expect_success '9h-setup: Avoid dir rename on merely modified path''2879 test_create_repo 9h &&2880 (2881 cd 9h &&28822883 mkdir z &&2884 echo b >z/b &&2885 echo c >z/c &&2886 printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&2887 git add z &&2888 test_tick &&2889 git commit -m "O" &&28902891 git branch O &&2892 git branch A &&2893 git branch B &&28942895 git checkout A &&2896 test_tick &&2897 echo more >>z/d &&2898 git add z/d &&2899 git commit -m "A" &&29002901 git checkout B &&2902 mkdir y &&2903 mkdir x &&2904 git mv z/b y/ &&2905 git mv z/c y/ &&2906 git mv z/d x/ &&2907 rmdir z &&2908 test_tick &&2909 git commit -m "B"2910 )2911'29122913test_expect_success '9h-check: Avoid dir rename on merely modified path''2914 (2915 cd 9h &&29162917 git checkout A^0 &&29182919 git merge -s recursive B^0 &&29202921 git ls-files -s >out &&2922 test_line_count = 3 out &&29232924 git rev-parse >actual \2925 HEAD:y/b HEAD:y/c HEAD:x/d &&2926 git rev-parse >expect \2927 O:z/b O:z/c A:z/d &&2928 test_cmp expect actual2929 )2930'29312932###########################################################################2933# Rules suggested by section 9:2934#2935# If the other side of history did a directory rename to a path that your2936# side renamed away, then ignore that particular rename from the other2937# side of history for any implicit directory renames.2938###########################################################################29392940###########################################################################2941# SECTION 10: Handling untracked files2942#2943# unpack_trees(), upon which the recursive merge algorithm is based, aborts2944# the operation if untracked or dirty files would be deleted or overwritten2945# by the merge. Unfortunately, unpack_trees() does not understand renames,2946# and if it doesn't abort, then it muddies up the working directory before2947# we even get to the point of detecting renames, so we need some special2948# handling, at least in the case of directory renames.2949###########################################################################29502951# Testcase 10a, Overwrite untracked: normal rename/delete2952# Commit O: z/{b,c_1}2953# Commit A: z/b + untracked z/c + untracked z/d2954# Commit B: z/{b,d_1}2955# Expected: Aborted Merge +2956# ERROR_MSG(untracked working tree files would be overwritten by merge)29572958test_expect_success '10a-setup: Overwrite untracked with normal rename/delete''2959 test_create_repo 10a &&2960 (2961 cd 10a &&29622963 mkdir z &&2964 echo b >z/b &&2965 echo c >z/c &&2966 git add z &&2967 test_tick &&2968 git commit -m "O" &&29692970 git branch O &&2971 git branch A &&2972 git branch B &&29732974 git checkout A &&2975 git rm z/c &&2976 test_tick &&2977 git commit -m "A" &&29782979 git checkout B &&2980 git mv z/c z/d &&2981 test_tick &&2982 git commit -m "B"2983 )2984'29852986test_expect_success '10a-check: Overwrite untracked with normal rename/delete''2987 (2988 cd 10a &&29892990 git checkout A^0 &&2991 echo very >z/c &&2992 echo important >z/d &&29932994 test_must_fail git merge -s recursive B^0 >out 2>err &&2995 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&29962997 git ls-files -s >out &&2998 test_line_count = 1 out &&2999 git ls-files -o >out &&3000 test_line_count = 4 out &&30013002 echo very >expect &&3003 test_cmp expect z/c &&30043005 echo important >expect &&3006 test_cmp expect z/d &&30073008 git rev-parse HEAD:z/b >actual &&3009 git rev-parse O:z/b >expect &&3010 test_cmp expect actual3011 )3012'30133014# Testcase 10b, Overwrite untracked: dir rename + delete3015# Commit O: z/{b,c_1}3016# Commit A: y/b + untracked y/{c,d,e}3017# Commit B: z/{b,d_1,e}3018# Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +3019# z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +3020# ERROR_MSG(refusing to lose untracked file at 'y/d')30213022test_expect_success '10b-setup: Overwrite untracked with dir rename + delete''3023 test_create_repo 10b &&3024 (3025 cd 10b &&30263027 mkdir z &&3028 echo b >z/b &&3029 echo c >z/c &&3030 git add z &&3031 test_tick &&3032 git commit -m "O" &&30333034 git branch O &&3035 git branch A &&3036 git branch B &&30373038 git checkout A &&3039 git rm z/c &&3040 git mv z/ y/ &&3041 test_tick &&3042 git commit -m "A" &&30433044 git checkout B &&3045 git mv z/c z/d &&3046 echo e >z/e &&3047 git add z/e &&3048 test_tick &&3049 git commit -m "B"3050 )3051'30523053test_expect_success '10b-check: Overwrite untracked with dir rename + delete''3054 (3055 cd 10b &&30563057 git checkout A^0 &&3058 echo very >y/c &&3059 echo important >y/d &&3060 echo contents >y/e &&30613062 test_must_fail git merge -s recursive B^0 >out 2>err &&3063 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&3064 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&30653066 git ls-files -s >out &&3067 test_line_count = 3 out &&3068 git ls-files -u >out &&3069 test_line_count = 2 out &&3070 git ls-files -o >out &&3071 test_line_count = 5 out &&30723073 git rev-parse >actual \3074 :0:y/b :3:y/d :3:y/e &&3075 git rev-parse >expect \3076 O:z/b O:z/c B:z/e &&3077 test_cmp expect actual &&30783079 echo very >expect &&3080 test_cmp expect y/c &&30813082 echo important >expect &&3083 test_cmp expect y/d &&30843085 echo contents >expect &&3086 test_cmp expect y/e3087 )3088'30893090# Testcase 10c, Overwrite untracked: dir rename/rename(1to2)3091# Commit O: z/{a,b}, x/{c,d}3092# Commit A: y/{a,b}, w/c, x/d + different untracked y/c3093# Commit B: z/{a,b,c}, x/d3094# Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +3095# CONFLICT(rename/rename) x/c -> w/c vs y/c +3096# y/c~B^0 +3097# ERROR_MSG(Refusing to lose untracked file at y/c)30983099test_expect_success '10c-setup: Overwrite untracked with dir rename/rename(1to2)''3100 test_create_repo 10c &&3101 (3102 cd 10c &&31033104 mkdir z x &&3105 echo a >z/a &&3106 echo b >z/b &&3107 echo c >x/c &&3108 echo d >x/d &&3109 git add z x &&3110 test_tick &&3111 git commit -m "O" &&31123113 git branch O &&3114 git branch A &&3115 git branch B &&31163117 git checkout A &&3118 mkdir w &&3119 git mv x/c w/c &&3120 git mv z/ y/ &&3121 test_tick &&3122 git commit -m "A" &&31233124 git checkout B &&3125 git mv x/c z/ &&3126 test_tick &&3127 git commit -m "B"3128 )3129'31303131test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)''3132 (3133 cd 10c &&31343135 git checkout A^0 &&3136 echo important >y/c &&31373138 test_must_fail git merge -s recursive B^0 >out 2>err &&3139 test_i18ngrep "CONFLICT (rename/rename)" out &&3140 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&31413142 git ls-files -s >out &&3143 test_line_count = 6 out &&3144 git ls-files -u >out &&3145 test_line_count = 3 out &&3146 git ls-files -o >out &&3147 test_line_count = 3 out &&31483149 git rev-parse >actual \3150 :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&3151 git rev-parse >expect \3152 O:z/a O:z/b O:x/d O:x/c O:x/c O:x/c &&3153 test_cmp expect actual &&31543155 git hash-object y/c~B^0 >actual &&3156 git rev-parse O:x/c >expect &&3157 test_cmp expect actual &&31583159 echo important >expect &&3160 test_cmp expect y/c3161 )3162'31633164# Testcase 10d, Delete untracked w/ dir rename/rename(2to1)3165# Commit O: z/{a,b,c_1}, x/{d,e,f_2}3166# Commit A: y/{a,b}, x/{d,e,f_2,wham_1} + untracked y/wham3167# Commit B: z/{a,b,c_1,wham_2}, y/{d,e}3168# Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+3169# CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham3170# ERROR_MSG(Refusing to lose untracked file at y/wham)31713172test_expect_success '10d-setup: Delete untracked with dir rename/rename(2to1)''3173 test_create_repo 10d &&3174 (3175 cd 10d &&31763177 mkdir z x &&3178 echo a >z/a &&3179 echo b >z/b &&3180 echo c >z/c &&3181 echo d >x/d &&3182 echo e >x/e &&3183 echo f >x/f &&3184 git add z x &&3185 test_tick &&3186 git commit -m "O" &&31873188 git branch O &&3189 git branch A &&3190 git branch B &&31913192 git checkout A &&3193 git mv z/c x/wham &&3194 git mv z/ y/ &&3195 test_tick &&3196 git commit -m "A" &&31973198 git checkout B &&3199 git mv x/f z/wham &&3200 git mv x/ y/ &&3201 test_tick &&3202 git commit -m "B"3203 )3204'32053206test_expect_success '10d-check: Delete untracked with dir rename/rename(2to1)''3207 (3208 cd 10d &&32093210 git checkout A^0 &&3211 echo important >y/wham &&32123213 test_must_fail git merge -s recursive B^0 >out 2>err &&3214 test_i18ngrep "CONFLICT (rename/rename)" out &&3215 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&32163217 git ls-files -s >out &&3218 test_line_count = 6 out &&3219 git ls-files -u >out &&3220 test_line_count = 2 out &&3221 git ls-files -o >out &&3222 test_line_count = 4 out &&32233224 git rev-parse >actual \3225 :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&3226 git rev-parse >expect \3227 O:z/a O:z/b O:x/d O:x/e O:z/c O:x/f &&3228 test_cmp expect actual &&32293230 test_must_fail git rev-parse :1:y/wham &&32313232 echo important >expect &&3233 test_cmp expect y/wham &&32343235 git hash-object >actual \3236 y/wham~B^0 y/wham~HEAD &&3237 git rev-parse >expect \3238 O:x/f O:z/c &&3239 test_cmp expect actual3240 )3241'32423243# Testcase 10e, Does git complain about untracked file that's not in the way?3244# Commit O: z/{a,b}3245# Commit A: y/{a,b} + untracked z/c3246# Commit B: z/{a,b,c}3247# Expected: y/{a,b,c} + untracked z/c32483249test_expect_success '10e-setup: Does git complain about untracked file that is not really in the way?''3250 test_create_repo 10e &&3251 (3252 cd 10e &&32533254 mkdir z &&3255 echo a >z/a &&3256 echo b >z/b &&3257 git add z &&3258 test_tick &&3259 git commit -m "O" &&32603261 git branch O &&3262 git branch A &&3263 git branch B &&32643265 git checkout A &&3266 git mv z/ y/ &&3267 test_tick &&3268 git commit -m "A" &&32693270 git checkout B &&3271 echo c >z/c &&3272 git add z/c &&3273 test_tick &&3274 git commit -m "B"3275 )3276'32773278test_expect_failure '10e-check: Does git complain about untracked file that is not really in the way?''3279 (3280 cd 10e &&32813282 git checkout A^0 &&3283 mkdir z &&3284 echo random >z/c &&32853286 git merge -s recursive B^0 >out 2>err &&3287 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&32883289 git ls-files -s >out &&3290 test_line_count = 3 out &&3291 git ls-files -u >out &&3292 test_line_count = 0 out &&3293 git ls-files -o >out &&3294 test_line_count = 3 out &&32953296 git rev-parse >actual \3297 :0:y/a :0:y/b :0:y/c &&3298 git rev-parse >expect \3299 O:z/a O:z/b B:z/c &&3300 test_cmp expect actual &&33013302 echo random >expect &&3303 test_cmp expect z/c3304 )3305'33063307###########################################################################3308# SECTION 11: Handling dirty (not up-to-date) files3309#3310# unpack_trees(), upon which the recursive merge algorithm is based, aborts3311# the operation if untracked or dirty files would be deleted or overwritten3312# by the merge. Unfortunately, unpack_trees() does not understand renames,3313# and if it doesn't abort, then it muddies up the working directory before3314# we even get to the point of detecting renames, so we need some special3315# handling. This was true even of normal renames, but there are additional3316# codepaths that need special handling with directory renames. Add3317# testcases for both renamed-by-directory-rename-detection and standard3318# rename cases.3319###########################################################################33203321# Testcase 11a, Avoid losing dirty contents with simple rename3322# Commit O: z/{a,b_v1},3323# Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods3324# Commit B: z/{a,b_v2}3325# Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +3326# z/a, staged version of z/c has sha1sum matching B:z/b_v2,3327# z/c~HEAD with contents of B:z/b_v2,3328# z/c with uncommitted mods on top of A:z/c_v133293330test_expect_success '11a-setup: Avoid losing dirty contents with simple rename''3331 test_create_repo 11a &&3332 (3333 cd 11a &&33343335 mkdir z &&3336 echo a >z/a &&3337 test_seq 1 10 >z/b &&3338 git add z &&3339 test_tick &&3340 git commit -m "O" &&33413342 git branch O &&3343 git branch A &&3344 git branch B &&33453346 git checkout A &&3347 git mv z/b z/c &&3348 test_tick &&3349 git commit -m "A" &&33503351 git checkout B &&3352 echo 11 >>z/b &&3353 git add z/b &&3354 test_tick &&3355 git commit -m "B"3356 )3357'33583359test_expect_success '11a-check: Avoid losing dirty contents with simple rename''3360 (3361 cd 11a &&33623363 git checkout A^0 &&3364 echo stuff >>z/c &&33653366 test_must_fail git merge -s recursive B^0 >out 2>err &&3367 test_i18ngrep "Refusing to lose dirty file at z/c" out &&33683369 test_seq 1 10 >expected &&3370 echo stuff >>expected &&3371 test_cmp expected z/c &&33723373 git ls-files -s >out &&3374 test_line_count = 2 out &&3375 git ls-files -u >out &&3376 test_line_count = 1 out &&3377 git ls-files -o >out &&3378 test_line_count = 4 out &&33793380 git rev-parse >actual \3381 :0:z/a :2:z/c &&3382 git rev-parse >expect \3383 O:z/a B:z/b &&3384 test_cmp expect actual &&33853386 git hash-object z/c~HEAD >actual &&3387 git rev-parse B:z/b >expect &&3388 test_cmp expect actual3389 )3390'33913392# Testcase 11b, Avoid losing dirty file involved in directory rename3393# Commit O: z/a, x/{b,c_v1}3394# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods3395# Commit B: y/a, x/{b,c_v2}3396# Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,3397# ERROR_MSG(Refusing to lose dirty file at z/c)339833993400test_expect_success '11b-setup: Avoid losing dirty file involved in directory rename''3401 test_create_repo 11b &&3402 (3403 cd 11b &&34043405 mkdir z x &&3406 echo a >z/a &&3407 echo b >x/b &&3408 test_seq 1 10 >x/c &&3409 git add z x &&3410 test_tick &&3411 git commit -m "O" &&34123413 git branch O &&3414 git branch A &&3415 git branch B &&34163417 git checkout A &&3418 git mv x/c z/c &&3419 test_tick &&3420 git commit -m "A" &&34213422 git checkout B &&3423 git mv z y &&3424 echo 11 >>x/c &&3425 git add x/c &&3426 test_tick &&3427 git commit -m "B"3428 )3429'34303431test_expect_success '11b-check: Avoid losing dirty file involved in directory rename''3432 (3433 cd 11b &&34343435 git checkout A^0 &&3436 echo stuff >>z/c &&34373438 git merge -s recursive B^0 >out 2>err &&3439 test_i18ngrep "Refusing to lose dirty file at z/c" out &&34403441 grep -q stuff z/c &&3442 test_seq 1 10 >expected &&3443 echo stuff >>expected &&3444 test_cmp expected z/c &&34453446 git ls-files -s >out &&3447 test_line_count = 3 out &&3448 git ls-files -u >out &&3449 test_line_count = 0 out &&3450 git ls-files -m >out &&3451 test_line_count = 0 out &&3452 git ls-files -o >out &&3453 test_line_count = 4 out &&34543455 git rev-parse >actual \3456 :0:x/b :0:y/a :0:y/c &&3457 git rev-parse >expect \3458 O:x/b O:z/a B:x/c &&3459 test_cmp expect actual &&34603461 git hash-object y/c >actual &&3462 git rev-parse B:x/c >expect &&3463 test_cmp expect actual3464 )3465'34663467# Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict3468# Commit O: y/a, x/{b,c_v1}3469# Commit A: y/{a,c_v1}, x/b, and y/c_v1 has uncommitted mods3470# Commit B: y/{a,c/d}, x/{b,c_v2}3471# Expected: Abort_msg("following files would be overwritten by merge") +3472# y/c left untouched (still has uncommitted mods)34733474test_expect_success '11c-setup: Avoid losing not-uptodate with rename + D/F conflict''3475 test_create_repo 11c &&3476 (3477 cd 11c &&34783479 mkdir y x &&3480 echo a >y/a &&3481 echo b >x/b &&3482 test_seq 1 10 >x/c &&3483 git add y x &&3484 test_tick &&3485 git commit -m "O" &&34863487 git branch O &&3488 git branch A &&3489 git branch B &&34903491 git checkout A &&3492 git mv x/c y/c &&3493 test_tick &&3494 git commit -m "A" &&34953496 git checkout B &&3497 mkdir y/c &&3498 echo d >y/c/d &&3499 echo 11 >>x/c &&3500 git add x/c y/c/d &&3501 test_tick &&3502 git commit -m "B"3503 )3504'35053506test_expect_success '11c-check: Avoid losing not-uptodate with rename + D/F conflict''3507 (3508 cd 11c &&35093510 git checkout A^0 &&3511 echo stuff >>y/c &&35123513 test_must_fail git merge -s recursive B^0 >out 2>err &&3514 test_i18ngrep "following files would be overwritten by merge" err &&35153516 grep -q stuff y/c &&3517 test_seq 1 10 >expected &&3518 echo stuff >>expected &&3519 test_cmp expected y/c &&35203521 git ls-files -s >out &&3522 test_line_count = 3 out &&3523 git ls-files -u >out &&3524 test_line_count = 0 out &&3525 git ls-files -m >out &&3526 test_line_count = 1 out &&3527 git ls-files -o >out &&3528 test_line_count = 3 out3529 )3530'35313532# Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict3533# Commit O: z/a, x/{b,c_v1}3534# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods3535# Commit B: y/{a,c/d}, x/{b,c_v2}3536# Expected: D/F: y/c_v2 vs y/c/d) +3537# Warning_Msg("Refusing to lose dirty file at z/c) +3538# y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods35393540test_expect_success '11d-setup: Avoid losing not-uptodate with rename + D/F conflict''3541 test_create_repo 11d &&3542 (3543 cd 11d &&35443545 mkdir z x &&3546 echo a >z/a &&3547 echo b >x/b &&3548 test_seq 1 10 >x/c &&3549 git add z x &&3550 test_tick &&3551 git commit -m "O" &&35523553 git branch O &&3554 git branch A &&3555 git branch B &&35563557 git checkout A &&3558 git mv x/c z/c &&3559 test_tick &&3560 git commit -m "A" &&35613562 git checkout B &&3563 git mv z y &&3564 mkdir y/c &&3565 echo d >y/c/d &&3566 echo 11 >>x/c &&3567 git add x/c y/c/d &&3568 test_tick &&3569 git commit -m "B"3570 )3571'35723573test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conflict''3574 (3575 cd 11d &&35763577 git checkout A^0 &&3578 echo stuff >>z/c &&35793580 test_must_fail git merge -s recursive B^0 >out 2>err &&3581 test_i18ngrep "Refusing to lose dirty file at z/c" out &&35823583 grep -q stuff z/c &&3584 test_seq 1 10 >expected &&3585 echo stuff >>expected &&3586 test_cmp expected z/c35873588 git ls-files -s >out &&3589 test_line_count = 4 out &&3590 git ls-files -u >out &&3591 test_line_count = 1 out &&3592 git ls-files -o >out &&3593 test_line_count = 5 out &&35943595 git rev-parse >actual \3596 :0:x/b :0:y/a :0:y/c/d :3:y/c &&3597 git rev-parse >expect \3598 O:x/b O:z/a B:y/c/d B:x/c &&3599 test_cmp expect actual &&36003601 git hash-object y/c~HEAD >actual &&3602 git rev-parse B:x/c >expect &&3603 test_cmp expect actual3604 )3605'36063607# Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add3608# Commit O: z/{a,b}, x/{c_1,d}3609# Commit A: y/{a,b,c_2}, x/d, w/c_1, and y/c_2 has uncommitted mods3610# Commit B: z/{a,b,c_1}, x/d3611# Expected: Failed Merge; y/{a,b} + x/d +3612# CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +3613# ERROR_MSG(Refusing to lose dirty file at y/c)3614# y/c~B^0 has O:x/c_1 contents3615# y/c~HEAD has A:y/c_2 contents3616# y/c has dirty file from before merge36173618test_expect_success '11e-setup: Avoid deleting not-uptodate with dir rename/rename(1to2)/add''3619 test_create_repo 11e &&3620 (3621 cd 11e &&36223623 mkdir z x &&3624 echo a >z/a &&3625 echo b >z/b &&3626 echo c >x/c &&3627 echo d >x/d &&3628 git add z x &&3629 test_tick &&3630 git commit -m "O" &&36313632 git branch O &&3633 git branch A &&3634 git branch B &&36353636 git checkout A &&3637 git mv z/ y/ &&3638 echo different >y/c &&3639 mkdir w &&3640 git mv x/c w/ &&3641 git add y/c &&3642 test_tick &&3643 git commit -m "A" &&36443645 git checkout B &&3646 git mv x/c z/ &&3647 test_tick &&3648 git commit -m "B"3649 )3650'36513652test_expect_success '11e-check: Avoid deleting not-uptodate with dir rename/rename(1to2)/add''3653 (3654 cd 11e &&36553656 git checkout A^0 &&3657 echo mods >>y/c &&36583659 test_must_fail git merge -s recursive B^0 >out 2>err &&3660 test_i18ngrep "CONFLICT (rename/rename)" out &&3661 test_i18ngrep "Refusing to lose dirty file at y/c" out &&36623663 git ls-files -s >out &&3664 test_line_count = 7 out &&3665 git ls-files -u >out &&3666 test_line_count = 4 out &&3667 git ls-files -o >out &&3668 test_line_count = 4 out &&36693670 echo different >expected &&3671 echo mods >>expected &&3672 test_cmp expected y/c &&36733674 git rev-parse >actual \3675 :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&3676 git rev-parse >expect \3677 O:z/a O:z/b O:x/d O:x/c O:x/c A:y/c O:x/c &&3678 test_cmp expect actual &&36793680 git hash-object >actual \3681 y/c~B^0 y/c~HEAD &&3682 git rev-parse >expect \3683 O:x/c A:y/c &&3684 test_cmp expect actual3685 )3686'36873688# Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)3689# Commit O: z/{a,b}, x/{c_1,d_2}3690# Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods3691# Commit B: z/{a,b,wham_2}, x/c_13692# Expected: Failed Merge; y/{a,b} + untracked y/{wham~B^0,wham~B^HEAD} +3693# y/wham with dirty changes from before merge +3694# CONFLICT(rename/rename) x/c vs x/d -> y/wham3695# ERROR_MSG(Refusing to lose dirty file at y/wham)36963697test_expect_success '11f-setup: Avoid deleting not-uptodate with dir rename/rename(2to1)''3698 test_create_repo 11f &&3699 (3700 cd 11f &&37013702 mkdir z x &&3703 echo a >z/a &&3704 echo b >z/b &&3705 test_seq 1 10 >x/c &&3706 echo d >x/d &&3707 git add z x &&3708 test_tick &&3709 git commit -m "O" &&37103711 git branch O &&3712 git branch A &&3713 git branch B &&37143715 git checkout A &&3716 git mv z/ y/ &&3717 git mv x/c y/wham &&3718 test_tick &&3719 git commit -m "A" &&37203721 git checkout B &&3722 git mv x/d z/wham &&3723 test_tick &&3724 git commit -m "B"3725 )3726'37273728test_expect_success '11f-check: Avoid deleting not-uptodate with dir rename/rename(2to1)''3729 (3730 cd 11f &&37313732 git checkout A^0 &&3733 echo important >>y/wham &&37343735 test_must_fail git merge -s recursive B^0 >out 2>err &&3736 test_i18ngrep "CONFLICT (rename/rename)" out &&3737 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&37383739 git ls-files -s >out &&3740 test_line_count = 4 out &&3741 git ls-files -u >out &&3742 test_line_count = 2 out &&3743 git ls-files -o >out &&3744 test_line_count = 4 out &&37453746 test_seq 1 10 >expected &&3747 echo important >>expected &&3748 test_cmp expected y/wham &&37493750 test_must_fail git rev-parse :1:y/wham &&3751 git hash-object >actual \3752 y/wham~B^0 y/wham~HEAD &&3753 git rev-parse >expect \3754 O:x/d O:x/c &&3755 test_cmp expect actual &&37563757 git rev-parse >actual \3758 :0:y/a :0:y/b :2:y/wham :3:y/wham &&3759 git rev-parse >expect \3760 O:z/a O:z/b O:x/c O:x/d &&3761 test_cmp expect actual3762 )3763'37643765###########################################################################3766# SECTION 12: Everything else3767#3768# Tests suggested by others. Tests added after implementation completed3769# and submitted. Grab bag.3770###########################################################################37713772# Testcase 12a, Moving one directory hierarchy into another3773# (Related to testcase 9a)3774# Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}3775# Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}3776# Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}3777# Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}37783779test_expect_success '12a-setup: Moving one directory hierarchy into another''3780 test_create_repo 12a &&3781 (3782 cd 12a &&37833784 mkdir -p node1 node2 &&3785 echo leaf1 >node1/leaf1 &&3786 echo leaf2 >node1/leaf2 &&3787 echo leaf3 >node2/leaf3 &&3788 echo leaf4 >node2/leaf4 &&3789 git add node1 node2 &&3790 test_tick &&3791 git commit -m "O" &&37923793 git branch O &&3794 git branch A &&3795 git branch B &&37963797 git checkout A &&3798 git mv node2/ node1/ &&3799 test_tick &&3800 git commit -m "A" &&38013802 git checkout B &&3803 echo leaf5 >node1/leaf5 &&3804 echo leaf6 >node2/leaf6 &&3805 git add node1 node2 &&3806 test_tick &&3807 git commit -m "B"3808 )3809'38103811test_expect_success '12a-check: Moving one directory hierarchy into another''3812 (3813 cd 12a &&38143815 git checkout A^0 &&38163817 git merge -s recursive B^0 &&38183819 git ls-files -s >out &&3820 test_line_count = 6 out &&38213822 git rev-parse >actual \3823 HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \3824 HEAD:node1/node2/leaf3 \3825 HEAD:node1/node2/leaf4 \3826 HEAD:node1/node2/leaf6 &&3827 git rev-parse >expect \3828 O:node1/leaf1 O:node1/leaf2 B:node1/leaf5 \3829 O:node2/leaf3 \3830 O:node2/leaf4 \3831 B:node2/leaf6 &&3832 test_cmp expect actual3833 )3834'38353836# Testcase 12b, Moving two directory hierarchies into each other3837# (Related to testcases 1c and 12c)3838# Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}3839# Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}3840# Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}3841# Expected: node1/node2/node1/{leaf1, leaf2},3842# node2/node1/node2/{leaf3, leaf4}3843# NOTE: Without directory renames, we would expect3844# node2/node1/{leaf1, leaf2},3845# node1/node2/{leaf3, leaf4}3846# with directory rename detection, we note that3847# commit A renames node2/ -> node1/node2/3848# commit B renames node1/ -> node2/node1/3849# therefore, applying those directory renames to the initial result3850# (making all four paths experience a transitive renaming), yields3851# the expected result.3852#3853# You may ask, is it weird to have two directories rename each other?3854# To which, I can do no more than shrug my shoulders and say that3855# even simple rules give weird results when given weird inputs.38563857test_expect_success '12b-setup: Moving one directory hierarchy into another''3858 test_create_repo 12b &&3859 (3860 cd 12b &&38613862 mkdir -p node1 node2 &&3863 echo leaf1 >node1/leaf1 &&3864 echo leaf2 >node1/leaf2 &&3865 echo leaf3 >node2/leaf3 &&3866 echo leaf4 >node2/leaf4 &&3867 git add node1 node2 &&3868 test_tick &&3869 git commit -m "O" &&38703871 git branch O &&3872 git branch A &&3873 git branch B &&38743875 git checkout A &&3876 git mv node2/ node1/ &&3877 test_tick &&3878 git commit -m "A" &&38793880 git checkout B &&3881 git mv node1/ node2/ &&3882 test_tick &&3883 git commit -m "B"3884 )3885'38863887test_expect_success '12b-check: Moving one directory hierarchy into another''3888 (3889 cd 12b &&38903891 git checkout A^0 &&38923893 git merge -s recursive B^0 &&38943895 git ls-files -s >out &&3896 test_line_count = 4 out &&38973898 git rev-parse >actual \3899 HEAD:node1/node2/node1/leaf1 \3900 HEAD:node1/node2/node1/leaf2 \3901 HEAD:node2/node1/node2/leaf3 \3902 HEAD:node2/node1/node2/leaf4 &&3903 git rev-parse >expect \3904 O:node1/leaf1 \3905 O:node1/leaf2 \3906 O:node2/leaf3 \3907 O:node2/leaf4 &&3908 test_cmp expect actual3909 )3910'39113912# Testcase 12c, Moving two directory hierarchies into each other w/ content merge3913# (Related to testcase 12b)3914# Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}3915# Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}}3916# Commit B: node2/{node1/{leaf1_3, leaf2_3}, leaf3_3, leaf4_3}3917# Expected: Content merge conflicts for each of:3918# node1/node2/node1/{leaf1, leaf2},3919# node2/node1/node2/{leaf3, leaf4}3920# NOTE: This is *exactly* like 12c, except that every path is modified on3921# each side of the merge.39223923test_expect_success '12c-setup: Moving one directory hierarchy into another w/ content merge''3924 test_create_repo 12c &&3925 (3926 cd 12c &&39273928 mkdir -p node1 node2 &&3929 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&3930 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&3931 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&3932 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&3933 git add node1 node2 &&3934 test_tick &&3935 git commit -m "O" &&39363937 git branch O &&3938 git branch A &&3939 git branch B &&39403941 git checkout A &&3942 git mv node2/ node1/ &&3943 for i in `git ls-files`; do echo side A >>$i; done &&3944 git add -u &&3945 test_tick &&3946 git commit -m "A" &&39473948 git checkout B &&3949 git mv node1/ node2/ &&3950 for i in `git ls-files`; do echo side B >>$i; done &&3951 git add -u &&3952 test_tick &&3953 git commit -m "B"3954 )3955'39563957test_expect_success '12c-check: Moving one directory hierarchy into another w/ content merge''3958 (3959 cd 12c &&39603961 git checkout A^0 &&39623963 test_must_fail git merge -s recursive B^0 &&39643965 git ls-files -u >out &&3966 test_line_count = 12 out &&39673968 git rev-parse >actual \3969 :1:node1/node2/node1/leaf1 \3970 :1:node1/node2/node1/leaf2 \3971 :1:node2/node1/node2/leaf3 \3972 :1:node2/node1/node2/leaf4 \3973 :2:node1/node2/node1/leaf1 \3974 :2:node1/node2/node1/leaf2 \3975 :2:node2/node1/node2/leaf3 \3976 :2:node2/node1/node2/leaf4 \3977 :3:node1/node2/node1/leaf1 \3978 :3:node1/node2/node1/leaf2 \3979 :3:node2/node1/node2/leaf3 \3980 :3:node2/node1/node2/leaf4 &&3981 git rev-parse >expect \3982 O:node1/leaf1 \3983 O:node1/leaf2 \3984 O:node2/leaf3 \3985 O:node2/leaf4 \3986 A:node1/leaf1 \3987 A:node1/leaf2 \3988 A:node1/node2/leaf3 \3989 A:node1/node2/leaf4 \3990 B:node2/node1/leaf1 \3991 B:node2/node1/leaf2 \3992 B:node2/leaf3 \3993 B:node2/leaf4 &&3994 test_cmp expect actual3995 )3996'39973998test_done