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