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, rename+modify/delete2082# (Related to testcases 5b and 8d)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(rename+modify/delete: x/d -> y/d or deleted)2087#2088# Note: This testcase doesn't present any concerns for me...until you2089# compare it with testcases 5b and 8d. See notes in 8d for more2090# details.20912092test_expect_success '8c-setup: rename+modify/delete''2093 test_create_repo 8c &&2094 (2095 cd 8c &&20962097 mkdir z &&2098 echo b >z/b &&2099 echo c >z/c &&2100 test_seq 1 10 >z/d &&2101 git add z &&2102 test_tick &&2103 git commit -m "O" &&21042105 git branch O &&2106 git branch A &&2107 git branch B &&21082109 git checkout A &&2110 git rm z/d &&2111 git mv z y &&2112 test_tick &&2113 git commit -m "A" &&21142115 git checkout B &&2116 echo 11 >z/d &&2117 test_chmod +x z/d &&2118 echo e >z/e &&2119 git add z/d z/e &&2120 test_tick &&2121 git commit -m "B"2122 )2123'21242125test_expect_success '8c-check: rename+modify/delete''2126 (2127 cd 8c &&21282129 git checkout A^0 &&21302131 test_must_fail git merge -s recursive B^0 >out &&2132 test_i18ngrep "CONFLICT (rename/delete).* z/d.*y/d" out &&21332134 git ls-files -s >out &&2135 test_line_count = 4 out &&2136 git ls-files -u >out &&2137 test_line_count = 1 out &&2138 git ls-files -o >out &&2139 test_line_count = 1 out &&21402141 git rev-parse >actual \2142 :0:y/b :0:y/c :0:y/e :3:y/d &&2143 git rev-parse >expect \2144 O:z/b O:z/c B:z/e B:z/d &&2145 test_cmp expect actual &&21462147 test_must_fail git rev-parse :1:y/d &&2148 test_must_fail git rev-parse :2:y/d &&2149 git ls-files -s y/d | grep ^100755 &&2150 test_path_is_file y/d2151 )2152'21532154# Testcase 8d, rename/delete...or not?2155# (Related to testcase 5b; these may appear slightly inconsistent to users;2156# Also related to testcases 7d and 7e)2157# Commit O: z/{b,c,d}2158# Commit A: y/{b,c}2159# Commit B: z/{b,c,d,e}2160# Expected: y/{b,c,e}2161#2162# Note: It would also be somewhat reasonable to resolve this as2163# y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)2164# The logic being that the only difference between this testcase and 8c2165# is that there is no modification to d. That suggests that instead of a2166# rename/modify vs. delete conflict, we should just have a rename/delete2167# conflict, otherwise we are being inconsistent.2168#2169# However...as far as consistency goes, we didn't report a conflict for2170# path d_1 in testcase 5b due to a different file being in the way. So,2171# we seem to be forced to have cases where users can change things2172# slightly and get what they may perceive as inconsistent results. It2173# would be nice to avoid that, but I'm not sure I see how.2174#2175# In this case, I'm leaning towards: commit A was the one that deleted z/d2176# and it did the rename of z to y, so the two "conflicts" (rename vs.2177# delete) are both coming from commit A, which is illogical. Conflicts2178# during merging are supposed to be about opposite sides doing things2179# differently.21802181test_expect_success '8d-setup: rename/delete...or not?''2182 test_create_repo 8d &&2183 (2184 cd 8d &&21852186 mkdir z &&2187 echo b >z/b &&2188 echo c >z/c &&2189 test_seq 1 10 >z/d &&2190 git add z &&2191 test_tick &&2192 git commit -m "O" &&21932194 git branch O &&2195 git branch A &&2196 git branch B &&21972198 git checkout A &&2199 git rm z/d &&2200 git mv z y &&2201 test_tick &&2202 git commit -m "A" &&22032204 git checkout B &&2205 echo e >z/e &&2206 git add z/e &&2207 test_tick &&2208 git commit -m "B"2209 )2210'22112212test_expect_success '8d-check: rename/delete...or not?''2213 (2214 cd 8d &&22152216 git checkout A^0 &&22172218 git merge -s recursive B^0 &&22192220 git ls-files -s >out &&2221 test_line_count = 3 out &&22222223 git rev-parse >actual \2224 HEAD:y/b HEAD:y/c HEAD:y/e &&2225 git rev-parse >expect \2226 O:z/b O:z/c B:z/e &&2227 test_cmp expect actual2228 )2229'22302231# Testcase 8e, Both sides rename, one side adds to original directory2232# Commit O: z/{b,c}2233# Commit A: y/{b,c}2234# Commit B: w/{b,c}, z/d2235#2236# Possible Resolutions:2237# w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),2238# CONFLICT(z/c -> y/c vs. w/c)2239# Currently expected: y/d, CONFLICT(z/b -> y/b vs. w/b),2240# CONFLICT(z/c -> y/c vs. w/c)2241# Optimal: ??2242#2243# Notes: In commit A, directory z got renamed to y. In commit B, directory z2244# did NOT get renamed; the directory is still present; instead it is2245# considered to have just renamed a subset of paths in directory z2246# elsewhere. Therefore, the directory rename done in commit A to z/2247# applies to z/d and maps it to y/d.2248#2249# It's possible that users would get confused about this, but what2250# should we do instead? Silently leaving at z/d seems just as bad or2251# maybe even worse. Perhaps we could print a big warning about z/d2252# and how we're moving to y/d in this case, but when I started thinking2253# about the ramifications of doing that, I didn't know how to rule out2254# that opening other weird edge and corner cases so I just punted.22552256test_expect_success '8e-setup: Both sides rename, one side adds to original directory''2257 test_create_repo 8e &&2258 (2259 cd 8e &&22602261 mkdir z &&2262 echo b >z/b &&2263 echo c >z/c &&2264 git add z &&2265 test_tick &&2266 git commit -m "O" &&22672268 git branch O &&2269 git branch A &&2270 git branch B &&22712272 git checkout A &&2273 git mv z y &&2274 test_tick &&2275 git commit -m "A" &&22762277 git checkout B &&2278 git mv z w &&2279 mkdir z &&2280 echo d >z/d &&2281 git add z/d &&2282 test_tick &&2283 git commit -m "B"2284 )2285'22862287test_expect_success '8e-check: Both sides rename, one side adds to original directory''2288 (2289 cd 8e &&22902291 git checkout A^0 &&22922293 test_must_fail git merge -s recursive B^0 >out 2>err &&2294 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&2295 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&22962297 git ls-files -s >out &&2298 test_line_count = 7 out &&2299 git ls-files -u >out &&2300 test_line_count = 6 out &&2301 git ls-files -o >out &&2302 test_line_count = 2 out &&23032304 git rev-parse >actual \2305 :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&2306 git rev-parse >expect \2307 O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&2308 test_cmp expect actual &&23092310 git hash-object >actual \2311 y/b w/b y/c w/c &&2312 git rev-parse >expect \2313 O:z/b O:z/b O:z/c O:z/c &&2314 test_cmp expect actual &&23152316 test_path_is_missing z/b &&2317 test_path_is_missing z/c2318 )2319'23202321###########################################################################2322# SECTION 9: Other testcases2323#2324# This section consists of miscellaneous testcases I thought of during2325# the implementation which round out the testing.2326###########################################################################23272328# Testcase 9a, Inner renamed directory within outer renamed directory2329# (Related to testcase 1f)2330# Commit O: z/{b,c,d/{e,f,g}}2331# Commit A: y/{b,c}, x/w/{e,f,g}2332# Commit B: z/{b,c,d/{e,f,g,h},i}2333# Expected: y/{b,c,i}, x/w/{e,f,g,h}2334# NOTE: The only reason this one is interesting is because when a directory2335# is split into multiple other directories, we determine by the weight2336# of which one had the most paths going to it. A naive implementation2337# of that could take the new file in commit B at z/i to x/w/i or x/i.23382339test_expect_success '9a-setup: Inner renamed directory within outer renamed directory''2340 test_create_repo 9a &&2341 (2342 cd 9a &&23432344 mkdir -p z/d &&2345 echo b >z/b &&2346 echo c >z/c &&2347 echo e >z/d/e &&2348 echo f >z/d/f &&2349 echo g >z/d/g &&2350 git add z &&2351 test_tick &&2352 git commit -m "O" &&23532354 git branch O &&2355 git branch A &&2356 git branch B &&23572358 git checkout A &&2359 mkdir x &&2360 git mv z/d x/w &&2361 git mv z y &&2362 test_tick &&2363 git commit -m "A" &&23642365 git checkout B &&2366 echo h >z/d/h &&2367 echo i >z/i &&2368 git add z &&2369 test_tick &&2370 git commit -m "B"2371 )2372'23732374test_expect_success '9a-check: Inner renamed directory within outer renamed directory''2375 (2376 cd 9a &&23772378 git checkout A^0 &&23792380 git merge -s recursive B^0 &&23812382 git ls-files -s >out &&2383 test_line_count = 7 out &&2384 git ls-files -u >out &&2385 test_line_count = 0 out &&2386 git ls-files -o >out &&2387 test_line_count = 1 out &&23882389 git rev-parse >actual \2390 HEAD:y/b HEAD:y/c HEAD:y/i &&2391 git rev-parse >expect \2392 O:z/b O:z/c B:z/i &&2393 test_cmp expect actual &&23942395 git rev-parse >actual \2396 HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&2397 git rev-parse >expect \2398 O:z/d/e O:z/d/f O:z/d/g B:z/d/h &&2399 test_cmp expect actual2400 )2401'24022403# Testcase 9b, Transitive rename with content merge2404# (Related to testcase 1c)2405# Commit O: z/{b,c}, x/d_12406# Commit A: y/{b,c}, x/d_22407# Commit B: z/{b,c,d_3}2408# Expected: y/{b,c,d_merged}24092410test_expect_success '9b-setup: Transitive rename with content merge''2411 test_create_repo 9b &&2412 (2413 cd 9b &&24142415 mkdir z &&2416 echo b >z/b &&2417 echo c >z/c &&2418 mkdir x &&2419 test_seq 1 10 >x/d &&2420 git add z x &&2421 test_tick &&2422 git commit -m "O" &&24232424 git branch O &&2425 git branch A &&2426 git branch B &&24272428 git checkout A &&2429 git mv z y &&2430 test_seq 1 11 >x/d &&2431 git add x/d &&2432 test_tick &&2433 git commit -m "A" &&24342435 git checkout B &&2436 test_seq 0 10 >x/d &&2437 git mv x/d z/d &&2438 git add z/d &&2439 test_tick &&2440 git commit -m "B"2441 )2442'24432444test_expect_success '9b-check: Transitive rename with content merge''2445 (2446 cd 9b &&24472448 git checkout A^0 &&24492450 git merge -s recursive B^0 &&24512452 git ls-files -s >out &&2453 test_line_count = 3 out &&24542455 test_seq 0 11 >expected &&2456 test_cmp expected y/d &&2457 git add expected &&2458 git rev-parse >actual \2459 HEAD:y/b HEAD:y/c HEAD:y/d &&2460 git rev-parse >expect \2461 O:z/b O:z/c :0:expected &&2462 test_cmp expect actual &&2463 test_must_fail git rev-parse HEAD:x/d &&2464 test_must_fail git rev-parse HEAD:z/d &&2465 test_path_is_missing z/d &&24662467 test$(git rev-parse HEAD:y/d)!=$(git rev-parse O:x/d)&&2468 test$(git rev-parse HEAD:y/d)!=$(git rev-parse A:x/d)&&2469 test$(git rev-parse HEAD:y/d)!=$(git rev-parse B:z/d)2470 )2471'24722473# Testcase 9c, Doubly transitive rename?2474# (Related to testcase 1c, 7e, and 9d)2475# Commit O: z/{b,c}, x/{d,e}, w/f2476# Commit A: y/{b,c}, x/{d,e,f,g}2477# Commit B: z/{b,c,d,e}, w/f2478# Expected: y/{b,c,d,e}, x/{f,g}2479#2480# NOTE: x/f and x/g may be slightly confusing here. The rename from w/f to2481# x/f is clear. Let's look beyond that. Here's the logic:2482# Commit B renamed x/ -> z/2483# Commit A renamed z/ -> y/2484# So, we could possibly further rename x/f to z/f to y/f, a doubly2485# transient rename. However, where does it end? We can chain these2486# indefinitely (see testcase 9d). What if there is a D/F conflict2487# at z/f/ or y/f/? Or just another file conflict at one of those2488# paths? In the case of an N-long chain of transient renamings,2489# where do we "abort" the rename at? Can the user make sense of2490# the resulting conflict and resolve it?2491#2492# To avoid this confusion I use the simple rule that if the other side2493# of history did a directory rename to a path that your side renamed2494# away, then ignore that particular rename from the other side of2495# history for any implicit directory renames.24962497test_expect_success '9c-setup: Doubly transitive rename?''2498 test_create_repo 9c &&2499 (2500 cd 9c &&25012502 mkdir z &&2503 echo b >z/b &&2504 echo c >z/c &&2505 mkdir x &&2506 echo d >x/d &&2507 echo e >x/e &&2508 mkdir w &&2509 echo f >w/f &&2510 git add z x w &&2511 test_tick &&2512 git commit -m "O" &&25132514 git branch O &&2515 git branch A &&2516 git branch B &&25172518 git checkout A &&2519 git mv z y &&2520 git mv w/f x/ &&2521 echo g >x/g &&2522 git add x/g &&2523 test_tick &&2524 git commit -m "A" &&25252526 git checkout B &&2527 git mv x/d z/d &&2528 git mv x/e z/e &&2529 test_tick &&2530 git commit -m "B"2531 )2532'25332534test_expect_success '9c-check: Doubly transitive rename?''2535 (2536 cd 9c &&25372538 git checkout A^0 &&25392540 git merge -s recursive B^0 >out &&2541 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&25422543 git ls-files -s >out &&2544 test_line_count = 6 out &&2545 git ls-files -o >out &&2546 test_line_count = 1 out &&25472548 git rev-parse >actual \2549 HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&2550 git rev-parse >expect \2551 O:z/b O:z/c O:x/d O:x/e O:w/f A:x/g &&2552 test_cmp expect actual2553 )2554'25552556# Testcase 9d, N-fold transitive rename?2557# (Related to testcase 9c...and 1c and 7e)2558# Commit O: z/a, y/b, x/c, w/d, v/e, u/f2559# Commit A: y/{a,b}, w/{c,d}, u/{e,f}2560# Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f2561# Expected: <see NOTE first>2562#2563# NOTE: z/ -> y/ (in commit A)2564# y/ -> x/ (in commit B)2565# x/ -> w/ (in commit A)2566# w/ -> v/ (in commit B)2567# v/ -> u/ (in commit A)2568# So, if we add a file to z, say z/t, where should it end up? In u?2569# What if there's another file or directory named 't' in one of the2570# intervening directories and/or in u itself? Also, shouldn't the2571# same logic that places 't' in u/ also move ALL other files to u/?2572# What if there are file or directory conflicts in any of them? If2573# we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames2574# like this, would the user have any hope of understanding any2575# conflicts or how their working tree ended up? I think not, so I'm2576# ruling out N-ary transitive renames for N>1.2577#2578# Therefore our expected result is:2579# z/t, y/a, x/b, w/c, u/d, u/e, u/f2580# The reason that v/d DOES get transitively renamed to u/d is that u/ isn't2581# renamed somewhere. A slightly sub-optimal result, but it uses fairly2582# simple rules that are consistent with what we need for all the other2583# testcases and simplifies things for the user.25842585test_expect_success '9d-setup: N-way transitive rename?''2586 test_create_repo 9d &&2587 (2588 cd 9d &&25892590 mkdir z y x w v u &&2591 echo a >z/a &&2592 echo b >y/b &&2593 echo c >x/c &&2594 echo d >w/d &&2595 echo e >v/e &&2596 echo f >u/f &&2597 git add z y x w v u &&2598 test_tick &&2599 git commit -m "O" &&26002601 git branch O &&2602 git branch A &&2603 git branch B &&26042605 git checkout A &&2606 git mv z/a y/ &&2607 git mv x/c w/ &&2608 git mv v/e u/ &&2609 test_tick &&2610 git commit -m "A" &&26112612 git checkout B &&2613 echo t >z/t &&2614 git mv y/b x/ &&2615 git mv w/d v/ &&2616 git add z/t &&2617 test_tick &&2618 git commit -m "B"2619 )2620'26212622test_expect_success '9d-check: N-way transitive rename?''2623 (2624 cd 9d &&26252626 git checkout A^0 &&26272628 git merge -s recursive B^0 >out &&2629 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&2630 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&2631 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&2632 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&26332634 git ls-files -s >out &&2635 test_line_count = 7 out &&2636 git ls-files -o >out &&2637 test_line_count = 1 out &&26382639 git rev-parse >actual \2640 HEAD:z/t \2641 HEAD:y/a HEAD:x/b HEAD:w/c \2642 HEAD:u/d HEAD:u/e HEAD:u/f &&2643 git rev-parse >expect \2644 B:z/t \2645 O:z/a O:y/b O:x/c \2646 O:w/d O:v/e A:u/f &&2647 test_cmp expect actual2648 )2649'26502651# Testcase 9e, N-to-1 whammo2652# (Related to testcase 9c...and 1c and 7e)2653# Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}2654# Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}2655# Commit B: combined/{a,b,d,e,g,h,j,k}2656# Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,2657# dir1/yo, dir2/yo, dir3/yo, dirN/yo26582659test_expect_success '9e-setup: N-to-1 whammo''2660 test_create_repo 9e &&2661 (2662 cd 9e &&26632664 mkdir dir1 dir2 dir3 dirN &&2665 echo a >dir1/a &&2666 echo b >dir1/b &&2667 echo d >dir2/d &&2668 echo e >dir2/e &&2669 echo g >dir3/g &&2670 echo h >dir3/h &&2671 echo j >dirN/j &&2672 echo k >dirN/k &&2673 git add dir* &&2674 test_tick &&2675 git commit -m "O" &&26762677 git branch O &&2678 git branch A &&2679 git branch B &&26802681 git checkout A &&2682 echo c >dir1/c &&2683 echo yo >dir1/yo &&2684 echo f >dir2/f &&2685 echo yo >dir2/yo &&2686 echo i >dir3/i &&2687 echo yo >dir3/yo &&2688 echo l >dirN/l &&2689 echo yo >dirN/yo &&2690 git add dir* &&2691 test_tick &&2692 git commit -m "A" &&26932694 git checkout B &&2695 git mv dir1 combined &&2696 git mv dir2/* combined/ &&2697 git mv dir3/* combined/ &&2698 git mv dirN/* combined/ &&2699 test_tick &&2700 git commit -m "B"2701 )2702'27032704test_expect_success C_LOCALE_OUTPUT '9e-check: N-to-1 whammo''2705 (2706 cd 9e &&27072708 git checkout A^0 &&27092710 test_must_fail git merge -s recursive B^0 >out &&2711 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&2712 grep -q dir1/yo error_line &&2713 grep -q dir2/yo error_line &&2714 grep -q dir3/yo error_line &&2715 grep -q dirN/yo error_line &&27162717 git ls-files -s >out &&2718 test_line_count = 16 out &&2719 git ls-files -u >out &&2720 test_line_count = 0 out &&2721 git ls-files -o >out &&2722 test_line_count = 2 out &&27232724 git rev-parse >actual \2725 :0:combined/a :0:combined/b :0:combined/c \2726 :0:combined/d :0:combined/e :0:combined/f \2727 :0:combined/g :0:combined/h :0:combined/i \2728 :0:combined/j :0:combined/k :0:combined/l &&2729 git rev-parse >expect \2730 O:dir1/a O:dir1/b A:dir1/c \2731 O:dir2/d O:dir2/e A:dir2/f \2732 O:dir3/g O:dir3/h A:dir3/i \2733 O:dirN/j O:dirN/k A:dirN/l &&2734 test_cmp expect actual &&27352736 git rev-parse >actual \2737 :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&2738 git rev-parse >expect \2739 A:dir1/yo A:dir2/yo A:dir3/yo A:dirN/yo &&2740 test_cmp expect actual2741 )2742'27432744# Testcase 9f, Renamed directory that only contained immediate subdirs2745# (Related to testcases 1e & 9g)2746# Commit O: goal/{a,b}/$more_files2747# Commit A: priority/{a,b}/$more_files2748# Commit B: goal/{a,b}/$more_files, goal/c2749# Expected: priority/{a,b}/$more_files, priority/c27502751test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs''2752 test_create_repo 9f &&2753 (2754 cd 9f &&27552756 mkdir -p goal/a &&2757 mkdir -p goal/b &&2758 echo foo >goal/a/foo &&2759 echo bar >goal/b/bar &&2760 echo baz >goal/b/baz &&2761 git add goal &&2762 test_tick &&2763 git commit -m "O" &&27642765 git branch O &&2766 git branch A &&2767 git branch B &&27682769 git checkout A &&2770 git mv goal/ priority &&2771 test_tick &&2772 git commit -m "A" &&27732774 git checkout B &&2775 echo c >goal/c &&2776 git add goal/c &&2777 test_tick &&2778 git commit -m "B"2779 )2780'27812782test_expect_success '9f-check: Renamed directory that only contained immediate subdirs''2783 (2784 cd 9f &&27852786 git checkout A^0 &&27872788 git merge -s recursive B^0 &&27892790 git ls-files -s >out &&2791 test_line_count = 4 out &&27922793 git rev-parse >actual \2794 HEAD:priority/a/foo \2795 HEAD:priority/b/bar \2796 HEAD:priority/b/baz \2797 HEAD:priority/c &&2798 git rev-parse >expect \2799 O:goal/a/foo \2800 O:goal/b/bar \2801 O:goal/b/baz \2802 B:goal/c &&2803 test_cmp expect actual &&2804 test_must_fail git rev-parse HEAD:goal/c2805 )2806'28072808# Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed2809# (Related to testcases 1e & 9f)2810# Commit O: goal/{a,b}/$more_files2811# Commit A: priority/{alpha,bravo}/$more_files2812# Commit B: goal/{a,b}/$more_files, goal/c2813# Expected: priority/{alpha,bravo}/$more_files, priority/c28142815test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed''2816 test_create_repo 9g &&2817 (2818 cd 9g &&28192820 mkdir -p goal/a &&2821 mkdir -p goal/b &&2822 echo foo >goal/a/foo &&2823 echo bar >goal/b/bar &&2824 echo baz >goal/b/baz &&2825 git add goal &&2826 test_tick &&2827 git commit -m "O" &&28282829 git branch O &&2830 git branch A &&2831 git branch B &&28322833 git checkout A &&2834 mkdir priority &&2835 git mv goal/a/ priority/alpha &&2836 git mv goal/b/ priority/beta &&2837 rmdir goal/ &&2838 test_tick &&2839 git commit -m "A" &&28402841 git checkout B &&2842 echo c >goal/c &&2843 git add goal/c &&2844 test_tick &&2845 git commit -m "B"2846 )2847'28482849test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed''2850 (2851 cd 9g &&28522853 git checkout A^0 &&28542855 git merge -s recursive B^0 &&28562857 git ls-files -s >out &&2858 test_line_count = 4 out &&28592860 git rev-parse >actual \2861 HEAD:priority/alpha/foo \2862 HEAD:priority/beta/bar \2863 HEAD:priority/beta/baz \2864 HEAD:priority/c &&2865 git rev-parse >expect \2866 O:goal/a/foo \2867 O:goal/b/bar \2868 O:goal/b/baz \2869 B:goal/c &&2870 test_cmp expect actual &&2871 test_must_fail git rev-parse HEAD:goal/c2872 )2873'28742875# Testcase 9h, Avoid implicit rename if involved as source on other side2876# (Extremely closely related to testcase 3a)2877# Commit O: z/{b,c,d_1}2878# Commit A: z/{b,c,d_2}2879# Commit B: y/{b,c}, x/d_12880# Expected: y/{b,c}, x/d_22881# NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with2882# a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)2883test_expect_success '9h-setup: Avoid dir rename on merely modified path''2884 test_create_repo 9h &&2885 (2886 cd 9h &&28872888 mkdir z &&2889 echo b >z/b &&2890 echo c >z/c &&2891 printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&2892 git add z &&2893 test_tick &&2894 git commit -m "O" &&28952896 git branch O &&2897 git branch A &&2898 git branch B &&28992900 git checkout A &&2901 test_tick &&2902 echo more >>z/d &&2903 git add z/d &&2904 git commit -m "A" &&29052906 git checkout B &&2907 mkdir y &&2908 mkdir x &&2909 git mv z/b y/ &&2910 git mv z/c y/ &&2911 git mv z/d x/ &&2912 rmdir z &&2913 test_tick &&2914 git commit -m "B"2915 )2916'29172918test_expect_failure '9h-check: Avoid dir rename on merely modified path''2919 (2920 cd 9h &&29212922 git checkout A^0 &&29232924 git merge -s recursive B^0 &&29252926 git ls-files -s >out &&2927 test_line_count = 3 out &&29282929 git rev-parse >actual \2930 HEAD:y/b HEAD:y/c HEAD:x/d &&2931 git rev-parse >expect \2932 O:z/b O:z/c A:z/d &&2933 test_cmp expect actual2934 )2935'29362937###########################################################################2938# Rules suggested by section 9:2939#2940# If the other side of history did a directory rename to a path that your2941# side renamed away, then ignore that particular rename from the other2942# side of history for any implicit directory renames.2943###########################################################################29442945###########################################################################2946# SECTION 10: Handling untracked files2947#2948# unpack_trees(), upon which the recursive merge algorithm is based, aborts2949# the operation if untracked or dirty files would be deleted or overwritten2950# by the merge. Unfortunately, unpack_trees() does not understand renames,2951# and if it doesn't abort, then it muddies up the working directory before2952# we even get to the point of detecting renames, so we need some special2953# handling, at least in the case of directory renames.2954###########################################################################29552956# Testcase 10a, Overwrite untracked: normal rename/delete2957# Commit O: z/{b,c_1}2958# Commit A: z/b + untracked z/c + untracked z/d2959# Commit B: z/{b,d_1}2960# Expected: Aborted Merge +2961# ERROR_MSG(untracked working tree files would be overwritten by merge)29622963test_expect_success '10a-setup: Overwrite untracked with normal rename/delete''2964 test_create_repo 10a &&2965 (2966 cd 10a &&29672968 mkdir z &&2969 echo b >z/b &&2970 echo c >z/c &&2971 git add z &&2972 test_tick &&2973 git commit -m "O" &&29742975 git branch O &&2976 git branch A &&2977 git branch B &&29782979 git checkout A &&2980 git rm z/c &&2981 test_tick &&2982 git commit -m "A" &&29832984 git checkout B &&2985 git mv z/c z/d &&2986 test_tick &&2987 git commit -m "B"2988 )2989'29902991test_expect_success '10a-check: Overwrite untracked with normal rename/delete''2992 (2993 cd 10a &&29942995 git checkout A^0 &&2996 echo very >z/c &&2997 echo important >z/d &&29982999 test_must_fail git merge -s recursive B^0 >out 2>err &&3000 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&30013002 git ls-files -s >out &&3003 test_line_count = 1 out &&3004 git ls-files -o >out &&3005 test_line_count = 4 out &&30063007 echo very >expect &&3008 test_cmp expect z/c &&30093010 echo important >expect &&3011 test_cmp expect z/d &&30123013 git rev-parse HEAD:z/b >actual &&3014 git rev-parse O:z/b >expect &&3015 test_cmp expect actual3016 )3017'30183019# Testcase 10b, Overwrite untracked: dir rename + delete3020# Commit O: z/{b,c_1}3021# Commit A: y/b + untracked y/{c,d,e}3022# Commit B: z/{b,d_1,e}3023# Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +3024# z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +3025# ERROR_MSG(refusing to lose untracked file at 'y/d')30263027test_expect_success '10b-setup: Overwrite untracked with dir rename + delete''3028 test_create_repo 10b &&3029 (3030 cd 10b &&30313032 mkdir z &&3033 echo b >z/b &&3034 echo c >z/c &&3035 git add z &&3036 test_tick &&3037 git commit -m "O" &&30383039 git branch O &&3040 git branch A &&3041 git branch B &&30423043 git checkout A &&3044 git rm z/c &&3045 git mv z/ y/ &&3046 test_tick &&3047 git commit -m "A" &&30483049 git checkout B &&3050 git mv z/c z/d &&3051 echo e >z/e &&3052 git add z/e &&3053 test_tick &&3054 git commit -m "B"3055 )3056'30573058test_expect_success '10b-check: Overwrite untracked with dir rename + delete''3059 (3060 cd 10b &&30613062 git checkout A^0 &&3063 echo very >y/c &&3064 echo important >y/d &&3065 echo contents >y/e &&30663067 test_must_fail git merge -s recursive B^0 >out 2>err &&3068 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&3069 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&30703071 git ls-files -s >out &&3072 test_line_count = 3 out &&3073 git ls-files -u >out &&3074 test_line_count = 2 out &&3075 git ls-files -o >out &&3076 test_line_count = 5 out &&30773078 git rev-parse >actual \3079 :0:y/b :3:y/d :3:y/e &&3080 git rev-parse >expect \3081 O:z/b O:z/c B:z/e &&3082 test_cmp expect actual &&30833084 echo very >expect &&3085 test_cmp expect y/c &&30863087 echo important >expect &&3088 test_cmp expect y/d &&30893090 echo contents >expect &&3091 test_cmp expect y/e3092 )3093'30943095# Testcase 10c, Overwrite untracked: dir rename/rename(1to2)3096# Commit O: z/{a,b}, x/{c,d}3097# Commit A: y/{a,b}, w/c, x/d + different untracked y/c3098# Commit B: z/{a,b,c}, x/d3099# Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +3100# CONFLICT(rename/rename) x/c -> w/c vs y/c +3101# y/c~B^0 +3102# ERROR_MSG(Refusing to lose untracked file at y/c)31033104test_expect_success '10c-setup: Overwrite untracked with dir rename/rename(1to2)''3105 test_create_repo 10c &&3106 (3107 cd 10c &&31083109 mkdir z x &&3110 echo a >z/a &&3111 echo b >z/b &&3112 echo c >x/c &&3113 echo d >x/d &&3114 git add z x &&3115 test_tick &&3116 git commit -m "O" &&31173118 git branch O &&3119 git branch A &&3120 git branch B &&31213122 git checkout A &&3123 mkdir w &&3124 git mv x/c w/c &&3125 git mv z/ y/ &&3126 test_tick &&3127 git commit -m "A" &&31283129 git checkout B &&3130 git mv x/c z/ &&3131 test_tick &&3132 git commit -m "B"3133 )3134'31353136test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)''3137 (3138 cd 10c &&31393140 git checkout A^0 &&3141 echo important >y/c &&31423143 test_must_fail git merge -s recursive B^0 >out 2>err &&3144 test_i18ngrep "CONFLICT (rename/rename)" out &&3145 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&31463147 git ls-files -s >out &&3148 test_line_count = 6 out &&3149 git ls-files -u >out &&3150 test_line_count = 3 out &&3151 git ls-files -o >out &&3152 test_line_count = 3 out &&31533154 git rev-parse >actual \3155 :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&3156 git rev-parse >expect \3157 O:z/a O:z/b O:x/d O:x/c O:x/c O:x/c &&3158 test_cmp expect actual &&31593160 git hash-object y/c~B^0 >actual &&3161 git rev-parse O:x/c >expect &&3162 test_cmp expect actual &&31633164 echo important >expect &&3165 test_cmp expect y/c3166 )3167'31683169# Testcase 10d, Delete untracked w/ dir rename/rename(2to1)3170# Commit O: z/{a,b,c_1}, x/{d,e,f_2}3171# Commit A: y/{a,b}, x/{d,e,f_2,wham_1} + untracked y/wham3172# Commit B: z/{a,b,c_1,wham_2}, y/{d,e}3173# Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+3174# CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham3175# ERROR_MSG(Refusing to lose untracked file at y/wham)31763177test_expect_success '10d-setup: Delete untracked with dir rename/rename(2to1)''3178 test_create_repo 10d &&3179 (3180 cd 10d &&31813182 mkdir z x &&3183 echo a >z/a &&3184 echo b >z/b &&3185 echo c >z/c &&3186 echo d >x/d &&3187 echo e >x/e &&3188 echo f >x/f &&3189 git add z x &&3190 test_tick &&3191 git commit -m "O" &&31923193 git branch O &&3194 git branch A &&3195 git branch B &&31963197 git checkout A &&3198 git mv z/c x/wham &&3199 git mv z/ y/ &&3200 test_tick &&3201 git commit -m "A" &&32023203 git checkout B &&3204 git mv x/f z/wham &&3205 git mv x/ y/ &&3206 test_tick &&3207 git commit -m "B"3208 )3209'32103211test_expect_success '10d-check: Delete untracked with dir rename/rename(2to1)''3212 (3213 cd 10d &&32143215 git checkout A^0 &&3216 echo important >y/wham &&32173218 test_must_fail git merge -s recursive B^0 >out 2>err &&3219 test_i18ngrep "CONFLICT (rename/rename)" out &&3220 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&32213222 git ls-files -s >out &&3223 test_line_count = 6 out &&3224 git ls-files -u >out &&3225 test_line_count = 2 out &&3226 git ls-files -o >out &&3227 test_line_count = 4 out &&32283229 git rev-parse >actual \3230 :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&3231 git rev-parse >expect \3232 O:z/a O:z/b O:x/d O:x/e O:z/c O:x/f &&3233 test_cmp expect actual &&32343235 test_must_fail git rev-parse :1:y/wham &&32363237 echo important >expect &&3238 test_cmp expect y/wham &&32393240 git hash-object >actual \3241 y/wham~B^0 y/wham~HEAD &&3242 git rev-parse >expect \3243 O:x/f O:z/c &&3244 test_cmp expect actual3245 )3246'32473248# Testcase 10e, Does git complain about untracked file that's not in the way?3249# Commit O: z/{a,b}3250# Commit A: y/{a,b} + untracked z/c3251# Commit B: z/{a,b,c}3252# Expected: y/{a,b,c} + untracked z/c32533254test_expect_success '10e-setup: Does git complain about untracked file that is not really in the way?''3255 test_create_repo 10e &&3256 (3257 cd 10e &&32583259 mkdir z &&3260 echo a >z/a &&3261 echo b >z/b &&3262 git add z &&3263 test_tick &&3264 git commit -m "O" &&32653266 git branch O &&3267 git branch A &&3268 git branch B &&32693270 git checkout A &&3271 git mv z/ y/ &&3272 test_tick &&3273 git commit -m "A" &&32743275 git checkout B &&3276 echo c >z/c &&3277 git add z/c &&3278 test_tick &&3279 git commit -m "B"3280 )3281'32823283test_expect_failure '10e-check: Does git complain about untracked file that is not really in the way?''3284 (3285 cd 10e &&32863287 git checkout A^0 &&3288 mkdir z &&3289 echo random >z/c &&32903291 git merge -s recursive B^0 >out 2>err &&3292 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&32933294 git ls-files -s >out &&3295 test_line_count = 3 out &&3296 git ls-files -u >out &&3297 test_line_count = 0 out &&3298 git ls-files -o >out &&3299 test_line_count = 3 out &&33003301 git rev-parse >actual \3302 :0:y/a :0:y/b :0:y/c &&3303 git rev-parse >expect \3304 O:z/a O:z/b B:z/c &&3305 test_cmp expect actual &&33063307 echo random >expect &&3308 test_cmp expect z/c3309 )3310'33113312###########################################################################3313# SECTION 11: Handling dirty (not up-to-date) files3314#3315# unpack_trees(), upon which the recursive merge algorithm is based, aborts3316# the operation if untracked or dirty files would be deleted or overwritten3317# by the merge. Unfortunately, unpack_trees() does not understand renames,3318# and if it doesn't abort, then it muddies up the working directory before3319# we even get to the point of detecting renames, so we need some special3320# handling. This was true even of normal renames, but there are additional3321# codepaths that need special handling with directory renames. Add3322# testcases for both renamed-by-directory-rename-detection and standard3323# rename cases.3324###########################################################################33253326# Testcase 11a, Avoid losing dirty contents with simple rename3327# Commit O: z/{a,b_v1},3328# Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods3329# Commit B: z/{a,b_v2}3330# Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +3331# z/a, staged version of z/c has sha1sum matching B:z/b_v2,3332# z/c~HEAD with contents of B:z/b_v2,3333# z/c with uncommitted mods on top of A:z/c_v133343335test_expect_success '11a-setup: Avoid losing dirty contents with simple rename''3336 test_create_repo 11a &&3337 (3338 cd 11a &&33393340 mkdir z &&3341 echo a >z/a &&3342 test_seq 1 10 >z/b &&3343 git add z &&3344 test_tick &&3345 git commit -m "O" &&33463347 git branch O &&3348 git branch A &&3349 git branch B &&33503351 git checkout A &&3352 git mv z/b z/c &&3353 test_tick &&3354 git commit -m "A" &&33553356 git checkout B &&3357 echo 11 >>z/b &&3358 git add z/b &&3359 test_tick &&3360 git commit -m "B"3361 )3362'33633364test_expect_success '11a-check: Avoid losing dirty contents with simple rename''3365 (3366 cd 11a &&33673368 git checkout A^0 &&3369 echo stuff >>z/c &&33703371 test_must_fail git merge -s recursive B^0 >out 2>err &&3372 test_i18ngrep "Refusing to lose dirty file at z/c" out &&33733374 test_seq 1 10 >expected &&3375 echo stuff >>expected &&3376 test_cmp expected z/c &&33773378 git ls-files -s >out &&3379 test_line_count = 2 out &&3380 git ls-files -u >out &&3381 test_line_count = 1 out &&3382 git ls-files -o >out &&3383 test_line_count = 4 out &&33843385 git rev-parse >actual \3386 :0:z/a :2:z/c &&3387 git rev-parse >expect \3388 O:z/a B:z/b &&3389 test_cmp expect actual &&33903391 git hash-object z/c~HEAD >actual &&3392 git rev-parse B:z/b >expect &&3393 test_cmp expect actual3394 )3395'33963397# Testcase 11b, Avoid losing dirty file involved in directory rename3398# Commit O: z/a, x/{b,c_v1}3399# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods3400# Commit B: y/a, x/{b,c_v2}3401# Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,3402# ERROR_MSG(Refusing to lose dirty file at z/c)340334043405test_expect_success '11b-setup: Avoid losing dirty file involved in directory rename''3406 test_create_repo 11b &&3407 (3408 cd 11b &&34093410 mkdir z x &&3411 echo a >z/a &&3412 echo b >x/b &&3413 test_seq 1 10 >x/c &&3414 git add z x &&3415 test_tick &&3416 git commit -m "O" &&34173418 git branch O &&3419 git branch A &&3420 git branch B &&34213422 git checkout A &&3423 git mv x/c z/c &&3424 test_tick &&3425 git commit -m "A" &&34263427 git checkout B &&3428 git mv z y &&3429 echo 11 >>x/c &&3430 git add x/c &&3431 test_tick &&3432 git commit -m "B"3433 )3434'34353436test_expect_success '11b-check: Avoid losing dirty file involved in directory rename''3437 (3438 cd 11b &&34393440 git checkout A^0 &&3441 echo stuff >>z/c &&34423443 git merge -s recursive B^0 >out 2>err &&3444 test_i18ngrep "Refusing to lose dirty file at z/c" out &&34453446 grep -q stuff z/c &&3447 test_seq 1 10 >expected &&3448 echo stuff >>expected &&3449 test_cmp expected z/c &&34503451 git ls-files -s >out &&3452 test_line_count = 3 out &&3453 git ls-files -u >out &&3454 test_line_count = 0 out &&3455 git ls-files -m >out &&3456 test_line_count = 0 out &&3457 git ls-files -o >out &&3458 test_line_count = 4 out &&34593460 git rev-parse >actual \3461 :0:x/b :0:y/a :0:y/c &&3462 git rev-parse >expect \3463 O:x/b O:z/a B:x/c &&3464 test_cmp expect actual &&34653466 git hash-object y/c >actual &&3467 git rev-parse B:x/c >expect &&3468 test_cmp expect actual3469 )3470'34713472# Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict3473# Commit O: y/a, x/{b,c_v1}3474# Commit A: y/{a,c_v1}, x/b, and y/c_v1 has uncommitted mods3475# Commit B: y/{a,c/d}, x/{b,c_v2}3476# Expected: Abort_msg("following files would be overwritten by merge") +3477# y/c left untouched (still has uncommitted mods)34783479test_expect_success '11c-setup: Avoid losing not-uptodate with rename + D/F conflict''3480 test_create_repo 11c &&3481 (3482 cd 11c &&34833484 mkdir y x &&3485 echo a >y/a &&3486 echo b >x/b &&3487 test_seq 1 10 >x/c &&3488 git add y x &&3489 test_tick &&3490 git commit -m "O" &&34913492 git branch O &&3493 git branch A &&3494 git branch B &&34953496 git checkout A &&3497 git mv x/c y/c &&3498 test_tick &&3499 git commit -m "A" &&35003501 git checkout B &&3502 mkdir y/c &&3503 echo d >y/c/d &&3504 echo 11 >>x/c &&3505 git add x/c y/c/d &&3506 test_tick &&3507 git commit -m "B"3508 )3509'35103511test_expect_success '11c-check: Avoid losing not-uptodate with rename + D/F conflict''3512 (3513 cd 11c &&35143515 git checkout A^0 &&3516 echo stuff >>y/c &&35173518 test_must_fail git merge -s recursive B^0 >out 2>err &&3519 test_i18ngrep "following files would be overwritten by merge" err &&35203521 grep -q stuff y/c &&3522 test_seq 1 10 >expected &&3523 echo stuff >>expected &&3524 test_cmp expected y/c &&35253526 git ls-files -s >out &&3527 test_line_count = 3 out &&3528 git ls-files -u >out &&3529 test_line_count = 0 out &&3530 git ls-files -m >out &&3531 test_line_count = 1 out &&3532 git ls-files -o >out &&3533 test_line_count = 3 out3534 )3535'35363537# Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict3538# Commit O: z/a, x/{b,c_v1}3539# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods3540# Commit B: y/{a,c/d}, x/{b,c_v2}3541# Expected: D/F: y/c_v2 vs y/c/d) +3542# Warning_Msg("Refusing to lose dirty file at z/c) +3543# y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods35443545test_expect_success '11d-setup: Avoid losing not-uptodate with rename + D/F conflict''3546 test_create_repo 11d &&3547 (3548 cd 11d &&35493550 mkdir z x &&3551 echo a >z/a &&3552 echo b >x/b &&3553 test_seq 1 10 >x/c &&3554 git add z x &&3555 test_tick &&3556 git commit -m "O" &&35573558 git branch O &&3559 git branch A &&3560 git branch B &&35613562 git checkout A &&3563 git mv x/c z/c &&3564 test_tick &&3565 git commit -m "A" &&35663567 git checkout B &&3568 git mv z y &&3569 mkdir y/c &&3570 echo d >y/c/d &&3571 echo 11 >>x/c &&3572 git add x/c y/c/d &&3573 test_tick &&3574 git commit -m "B"3575 )3576'35773578test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conflict''3579 (3580 cd 11d &&35813582 git checkout A^0 &&3583 echo stuff >>z/c &&35843585 test_must_fail git merge -s recursive B^0 >out 2>err &&3586 test_i18ngrep "Refusing to lose dirty file at z/c" out &&35873588 grep -q stuff z/c &&3589 test_seq 1 10 >expected &&3590 echo stuff >>expected &&3591 test_cmp expected z/c35923593 git ls-files -s >out &&3594 test_line_count = 4 out &&3595 git ls-files -u >out &&3596 test_line_count = 1 out &&3597 git ls-files -o >out &&3598 test_line_count = 5 out &&35993600 git rev-parse >actual \3601 :0:x/b :0:y/a :0:y/c/d :3:y/c &&3602 git rev-parse >expect \3603 O:x/b O:z/a B:y/c/d B:x/c &&3604 test_cmp expect actual &&36053606 git hash-object y/c~HEAD >actual &&3607 git rev-parse B:x/c >expect &&3608 test_cmp expect actual3609 )3610'36113612# Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add3613# Commit O: z/{a,b}, x/{c_1,d}3614# Commit A: y/{a,b,c_2}, x/d, w/c_1, and y/c_2 has uncommitted mods3615# Commit B: z/{a,b,c_1}, x/d3616# Expected: Failed Merge; y/{a,b} + x/d +3617# CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +3618# ERROR_MSG(Refusing to lose dirty file at y/c)3619# y/c~B^0 has O:x/c_1 contents3620# y/c~HEAD has A:y/c_2 contents3621# y/c has dirty file from before merge36223623test_expect_success '11e-setup: Avoid deleting not-uptodate with dir rename/rename(1to2)/add''3624 test_create_repo 11e &&3625 (3626 cd 11e &&36273628 mkdir z x &&3629 echo a >z/a &&3630 echo b >z/b &&3631 echo c >x/c &&3632 echo d >x/d &&3633 git add z x &&3634 test_tick &&3635 git commit -m "O" &&36363637 git branch O &&3638 git branch A &&3639 git branch B &&36403641 git checkout A &&3642 git mv z/ y/ &&3643 echo different >y/c &&3644 mkdir w &&3645 git mv x/c w/ &&3646 git add y/c &&3647 test_tick &&3648 git commit -m "A" &&36493650 git checkout B &&3651 git mv x/c z/ &&3652 test_tick &&3653 git commit -m "B"3654 )3655'36563657test_expect_success '11e-check: Avoid deleting not-uptodate with dir rename/rename(1to2)/add''3658 (3659 cd 11e &&36603661 git checkout A^0 &&3662 echo mods >>y/c &&36633664 test_must_fail git merge -s recursive B^0 >out 2>err &&3665 test_i18ngrep "CONFLICT (rename/rename)" out &&3666 test_i18ngrep "Refusing to lose dirty file at y/c" out &&36673668 git ls-files -s >out &&3669 test_line_count = 7 out &&3670 git ls-files -u >out &&3671 test_line_count = 4 out &&3672 git ls-files -o >out &&3673 test_line_count = 4 out &&36743675 echo different >expected &&3676 echo mods >>expected &&3677 test_cmp expected y/c &&36783679 git rev-parse >actual \3680 :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&3681 git rev-parse >expect \3682 O:z/a O:z/b O:x/d O:x/c O:x/c A:y/c O:x/c &&3683 test_cmp expect actual &&36843685 git hash-object >actual \3686 y/c~B^0 y/c~HEAD &&3687 git rev-parse >expect \3688 O:x/c A:y/c &&3689 test_cmp expect actual3690 )3691'36923693# Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)3694# Commit O: z/{a,b}, x/{c_1,d_2}3695# Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods3696# Commit B: z/{a,b,wham_2}, x/c_13697# Expected: Failed Merge; y/{a,b} + untracked y/{wham~B^0,wham~B^HEAD} +3698# y/wham with dirty changes from before merge +3699# CONFLICT(rename/rename) x/c vs x/d -> y/wham3700# ERROR_MSG(Refusing to lose dirty file at y/wham)37013702test_expect_success '11f-setup: Avoid deleting not-uptodate with dir rename/rename(2to1)''3703 test_create_repo 11f &&3704 (3705 cd 11f &&37063707 mkdir z x &&3708 echo a >z/a &&3709 echo b >z/b &&3710 test_seq 1 10 >x/c &&3711 echo d >x/d &&3712 git add z x &&3713 test_tick &&3714 git commit -m "O" &&37153716 git branch O &&3717 git branch A &&3718 git branch B &&37193720 git checkout A &&3721 git mv z/ y/ &&3722 git mv x/c y/wham &&3723 test_tick &&3724 git commit -m "A" &&37253726 git checkout B &&3727 git mv x/d z/wham &&3728 test_tick &&3729 git commit -m "B"3730 )3731'37323733test_expect_success '11f-check: Avoid deleting not-uptodate with dir rename/rename(2to1)''3734 (3735 cd 11f &&37363737 git checkout A^0 &&3738 echo important >>y/wham &&37393740 test_must_fail git merge -s recursive B^0 >out 2>err &&3741 test_i18ngrep "CONFLICT (rename/rename)" out &&3742 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&37433744 git ls-files -s >out &&3745 test_line_count = 4 out &&3746 git ls-files -u >out &&3747 test_line_count = 2 out &&3748 git ls-files -o >out &&3749 test_line_count = 4 out &&37503751 test_seq 1 10 >expected &&3752 echo important >>expected &&3753 test_cmp expected y/wham &&37543755 test_must_fail git rev-parse :1:y/wham &&3756 git hash-object >actual \3757 y/wham~B^0 y/wham~HEAD &&3758 git rev-parse >expect \3759 O:x/d O:x/c &&3760 test_cmp expect actual &&37613762 git rev-parse >actual \3763 :0:y/a :0:y/b :2:y/wham :3:y/wham &&3764 git rev-parse >expect \3765 O:z/a O:z/b O:x/c O:x/d &&3766 test_cmp expect actual3767 )3768'37693770###########################################################################3771# SECTION 12: Everything else3772#3773# Tests suggested by others. Tests added after implementation completed3774# and submitted. Grab bag.3775###########################################################################37763777# Testcase 12a, Moving one directory hierarchy into another3778# (Related to testcase 9a)3779# Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}3780# Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}3781# Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}3782# Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}37833784test_expect_success '12a-setup: Moving one directory hierarchy into another''3785 test_create_repo 12a &&3786 (3787 cd 12a &&37883789 mkdir -p node1 node2 &&3790 echo leaf1 >node1/leaf1 &&3791 echo leaf2 >node1/leaf2 &&3792 echo leaf3 >node2/leaf3 &&3793 echo leaf4 >node2/leaf4 &&3794 git add node1 node2 &&3795 test_tick &&3796 git commit -m "O" &&37973798 git branch O &&3799 git branch A &&3800 git branch B &&38013802 git checkout A &&3803 git mv node2/ node1/ &&3804 test_tick &&3805 git commit -m "A" &&38063807 git checkout B &&3808 echo leaf5 >node1/leaf5 &&3809 echo leaf6 >node2/leaf6 &&3810 git add node1 node2 &&3811 test_tick &&3812 git commit -m "B"3813 )3814'38153816test_expect_success '12a-check: Moving one directory hierarchy into another''3817 (3818 cd 12a &&38193820 git checkout A^0 &&38213822 git merge -s recursive B^0 &&38233824 git ls-files -s >out &&3825 test_line_count = 6 out &&38263827 git rev-parse >actual \3828 HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \3829 HEAD:node1/node2/leaf3 \3830 HEAD:node1/node2/leaf4 \3831 HEAD:node1/node2/leaf6 &&3832 git rev-parse >expect \3833 O:node1/leaf1 O:node1/leaf2 B:node1/leaf5 \3834 O:node2/leaf3 \3835 O:node2/leaf4 \3836 B:node2/leaf6 &&3837 test_cmp expect actual3838 )3839'38403841# Testcase 12b, Moving two directory hierarchies into each other3842# (Related to testcases 1c and 12c)3843# Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}3844# Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}3845# Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}3846# Expected: node1/node2/node1/{leaf1, leaf2},3847# node2/node1/node2/{leaf3, leaf4}3848# NOTE: Without directory renames, we would expect3849# node2/node1/{leaf1, leaf2},3850# node1/node2/{leaf3, leaf4}3851# with directory rename detection, we note that3852# commit A renames node2/ -> node1/node2/3853# commit B renames node1/ -> node2/node1/3854# therefore, applying those directory renames to the initial result3855# (making all four paths experience a transitive renaming), yields3856# the expected result.3857#3858# You may ask, is it weird to have two directories rename each other?3859# To which, I can do no more than shrug my shoulders and say that3860# even simple rules give weird results when given weird inputs.38613862test_expect_success '12b-setup: Moving one directory hierarchy into another''3863 test_create_repo 12b &&3864 (3865 cd 12b &&38663867 mkdir -p node1 node2 &&3868 echo leaf1 >node1/leaf1 &&3869 echo leaf2 >node1/leaf2 &&3870 echo leaf3 >node2/leaf3 &&3871 echo leaf4 >node2/leaf4 &&3872 git add node1 node2 &&3873 test_tick &&3874 git commit -m "O" &&38753876 git branch O &&3877 git branch A &&3878 git branch B &&38793880 git checkout A &&3881 git mv node2/ node1/ &&3882 test_tick &&3883 git commit -m "A" &&38843885 git checkout B &&3886 git mv node1/ node2/ &&3887 test_tick &&3888 git commit -m "B"3889 )3890'38913892test_expect_failure '12b-check: Moving one directory hierarchy into another''3893 (3894 cd 12b &&38953896 git checkout A^0 &&38973898 git merge -s recursive B^0 &&38993900 git ls-files -s >out &&3901 test_line_count = 4 out &&39023903 git rev-parse >actual \3904 HEAD:node1/node2/node1/leaf1 \3905 HEAD:node1/node2/node1/leaf2 \3906 HEAD:node2/node1/node2/leaf3 \3907 HEAD:node2/node1/node2/leaf4 &&3908 git rev-parse >expect \3909 O:node1/leaf1 \3910 O:node1/leaf2 \3911 O:node2/leaf3 \3912 O:node2/leaf4 &&3913 test_cmp expect actual3914 )3915'39163917# Testcase 12c, Moving two directory hierarchies into each other w/ content merge3918# (Related to testcase 12b)3919# Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}3920# Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}}3921# Commit B: node2/{node1/{leaf1_3, leaf2_3}, leaf3_3, leaf4_3}3922# Expected: Content merge conflicts for each of:3923# node1/node2/node1/{leaf1, leaf2},3924# node2/node1/node2/{leaf3, leaf4}3925# NOTE: This is *exactly* like 12c, except that every path is modified on3926# each side of the merge.39273928test_expect_success '12c-setup: Moving one directory hierarchy into another w/ content merge''3929 test_create_repo 12c &&3930 (3931 cd 12c &&39323933 mkdir -p node1 node2 &&3934 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&3935 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&3936 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&3937 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&3938 git add node1 node2 &&3939 test_tick &&3940 git commit -m "O" &&39413942 git branch O &&3943 git branch A &&3944 git branch B &&39453946 git checkout A &&3947 git mv node2/ node1/ &&3948 for i in `git ls-files`; do echo side A >>$i; done &&3949 git add -u &&3950 test_tick &&3951 git commit -m "A" &&39523953 git checkout B &&3954 git mv node1/ node2/ &&3955 for i in `git ls-files`; do echo side B >>$i; done &&3956 git add -u &&3957 test_tick &&3958 git commit -m "B"3959 )3960'39613962test_expect_failure '12c-check: Moving one directory hierarchy into another w/ content merge''3963 (3964 cd 12c &&39653966 git checkout A^0 &&39673968 test_must_fail git merge -s recursive B^0 &&39693970 git ls-files -u >out &&3971 test_line_count = 12 out &&39723973 git rev-parse >actual \3974 :1:node1/node2/node1/leaf1 \3975 :1:node1/node2/node1/leaf2 \3976 :1:node2/node1/node2/leaf3 \3977 :1:node2/node1/node2/leaf4 \3978 :2:node1/node2/node1/leaf1 \3979 :2:node1/node2/node1/leaf2 \3980 :2:node2/node1/node2/leaf3 \3981 :2:node2/node1/node2/leaf4 \3982 :3:node1/node2/node1/leaf1 \3983 :3:node1/node2/node1/leaf2 \3984 :3:node2/node1/node2/leaf3 \3985 :3:node2/node1/node2/leaf4 &&3986 git rev-parse >expect \3987 O:node1/leaf1 \3988 O:node1/leaf2 \3989 O:node2/leaf3 \3990 O:node2/leaf4 \3991 A:node1/leaf1 \3992 A:node1/leaf2 \3993 A:node1/node2/leaf3 \3994 A:node1/node2/leaf4 \3995 B:node2/node1/leaf1 \3996 B:node2/node1/leaf2 \3997 B:node2/leaf3 \3998 B:node2/leaf4 &&3999 test_cmp expect actual4000 )4001'40024003test_done