t / t6036-recursive-corner-cases.shon commit Merge branch 'nd/the-index-final' (7589e63)
   1#!/bin/sh
   2
   3test_description='recursive merge corner cases involving criss-cross merges'
   4
   5. ./test-lib.sh
   6
   7#
   8#  L1  L2
   9#   o---o
  10#  / \ / \
  11# o   X   ?
  12#  \ / \ /
  13#   o---o
  14#  R1  R2
  15#
  16
  17test_expect_success 'setup basic criss-cross + rename with no modifications' '
  18        test_create_repo basic-rename &&
  19        (
  20                cd basic-rename &&
  21
  22                ten="0 1 2 3 4 5 6 7 8 9" &&
  23                for i in $ten
  24                do
  25                        echo line $i in a sample file
  26                done >one &&
  27                for i in $ten
  28                do
  29                        echo line $i in another sample file
  30                done >two &&
  31                git add one two &&
  32                test_tick && git commit -m initial &&
  33
  34                git branch L1 &&
  35                git checkout -b R1 &&
  36                git mv one three &&
  37                test_tick && git commit -m R1 &&
  38
  39                git checkout L1 &&
  40                git mv two three &&
  41                test_tick && git commit -m L1 &&
  42
  43                git checkout L1^0 &&
  44                test_tick && git merge -s ours R1 &&
  45                git tag L2 &&
  46
  47                git checkout R1^0 &&
  48                test_tick && git merge -s ours L1 &&
  49                git tag R2
  50        )
  51'
  52
  53test_expect_success 'merge simple rename+criss-cross with no modifications' '
  54        (
  55                cd basic-rename &&
  56
  57                git reset --hard &&
  58                git checkout L2^0 &&
  59
  60                test_must_fail git merge -s recursive R2^0 &&
  61
  62                git ls-files -s >out &&
  63                test_line_count = 2 out &&
  64                git ls-files -u >out &&
  65                test_line_count = 2 out &&
  66                git ls-files -o >out &&
  67                test_line_count = 1 out &&
  68
  69                git rev-parse >expect       \
  70                        L2:three   R2:three &&
  71                git rev-parse   >actual     \
  72                        :2:three   :3:three &&
  73                test_cmp expect actual
  74        )
  75'
  76
  77#
  78# Same as before, but modify L1 slightly:
  79#
  80#  L1m L2
  81#   o---o
  82#  / \ / \
  83# o   X   ?
  84#  \ / \ /
  85#   o---o
  86#  R1  R2
  87#
  88
  89test_expect_success 'setup criss-cross + rename merges with basic modification' '
  90        test_create_repo rename-modify &&
  91        (
  92                cd rename-modify &&
  93
  94                ten="0 1 2 3 4 5 6 7 8 9" &&
  95                for i in $ten
  96                do
  97                        echo line $i in a sample file
  98                done >one &&
  99                for i in $ten
 100                do
 101                        echo line $i in another sample file
 102                done >two &&
 103                git add one two &&
 104                test_tick && git commit -m initial &&
 105
 106                git branch L1 &&
 107                git checkout -b R1 &&
 108                git mv one three &&
 109                echo more >>two &&
 110                git add two &&
 111                test_tick && git commit -m R1 &&
 112
 113                git checkout L1 &&
 114                git mv two three &&
 115                test_tick && git commit -m L1 &&
 116
 117                git checkout L1^0 &&
 118                test_tick && git merge -s ours R1 &&
 119                git tag L2 &&
 120
 121                git checkout R1^0 &&
 122                test_tick && git merge -s ours L1 &&
 123                git tag R2
 124        )
 125'
 126
 127test_expect_success 'merge criss-cross + rename merges with basic modification' '
 128        (
 129                cd rename-modify &&
 130
 131                git checkout L2^0 &&
 132
 133                test_must_fail git merge -s recursive R2^0 &&
 134
 135                git ls-files -s >out &&
 136                test_line_count = 2 out &&
 137                git ls-files -u >out &&
 138                test_line_count = 2 out &&
 139                git ls-files -o >out &&
 140                test_line_count = 1 out &&
 141
 142                git rev-parse >expect       \
 143                        L2:three   R2:three &&
 144                git rev-parse   >actual     \
 145                        :2:three   :3:three &&
 146                test_cmp expect actual
 147        )
 148'
 149
 150#
 151# For the next test, we start with three commits in two lines of development
 152# which setup a rename/add conflict:
 153#   Commit A: File 'a' exists
 154#   Commit B: Rename 'a' -> 'new_a'
 155#   Commit C: Modify 'a', create different 'new_a'
 156# Later, two different people merge and resolve differently:
 157#   Commit D: Merge B & C, ignoring separately created 'new_a'
 158#   Commit E: Merge B & C making use of some piece of secondary 'new_a'
 159# Finally, someone goes to merge D & E.  Does git detect the conflict?
 160#
 161#      B   D
 162#      o---o
 163#     / \ / \
 164#  A o   X   ? F
 165#     \ / \ /
 166#      o---o
 167#      C   E
 168#
 169
 170test_expect_success 'setup differently handled merges of rename/add conflict' '
 171        test_create_repo rename-add &&
 172        (
 173                cd rename-add &&
 174
 175                printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a &&
 176                git add a &&
 177                test_tick && git commit -m A &&
 178
 179                git branch B &&
 180                git checkout -b C &&
 181                echo 10 >>a &&
 182                test_write_lines 0 1 2 3 4 5 6 7 foobar >new_a &&
 183                git add a new_a &&
 184                test_tick && git commit -m C &&
 185
 186                git checkout B &&
 187                git mv a new_a &&
 188                test_tick && git commit -m B &&
 189
 190                git checkout B^0 &&
 191                test_must_fail git merge C &&
 192                git show :2:new_a >new_a &&
 193                git add new_a &&
 194                test_tick && git commit -m D &&
 195                git tag D &&
 196
 197                git checkout C^0 &&
 198                test_must_fail git merge B &&
 199                test_write_lines 0 1 2 3 4 5 6 7 bad_merge >new_a &&
 200                git add -u &&
 201                test_tick && git commit -m E &&
 202                git tag E
 203        )
 204'
 205
 206test_expect_success 'git detects differently handled merges conflict' '
 207        (
 208                cd rename-add &&
 209
 210                git checkout D^0 &&
 211
 212                test_must_fail git merge -s recursive E^0 &&
 213
 214                git ls-files -s >out &&
 215                test_line_count = 3 out &&
 216                git ls-files -u >out &&
 217                test_line_count = 3 out &&
 218                git ls-files -o >out &&
 219                test_line_count = 1 out &&
 220
 221                git rev-parse >expect       \
 222                        C:new_a  D:new_a  E:new_a &&
 223                git rev-parse   >actual     \
 224                        :1:new_a :2:new_a :3:new_a &&
 225                test_cmp expect actual &&
 226
 227                # Test that the two-way merge in new_a is as expected
 228                git cat-file -p D:new_a >ours &&
 229                git cat-file -p E:new_a >theirs &&
 230                >empty &&
 231                test_must_fail git merge-file \
 232                        -L "HEAD" \
 233                        -L "" \
 234                        -L "E^0" \
 235                        ours empty theirs &&
 236                sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect &&
 237                git hash-object new_a >actual &&
 238                git hash-object ours  >expect &&
 239                test_cmp expect actual
 240        )
 241'
 242
 243# Repeat the above testcase with precisely the same setup, other than with
 244# the two merge bases having different orderings of commit timestamps so
 245# that they are reversed in the order they are provided to merge-recursive,
 246# so that we can improve code coverage.
 247test_expect_success 'git detects differently handled merges conflict, swapped' '
 248        (
 249                cd rename-add &&
 250
 251                # Difference #1: Do cleanup from previous testrun
 252                git reset --hard &&
 253                git clean -fdqx &&
 254
 255                # Difference #2: Change commit timestamps
 256                btime=$(git log --no-walk --date=raw --format=%cd B | awk "{print \$1}") &&
 257                ctime=$(git log --no-walk --date=raw --format=%cd C | awk "{print \$1}") &&
 258                newctime=$(($btime+1)) &&
 259                git fast-export --no-data --all | sed -e s/$ctime/$newctime/ | git fast-import --force --quiet &&
 260                # End of differences; rest is copy-paste of last test
 261
 262                git checkout D^0 &&
 263                test_must_fail git merge -s recursive E^0 &&
 264
 265                git ls-files -s >out &&
 266                test_line_count = 3 out &&
 267                git ls-files -u >out &&
 268                test_line_count = 3 out &&
 269                git ls-files -o >out &&
 270                test_line_count = 1 out &&
 271
 272                git rev-parse >expect       \
 273                        C:new_a  D:new_a  E:new_a &&
 274                git rev-parse   >actual     \
 275                        :1:new_a :2:new_a :3:new_a &&
 276                test_cmp expect actual &&
 277
 278                # Test that the two-way merge in new_a is as expected
 279                git cat-file -p D:new_a >ours &&
 280                git cat-file -p E:new_a >theirs &&
 281                >empty &&
 282                test_must_fail git merge-file \
 283                        -L "HEAD" \
 284                        -L "" \
 285                        -L "E^0" \
 286                        ours empty theirs &&
 287                sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect &&
 288                git hash-object new_a >actual &&
 289                git hash-object ours  >expect &&
 290                test_cmp expect actual
 291        )
 292'
 293
 294#
 295# criss-cross + modify/delete:
 296#
 297#      B   D
 298#      o---o
 299#     / \ / \
 300#  A o   X   ? F
 301#     \ / \ /
 302#      o---o
 303#      C   E
 304#
 305#   Commit A: file with contents 'A\n'
 306#   Commit B: file with contents 'B\n'
 307#   Commit C: file not present
 308#   Commit D: file with contents 'B\n'
 309#   Commit E: file not present
 310#
 311# Merging commits D & E should result in modify/delete conflict.
 312
 313test_expect_success 'setup criss-cross + modify/delete resolved differently' '
 314        test_create_repo modify-delete &&
 315        (
 316                cd modify-delete &&
 317
 318                echo A >file &&
 319                git add file &&
 320                test_tick &&
 321                git commit -m A &&
 322
 323                git branch B &&
 324                git checkout -b C &&
 325                git rm file &&
 326                test_tick &&
 327                git commit -m C &&
 328
 329                git checkout B &&
 330                echo B >file &&
 331                git add file &&
 332                test_tick &&
 333                git commit -m B &&
 334
 335                git checkout B^0 &&
 336                test_must_fail git merge C &&
 337                echo B >file &&
 338                git add file &&
 339                test_tick &&
 340                git commit -m D &&
 341                git tag D &&
 342
 343                git checkout C^0 &&
 344                test_must_fail git merge B &&
 345                git rm file &&
 346                test_tick &&
 347                git commit -m E &&
 348                git tag E
 349        )
 350'
 351
 352test_expect_success 'git detects conflict merging criss-cross+modify/delete' '
 353        (
 354                cd modify-delete &&
 355
 356                git checkout D^0 &&
 357
 358                test_must_fail git merge -s recursive E^0 &&
 359
 360                git ls-files -s >out &&
 361                test_line_count = 2 out &&
 362                git ls-files -u >out &&
 363                test_line_count = 2 out &&
 364
 365                git rev-parse >expect       \
 366                        master:file  B:file &&
 367                git rev-parse   >actual      \
 368                        :1:file      :2:file &&
 369                test_cmp expect actual
 370        )
 371'
 372
 373test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' '
 374        (
 375                cd modify-delete &&
 376
 377                git reset --hard &&
 378                git checkout E^0 &&
 379
 380                test_must_fail git merge -s recursive D^0 &&
 381
 382                git ls-files -s >out &&
 383                test_line_count = 2 out &&
 384                git ls-files -u >out &&
 385                test_line_count = 2 out &&
 386
 387                git rev-parse >expect       \
 388                        master:file  B:file &&
 389                git rev-parse   >actual      \
 390                        :1:file      :3:file &&
 391                test_cmp expect actual
 392        )
 393'
 394
 395#      SORRY FOR THE SUPER LONG DESCRIPTION, BUT THIS NEXT ONE IS HAIRY
 396#
 397# criss-cross + d/f conflict via add/add:
 398#   Commit A: Neither file 'a' nor directory 'a/' exists.
 399#   Commit B: Introduce 'a'
 400#   Commit C: Introduce 'a/file'
 401#   Commit D1: Merge B & C, keeping 'a'    and deleting 'a/'
 402#   Commit E1: Merge B & C, deleting 'a' but keeping 'a/file'
 403#
 404#      B   D1 or D2
 405#      o---o
 406#     / \ / \
 407#  A o   X   ? F
 408#     \ / \ /
 409#      o---o
 410#      C   E1 or E2 or E3
 411#
 412# I'll describe D2, E2, & E3 (which are alternatives for D1 & E1) more below...
 413#
 414# Merging D1 & E1 requires we first create a virtual merge base X from
 415# merging A & B in memory.  There are several possibilities for the merge-base:
 416#   1: Keep both 'a' and 'a/file' (assuming crazy filesystem allowing a tree
 417#      with a directory and file at same path): results in merge of D1 & E1
 418#      being clean with both files deleted.  Bad (no conflict detected).
 419#   2: Keep 'a' but not 'a/file': Merging D1 & E1 is clean and matches E1.  Bad.
 420#   3: Keep 'a/file' but not 'a': Merging D1 & E1 is clean and matches D1.  Bad.
 421#   4: Keep neither file: Merging D1 & E1 reports the D/F add/add conflict.
 422#
 423# So 4 sounds good for this case, but if we were to merge D1 & E3, where E3
 424# is defined as:
 425#   Commit E3: Merge B & C, keeping modified a, and deleting a/
 426# then we'd get an add/add conflict for 'a', which seems suboptimal.  A little
 427# creativity leads us to an alternate choice:
 428#   5: Keep 'a' as 'a~$UNIQUE' and a/file; results:
 429#        Merge D1 & E1: rename/delete conflict for 'a'; a/file silently deleted
 430#        Merge D1 & E3 is clean, as expected.
 431#
 432# So choice 5 at least provides some kind of conflict for the original case,
 433# and can merge cleanly as expected with D1 and E3.  It also made things just
 434# slightly funny for merging D1 and e$, where E4 is defined as:
 435#   Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/'
 436# in this case, we'll get a rename/rename(1to2) conflict because a~$UNIQUE
 437# gets renamed to 'a' in D1 and to 'a2' in E4.  But that's better than having
 438# two files (both 'a' and 'a2') sitting around without the user being notified
 439# that we could detect they were related and need to be merged.  Also, choice
 440# 5 makes the handling of 'a/file' seem suboptimal.  What if we were to merge
 441# D2 and E4, where D2 is:
 442#   Commit D2: Merge B & C, renaming 'a'->'a2', keeping 'a/file'
 443# This would result in a clean merge with 'a2' having three-way merged
 444# contents (good), and deleting 'a/' (bad) -- it doesn't detect the
 445# conflict in how the different sides treated a/file differently.
 446# Continuing down the creative route:
 447#   6: Keep 'a' as 'a~$UNIQUE1' and keep 'a/' as 'a~$UNIQUE2/'; results:
 448#        Merge D1 & E1: rename/delete conflict for 'a' and each path under 'a/'.
 449#        Merge D1 & E3: clean, as expected.
 450#        Merge D1 & E4: rename/rename(1to2) conflict on 'a' vs 'a2'.
 451#        Merge D2 & E4: clean for 'a2', rename/delete for a/file
 452#
 453# Choice 6 could cause rename detection to take longer (providing more targets
 454# that need to be searched).  Also, the conflict message for each path under
 455# 'a/' might be annoying unless we can detect it at the directory level, print
 456# it once, and then suppress it for individual filepaths underneath.
 457#
 458#
 459# As of time of writing, git uses choice 5.  Directory rename detection and
 460# rename detection performance improvements might make choice 6 a desirable
 461# improvement.  But we can at least document where we fall short for now...
 462#
 463#
 464# Historically, this testcase also used:
 465#   Commit E2: Merge B & C, deleting 'a' but keeping slightly modified 'a/file'
 466# The merge of D1 & E2 is very similar to D1 & E1 -- it has similar issues for
 467# path 'a', but should always result in a modify/delete conflict for path
 468# 'a/file'.  These tests ran the two merges
 469#   D1 & E1
 470#   D1 & E2
 471# in both directions, to check for directional issues with D/F conflict
 472# handling. Later we added
 473#   D1 & E3
 474#   D1 & E4
 475#   D2 & E4
 476# for good measure, though we only ran those one way because we had pretty
 477# good confidence in merge-recursive's directional handling of D/F issues.
 478#
 479# Just to summarize all the intermediate merge commits:
 480#   Commit D1: Merge B & C, keeping a    and deleting a/
 481#   Commit D2: Merge B & C, renaming a->a2, keeping a/file
 482#   Commit E1: Merge B & C, deleting a but keeping a/file
 483#   Commit E2: Merge B & C, deleting a but keeping slightly modified a/file
 484#   Commit E3: Merge B & C, keeping modified a, and deleting a/
 485#   Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/'
 486#
 487
 488test_expect_success 'setup differently handled merges of directory/file conflict' '
 489        test_create_repo directory-file &&
 490        (
 491                cd directory-file &&
 492
 493                >ignore-me &&
 494                git add ignore-me &&
 495                test_tick &&
 496                git commit -m A &&
 497                git tag A &&
 498
 499                git branch B &&
 500                git checkout -b C &&
 501                mkdir a &&
 502                test_write_lines a b c d e f g >a/file &&
 503                git add a/file &&
 504                test_tick &&
 505                git commit -m C &&
 506
 507                git checkout B &&
 508                test_write_lines 1 2 3 4 5 6 7 >a &&
 509                git add a &&
 510                test_tick &&
 511                git commit -m B &&
 512
 513                git checkout B^0 &&
 514                git merge -s ours -m D1 C^0 &&
 515                git tag D1 &&
 516
 517                git checkout B^0 &&
 518                test_must_fail git merge C^0 &&
 519                git clean -fd &&
 520                git rm -rf a/ &&
 521                git rm a &&
 522                git cat-file -p B:a >a2 &&
 523                git add a2 &&
 524                git commit -m D2 &&
 525                git tag D2 &&
 526
 527                git checkout C^0 &&
 528                git merge -s ours -m E1 B^0 &&
 529                git tag E1 &&
 530
 531                git checkout C^0 &&
 532                git merge -s ours -m E2 B^0 &&
 533                test_write_lines a b c d e f g h >a/file &&
 534                git add a/file &&
 535                git commit --amend -C HEAD &&
 536                git tag E2 &&
 537
 538                git checkout C^0 &&
 539                test_must_fail git merge B^0 &&
 540                git clean -fd &&
 541                git rm -rf a/ &&
 542                test_write_lines 1 2 3 4 5 6 7 8 >a &&
 543                git add a &&
 544                git commit -m E3 &&
 545                git tag E3 &&
 546
 547                git checkout C^0 &&
 548                test_must_fail git merge B^0 &&
 549                git clean -fd &&
 550                git rm -rf a/ &&
 551                git rm a &&
 552                test_write_lines 1 2 3 4 5 6 7 8 >a2 &&
 553                git add a2 &&
 554                git commit -m E4 &&
 555                git tag E4
 556        )
 557'
 558
 559test_expect_success 'merge of D1 & E1 fails but has appropriate contents' '
 560        test_when_finished "git -C directory-file reset --hard" &&
 561        test_when_finished "git -C directory-file clean -fdqx" &&
 562        (
 563                cd directory-file &&
 564
 565                git checkout D1^0 &&
 566
 567                test_must_fail git merge -s recursive E1^0 &&
 568
 569                git ls-files -s >out &&
 570                test_line_count = 2 out &&
 571                git ls-files -u >out &&
 572                test_line_count = 1 out &&
 573                git ls-files -o >out &&
 574                test_line_count = 1 out &&
 575
 576                git rev-parse >expect    \
 577                        A:ignore-me  B:a &&
 578                git rev-parse   >actual   \
 579                        :0:ignore-me :2:a &&
 580                test_cmp expect actual
 581        )
 582'
 583
 584test_expect_success 'merge of E1 & D1 fails but has appropriate contents' '
 585        test_when_finished "git -C directory-file reset --hard" &&
 586        test_when_finished "git -C directory-file clean -fdqx" &&
 587        (
 588                cd directory-file &&
 589
 590                git checkout E1^0 &&
 591
 592                test_must_fail git merge -s recursive D1^0 &&
 593
 594                git ls-files -s >out &&
 595                test_line_count = 2 out &&
 596                git ls-files -u >out &&
 597                test_line_count = 1 out &&
 598                git ls-files -o >out &&
 599                test_line_count = 1 out &&
 600
 601                git rev-parse >expect    \
 602                        A:ignore-me  B:a &&
 603                git rev-parse   >actual   \
 604                        :0:ignore-me :3:a &&
 605                test_cmp expect actual
 606        )
 607'
 608
 609test_expect_success 'merge of D1 & E2 fails but has appropriate contents' '
 610        test_when_finished "git -C directory-file reset --hard" &&
 611        test_when_finished "git -C directory-file clean -fdqx" &&
 612        (
 613                cd directory-file &&
 614
 615                git checkout D1^0 &&
 616
 617                test_must_fail git merge -s recursive E2^0 &&
 618
 619                git ls-files -s >out &&
 620                test_line_count = 4 out &&
 621                git ls-files -u >out &&
 622                test_line_count = 3 out &&
 623                git ls-files -o >out &&
 624                test_line_count = 2 out &&
 625
 626                git rev-parse >expect    \
 627                        B:a   E2:a/file  C:a/file   A:ignore-me &&
 628                git rev-parse   >actual   \
 629                        :2:a  :3:a/file  :1:a/file  :0:ignore-me &&
 630                test_cmp expect actual &&
 631
 632                test_path_is_file a~HEAD
 633        )
 634'
 635
 636test_expect_success 'merge of E2 & D1 fails but has appropriate contents' '
 637        test_when_finished "git -C directory-file reset --hard" &&
 638        test_when_finished "git -C directory-file clean -fdqx" &&
 639        (
 640                cd directory-file &&
 641
 642                git checkout E2^0 &&
 643
 644                test_must_fail git merge -s recursive D1^0 &&
 645
 646                git ls-files -s >out &&
 647                test_line_count = 4 out &&
 648                git ls-files -u >out &&
 649                test_line_count = 3 out &&
 650                git ls-files -o >out &&
 651                test_line_count = 2 out &&
 652
 653                git rev-parse >expect    \
 654                        B:a   E2:a/file  C:a/file   A:ignore-me &&
 655                git rev-parse   >actual   \
 656                        :3:a  :2:a/file  :1:a/file  :0:ignore-me &&
 657                test_cmp expect actual &&
 658
 659                test_path_is_file a~D1^0
 660        )
 661'
 662
 663test_expect_success 'merge of D1 & E3 succeeds' '
 664        test_when_finished "git -C directory-file reset --hard" &&
 665        test_when_finished "git -C directory-file clean -fdqx" &&
 666        (
 667                cd directory-file &&
 668
 669                git checkout D1^0 &&
 670
 671                git merge -s recursive E3^0 &&
 672
 673                git ls-files -s >out &&
 674                test_line_count = 2 out &&
 675                git ls-files -u >out &&
 676                test_line_count = 0 out &&
 677                git ls-files -o >out &&
 678                test_line_count = 1 out &&
 679
 680                git rev-parse >expect    \
 681                        A:ignore-me  E3:a &&
 682                git rev-parse   >actual   \
 683                        :0:ignore-me :0:a &&
 684                test_cmp expect actual
 685        )
 686'
 687
 688test_expect_success 'merge of D1 & E4 notifies user a and a2 are related' '
 689        test_when_finished "git -C directory-file reset --hard" &&
 690        test_when_finished "git -C directory-file clean -fdqx" &&
 691        (
 692                cd directory-file &&
 693
 694                git checkout D1^0 &&
 695
 696                test_must_fail git merge -s recursive E4^0 &&
 697
 698                git ls-files -s >out &&
 699                test_line_count = 4 out &&
 700                git ls-files -u >out &&
 701                test_line_count = 3 out &&
 702                git ls-files -o >out &&
 703                test_line_count = 1 out &&
 704
 705                git rev-parse >expect                  \
 706                        A:ignore-me  B:a   D1:a  E4:a2 &&
 707                git rev-parse   >actual                \
 708                        :0:ignore-me :1:a~Temporary\ merge\ branch\ 2  :2:a  :3:a2 &&
 709                test_cmp expect actual
 710        )
 711'
 712
 713test_expect_failure 'merge of D2 & E4 merges a2s & reports conflict for a/file' '
 714        test_when_finished "git -C directory-file reset --hard" &&
 715        test_when_finished "git -C directory-file clean -fdqx" &&
 716        (
 717                cd directory-file &&
 718
 719                git checkout D2^0 &&
 720
 721                test_must_fail git merge -s recursive E4^0 &&
 722
 723                git ls-files -s >out &&
 724                test_line_count = 3 out &&
 725                git ls-files -u >out &&
 726                test_line_count = 1 out &&
 727                git ls-files -o >out &&
 728                test_line_count = 1 out &&
 729
 730                git rev-parse >expect                 \
 731                        A:ignore-me  E4:a2  D2:a/file &&
 732                git rev-parse   >actual               \
 733                        :0:ignore-me :0:a2  :2:a/file &&
 734                test_cmp expect actual
 735        )
 736'
 737
 738#
 739# criss-cross with rename/rename(1to2)/modify followed by
 740# rename/rename(2to1)/modify:
 741#
 742#      B   D
 743#      o---o
 744#     / \ / \
 745#  A o   X   ? F
 746#     \ / \ /
 747#      o---o
 748#      C   E
 749#
 750#   Commit A: new file: a
 751#   Commit B: rename a->b, modifying by adding a line
 752#   Commit C: rename a->c
 753#   Commit D: merge B&C, resolving conflict by keeping contents in newname
 754#   Commit E: merge B&C, resolving conflict similar to D but adding another line
 755#
 756# There is a conflict merging B & C, but one of filename not of file
 757# content.  Whoever created D and E chose specific resolutions for that
 758# conflict resolution.  Now, since: (1) there is no content conflict
 759# merging B & C, (2) D does not modify that merged content further, and (3)
 760# both D & E resolve the name conflict in the same way, the modification to
 761# newname in E should not cause any conflicts when it is merged with D.
 762# (Note that this can be accomplished by having the virtual merge base have
 763# the merged contents of b and c stored in a file named a, which seems like
 764# the most logical choice anyway.)
 765#
 766# Comment from Junio: I do not necessarily agree with the choice "a", but
 767# it feels sound to say "B and C do not agree what the final pathname
 768# should be, but we know this content was derived from the common A:a so we
 769# use one path whose name is arbitrary in the virtual merge base X between
 770# D and E" and then further let the rename detection to notice that that
 771# arbitrary path gets renamed between X-D to "newname" and X-E also to
 772# "newname" to resolve it as both sides renaming it to the same new
 773# name. It is akin to what we do at the content level, i.e. "B and C do not
 774# agree what the final contents should be, so we leave the conflict marker
 775# but that may cancel out at the final merge stage".
 776
 777test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
 778        test_create_repo rename-squared-squared &&
 779        (
 780                cd rename-squared-squared &&
 781
 782                printf "1\n2\n3\n4\n5\n6\n" >a &&
 783                git add a &&
 784                git commit -m A &&
 785                git tag A &&
 786
 787                git checkout -b B A &&
 788                git mv a b &&
 789                echo 7 >>b &&
 790                git add -u &&
 791                git commit -m B &&
 792
 793                git checkout -b C A &&
 794                git mv a c &&
 795                git commit -m C &&
 796
 797                git checkout -q B^0 &&
 798                git merge --no-commit -s ours C^0 &&
 799                git mv b newname &&
 800                git commit -m "Merge commit C^0 into HEAD" &&
 801                git tag D &&
 802
 803                git checkout -q C^0 &&
 804                git merge --no-commit -s ours B^0 &&
 805                git mv c newname &&
 806                printf "7\n8\n" >>newname &&
 807                git add -u &&
 808                git commit -m "Merge commit B^0 into HEAD" &&
 809                git tag E
 810        )
 811'
 812
 813test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
 814        (
 815                cd rename-squared-squared &&
 816
 817                git checkout D^0 &&
 818
 819                git merge -s recursive E^0 &&
 820
 821                git ls-files -s >out &&
 822                test_line_count = 1 out &&
 823                git ls-files -u >out &&
 824                test_line_count = 0 out &&
 825                git ls-files -o >out &&
 826                test_line_count = 1 out &&
 827
 828                test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname)
 829        )
 830'
 831
 832#
 833# criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify:
 834#
 835#      B   D
 836#      o---o
 837#     / \ / \
 838#  A o   X   ? F
 839#     \ / \ /
 840#      o---o
 841#      C   E
 842#
 843#   Commit A: new file: a
 844#   Commit B: rename a->b
 845#   Commit C: rename a->c, add different a
 846#   Commit D: merge B&C, keeping b&c and (new) a modified at beginning
 847#   Commit E: merge B&C, keeping b&c and (new) a modified at end
 848#
 849# Merging commits D & E should result in no conflict; doing so correctly
 850# requires getting the virtual merge base (from merging B&C) right, handling
 851# renaming carefully (both in the virtual merge base and later), and getting
 852# content merge handled.
 853
 854test_expect_success 'setup criss-cross + rename/rename/add-source + modify/modify' '
 855        test_create_repo rename-rename-add-source &&
 856        (
 857                cd rename-rename-add-source &&
 858
 859                printf "lots\nof\nwords\nand\ncontent\n" >a &&
 860                git add a &&
 861                git commit -m A &&
 862                git tag A &&
 863
 864                git checkout -b B A &&
 865                git mv a b &&
 866                git commit -m B &&
 867
 868                git checkout -b C A &&
 869                git mv a c &&
 870                printf "2\n3\n4\n5\n6\n7\n" >a &&
 871                git add a &&
 872                git commit -m C &&
 873
 874                git checkout B^0 &&
 875                git merge --no-commit -s ours C^0 &&
 876                git checkout C -- a c &&
 877                mv a old_a &&
 878                echo 1 >a &&
 879                cat old_a >>a &&
 880                rm old_a &&
 881                git add -u &&
 882                git commit -m "Merge commit C^0 into HEAD" &&
 883                git tag D &&
 884
 885                git checkout C^0 &&
 886                git merge --no-commit -s ours B^0 &&
 887                git checkout B -- b &&
 888                echo 8 >>a &&
 889                git add -u &&
 890                git commit -m "Merge commit B^0 into HEAD" &&
 891                git tag E
 892        )
 893'
 894
 895test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
 896        (
 897                cd rename-rename-add-source &&
 898
 899                git checkout D^0 &&
 900
 901                git merge -s recursive E^0 &&
 902
 903                git ls-files -s >out &&
 904                test_line_count = 3 out &&
 905                git ls-files -u >out &&
 906                test_line_count = 0 out &&
 907                git ls-files -o >out &&
 908                test_line_count = 1 out &&
 909
 910                printf "1\n2\n3\n4\n5\n6\n7\n8\n" >correct &&
 911                git rev-parse >expect \
 912                        A:a   A:a     \
 913                        correct       &&
 914                git rev-parse   >actual  \
 915                        :0:b  :0:c       &&
 916                git hash-object >>actual \
 917                        a                &&
 918                test_cmp expect actual
 919        )
 920'
 921
 922#
 923# criss-cross with rename/rename(1to2)/add-dest + simple modify:
 924#
 925#      B   D
 926#      o---o
 927#     / \ / \
 928#  A o   X   ? F
 929#     \ / \ /
 930#      o---o
 931#      C   E
 932#
 933#   Commit A: new file: a
 934#   Commit B: rename a->b, add c
 935#   Commit C: rename a->c
 936#   Commit D: merge B&C, keeping A:a and B:c
 937#   Commit E: merge B&C, keeping A:a and slightly modified c from B
 938#
 939# Merging commits D & E should result in no conflict.  The virtual merge
 940# base of B & C needs to not delete B:c for that to work, though...
 941
 942test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' '
 943        test_create_repo rename-rename-add-dest &&
 944        (
 945                cd rename-rename-add-dest &&
 946
 947                >a &&
 948                git add a &&
 949                git commit -m A &&
 950                git tag A &&
 951
 952                git checkout -b B A &&
 953                git mv a b &&
 954                printf "1\n2\n3\n4\n5\n6\n7\n" >c &&
 955                git add c &&
 956                git commit -m B &&
 957
 958                git checkout -b C A &&
 959                git mv a c &&
 960                git commit -m C &&
 961
 962                git checkout B^0 &&
 963                git merge --no-commit -s ours C^0 &&
 964                git mv b a &&
 965                git commit -m "D is like B but renames b back to a" &&
 966                git tag D &&
 967
 968                git checkout B^0 &&
 969                git merge --no-commit -s ours C^0 &&
 970                git mv b a &&
 971                echo 8 >>c &&
 972                git add c &&
 973                git commit -m "E like D but has mod in c" &&
 974                git tag E
 975        )
 976'
 977
 978test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' '
 979        (
 980                cd rename-rename-add-dest &&
 981
 982                git checkout D^0 &&
 983
 984                git merge -s recursive E^0 &&
 985
 986                git ls-files -s >out &&
 987                test_line_count = 2 out &&
 988                git ls-files -u >out &&
 989                test_line_count = 0 out &&
 990                git ls-files -o >out &&
 991                test_line_count = 1 out &&
 992
 993                git rev-parse >expect \
 994                        A:a   E:c     &&
 995                git rev-parse   >actual \
 996                        :0:a  :0:c      &&
 997                test_cmp expect actual
 998        )
 999'
1000
1001#
1002# criss-cross with modify/modify on a symlink:
1003#
1004#      B   D
1005#      o---o
1006#     / \ / \
1007#  A o   X   ? F
1008#     \ / \ /
1009#      o---o
1010#      C   E
1011#
1012#   Commit A: simple simlink fickle->lagoon
1013#   Commit B: redirect fickle->disneyland
1014#   Commit C: redirect fickle->home
1015#   Commit D: merge B&C, resolving in favor of B
1016#   Commit E: merge B&C, resolving in favor of C
1017#
1018# This is an obvious modify/modify conflict for the symlink 'fickle'.  Can
1019# git detect it?
1020
1021test_expect_success 'setup symlink modify/modify' '
1022        test_create_repo symlink-modify-modify &&
1023        (
1024                cd symlink-modify-modify &&
1025
1026                test_ln_s_add lagoon fickle &&
1027                git commit -m A &&
1028                git tag A &&
1029
1030                git checkout -b B A &&
1031                git rm fickle &&
1032                test_ln_s_add disneyland fickle &&
1033                git commit -m B &&
1034
1035                git checkout -b C A &&
1036                git rm fickle &&
1037                test_ln_s_add home fickle &&
1038                git add fickle &&
1039                git commit -m C &&
1040
1041                git checkout -q B^0 &&
1042                git merge -s ours -m D C^0 &&
1043                git tag D &&
1044
1045                git checkout -q C^0 &&
1046                git merge -s ours -m E B^0 &&
1047                git tag E
1048        )
1049'
1050
1051test_expect_failure 'check symlink modify/modify' '
1052        (
1053                cd symlink-modify-modify &&
1054
1055                git checkout D^0 &&
1056
1057                test_must_fail git merge -s recursive E^0 &&
1058
1059                git ls-files -s >out &&
1060                test_line_count = 3 out &&
1061                git ls-files -u >out &&
1062                test_line_count = 3 out &&
1063                git ls-files -o >out &&
1064                test_line_count = 1 out
1065        )
1066'
1067
1068#
1069# criss-cross with add/add of a symlink:
1070#
1071#      B   D
1072#      o---o
1073#     / \ / \
1074#  A o   X   ? F
1075#     \ / \ /
1076#      o---o
1077#      C   E
1078#
1079#   Commit A: No symlink or path exists yet
1080#   Commit B: set up symlink: fickle->disneyland
1081#   Commit C: set up symlink: fickle->home
1082#   Commit D: merge B&C, resolving in favor of B
1083#   Commit E: merge B&C, resolving in favor of C
1084#
1085# This is an obvious add/add conflict for the symlink 'fickle'.  Can
1086# git detect it?
1087
1088test_expect_success 'setup symlink add/add' '
1089        test_create_repo symlink-add-add &&
1090        (
1091                cd symlink-add-add &&
1092
1093                touch ignoreme &&
1094                git add ignoreme &&
1095                git commit -m A &&
1096                git tag A &&
1097
1098                git checkout -b B A &&
1099                test_ln_s_add disneyland fickle &&
1100                git commit -m B &&
1101
1102                git checkout -b C A &&
1103                test_ln_s_add home fickle &&
1104                git add fickle &&
1105                git commit -m C &&
1106
1107                git checkout -q B^0 &&
1108                git merge -s ours -m D C^0 &&
1109                git tag D &&
1110
1111                git checkout -q C^0 &&
1112                git merge -s ours -m E B^0 &&
1113                git tag E
1114        )
1115'
1116
1117test_expect_failure 'check symlink add/add' '
1118        (
1119                cd symlink-add-add &&
1120
1121                git checkout D^0 &&
1122
1123                test_must_fail git merge -s recursive E^0 &&
1124
1125                git ls-files -s >out &&
1126                test_line_count = 2 out &&
1127                git ls-files -u >out &&
1128                test_line_count = 2 out &&
1129                git ls-files -o >out &&
1130                test_line_count = 1 out
1131        )
1132'
1133
1134#
1135# criss-cross with modify/modify on a submodule:
1136#
1137#      B   D
1138#      o---o
1139#     / \ / \
1140#  A o   X   ? F
1141#     \ / \ /
1142#      o---o
1143#      C   E
1144#
1145#   Commit A: simple submodule repo
1146#   Commit B: update repo
1147#   Commit C: update repo differently
1148#   Commit D: merge B&C, resolving in favor of B
1149#   Commit E: merge B&C, resolving in favor of C
1150#
1151# This is an obvious modify/modify conflict for the submodule 'repo'.  Can
1152# git detect it?
1153
1154test_expect_success 'setup submodule modify/modify' '
1155        test_create_repo submodule-modify-modify &&
1156        (
1157                cd submodule-modify-modify &&
1158
1159                test_create_repo submod &&
1160                (
1161                        cd submod &&
1162                        touch file-A &&
1163                        git add file-A &&
1164                        git commit -m A &&
1165                        git tag A &&
1166
1167                        git checkout -b B A &&
1168                        touch file-B &&
1169                        git add file-B &&
1170                        git commit -m B &&
1171                        git tag B &&
1172
1173                        git checkout -b C A &&
1174                        touch file-C &&
1175                        git add file-C &&
1176                        git commit -m C &&
1177                        git tag C
1178                ) &&
1179
1180                git -C submod reset --hard A &&
1181                git add submod &&
1182                git commit -m A &&
1183                git tag A &&
1184
1185                git checkout -b B A &&
1186                git -C submod reset --hard B &&
1187                git add submod &&
1188                git commit -m B &&
1189
1190                git checkout -b C A &&
1191                git -C submod reset --hard C &&
1192                git add submod &&
1193                git commit -m C &&
1194
1195                git checkout -q B^0 &&
1196                git merge -s ours -m D C^0 &&
1197                git tag D &&
1198
1199                git checkout -q C^0 &&
1200                git merge -s ours -m E B^0 &&
1201                git tag E
1202        )
1203'
1204
1205test_expect_failure 'check submodule modify/modify' '
1206        (
1207                cd submodule-modify-modify &&
1208
1209                git checkout D^0 &&
1210
1211                test_must_fail git merge -s recursive E^0 &&
1212
1213                git ls-files -s >out &&
1214                test_line_count = 3 out &&
1215                git ls-files -u >out &&
1216                test_line_count = 3 out &&
1217                git ls-files -o >out &&
1218                test_line_count = 1 out
1219        )
1220'
1221
1222#
1223# criss-cross with add/add on a submodule:
1224#
1225#      B   D
1226#      o---o
1227#     / \ / \
1228#  A o   X   ? F
1229#     \ / \ /
1230#      o---o
1231#      C   E
1232#
1233#   Commit A: nothing of note
1234#   Commit B: introduce submodule repo
1235#   Commit C: introduce submodule repo at different commit
1236#   Commit D: merge B&C, resolving in favor of B
1237#   Commit E: merge B&C, resolving in favor of C
1238#
1239# This is an obvious add/add conflict for the submodule 'repo'.  Can
1240# git detect it?
1241
1242test_expect_success 'setup submodule add/add' '
1243        test_create_repo submodule-add-add &&
1244        (
1245                cd submodule-add-add &&
1246
1247                test_create_repo submod &&
1248                (
1249                        cd submod &&
1250                        touch file-A &&
1251                        git add file-A &&
1252                        git commit -m A &&
1253                        git tag A &&
1254
1255                        git checkout -b B A &&
1256                        touch file-B &&
1257                        git add file-B &&
1258                        git commit -m B &&
1259                        git tag B &&
1260
1261                        git checkout -b C A &&
1262                        touch file-C &&
1263                        git add file-C &&
1264                        git commit -m C &&
1265                        git tag C
1266                ) &&
1267
1268                touch irrelevant-file &&
1269                git add irrelevant-file &&
1270                git commit -m A &&
1271                git tag A &&
1272
1273                git checkout -b B A &&
1274                git -C submod reset --hard B &&
1275                git add submod &&
1276                git commit -m B &&
1277
1278                git checkout -b C A &&
1279                git -C submod reset --hard C &&
1280                git add submod &&
1281                git commit -m C &&
1282
1283                git checkout -q B^0 &&
1284                git merge -s ours -m D C^0 &&
1285                git tag D &&
1286
1287                git checkout -q C^0 &&
1288                git merge -s ours -m E B^0 &&
1289                git tag E
1290        )
1291'
1292
1293test_expect_failure 'check submodule add/add' '
1294        (
1295                cd submodule-add-add &&
1296
1297                git checkout D^0 &&
1298
1299                test_must_fail git merge -s recursive E^0 &&
1300
1301                git ls-files -s >out &&
1302                test_line_count = 3 out &&
1303                git ls-files -u >out &&
1304                test_line_count = 2 out &&
1305                git ls-files -o >out &&
1306                test_line_count = 1 out
1307        )
1308'
1309
1310#
1311# criss-cross with conflicting entry types:
1312#
1313#      B   D
1314#      o---o
1315#     / \ / \
1316#  A o   X   ? F
1317#     \ / \ /
1318#      o---o
1319#      C   E
1320#
1321#   Commit A: nothing of note
1322#   Commit B: introduce submodule 'path'
1323#   Commit C: introduce symlink 'path'
1324#   Commit D: merge B&C, resolving in favor of B
1325#   Commit E: merge B&C, resolving in favor of C
1326#
1327# This is an obvious add/add conflict for 'path'.  Can git detect it?
1328
1329test_expect_success 'setup conflicting entry types (submodule vs symlink)' '
1330        test_create_repo submodule-symlink-add-add &&
1331        (
1332                cd submodule-symlink-add-add &&
1333
1334                test_create_repo path &&
1335                (
1336                        cd path &&
1337                        touch file-B &&
1338                        git add file-B &&
1339                        git commit -m B &&
1340                        git tag B
1341                ) &&
1342
1343                touch irrelevant-file &&
1344                git add irrelevant-file &&
1345                git commit -m A &&
1346                git tag A &&
1347
1348                git checkout -b B A &&
1349                git -C path reset --hard B &&
1350                git add path &&
1351                git commit -m B &&
1352
1353                git checkout -b C A &&
1354                rm -rf path/ &&
1355                test_ln_s_add irrelevant-file path &&
1356                git commit -m C &&
1357
1358                git checkout -q B^0 &&
1359                git merge -s ours -m D C^0 &&
1360                git tag D &&
1361
1362                git checkout -q C^0 &&
1363                git merge -s ours -m E B^0 &&
1364                git tag E
1365        )
1366'
1367
1368test_expect_failure 'check conflicting entry types (submodule vs symlink)' '
1369        (
1370                cd submodule-symlink-add-add &&
1371
1372                git checkout D^0 &&
1373
1374                test_must_fail git merge -s recursive E^0 &&
1375
1376                git ls-files -s >out &&
1377                test_line_count = 3 out &&
1378                git ls-files -u >out &&
1379                test_line_count = 2 out &&
1380                git ls-files -o >out &&
1381                test_line_count = 1 out
1382        )
1383'
1384
1385#
1386# criss-cross with regular files that have conflicting modes:
1387#
1388#      B   D
1389#      o---o
1390#     / \ / \
1391#  A o   X   ? F
1392#     \ / \ /
1393#      o---o
1394#      C   E
1395#
1396#   Commit A: nothing of note
1397#   Commit B: introduce file source_me.bash, not executable
1398#   Commit C: introduce file source_me.bash, executable
1399#   Commit D: merge B&C, resolving in favor of B
1400#   Commit E: merge B&C, resolving in favor of C
1401#
1402# This is an obvious add/add mode conflict.  Can git detect it?
1403
1404test_expect_success 'setup conflicting modes for regular file' '
1405        test_create_repo regular-file-mode-conflict &&
1406        (
1407                cd regular-file-mode-conflict &&
1408
1409                touch irrelevant-file &&
1410                git add irrelevant-file &&
1411                git commit -m A &&
1412                git tag A &&
1413
1414                git checkout -b B A &&
1415                echo "command_to_run" >source_me.bash &&
1416                git add source_me.bash &&
1417                git commit -m B &&
1418
1419                git checkout -b C A &&
1420                echo "command_to_run" >source_me.bash &&
1421                git add source_me.bash &&
1422                test_chmod +x source_me.bash &&
1423                git commit -m C &&
1424
1425                git checkout -q B^0 &&
1426                git merge -s ours -m D C^0 &&
1427                git tag D &&
1428
1429                git checkout -q C^0 &&
1430                git merge -s ours -m E B^0 &&
1431                git tag E
1432        )
1433'
1434
1435test_expect_failure 'check conflicting modes for regular file' '
1436        (
1437                cd regular-file-mode-conflict &&
1438
1439                git checkout D^0 &&
1440
1441                test_must_fail git merge -s recursive E^0 &&
1442
1443                git ls-files -s >out &&
1444                test_line_count = 3 out &&
1445                git ls-files -u >out &&
1446                test_line_count = 2 out &&
1447                git ls-files -o >out &&
1448                test_line_count = 1 out
1449        )
1450'
1451
1452# Setup:
1453#          L1---L2
1454#         /  \ /  \
1455#   master    X    ?
1456#         \  / \  /
1457#          R1---R2
1458#
1459# Where:
1460#   master has two files, named 'b' and 'a'
1461#   branches L1 and R1 both modify each of the two files in conflicting ways
1462#
1463#   L2 is a merge of R1 into L1; more on it later.
1464#   R2 is a merge of L1 into R1; more on it later.
1465#
1466#   X is an auto-generated merge-base used when merging L2 and R2.
1467#   since X is a merge of L1 and R1, it has conflicting versions of each file
1468#
1469#   More about L2 and R2:
1470#     - both resolve the conflicts in 'b' and 'a' differently
1471#     - L2 renames 'b' to 'm'
1472#     - R2 renames 'a' to 'm'
1473#
1474#   In the end, in file 'm' we have four different conflicting files (from
1475#   two versions of 'b' and two of 'a').  In addition, if
1476#   merge.conflictstyle is diff3, then the base version also has
1477#   conflict markers of its own, leading to a total of three levels of
1478#   conflict markers.  This is a pretty weird corner case, but we just want
1479#   to ensure that we handle it as well as practical.
1480
1481test_expect_success 'setup nested conflicts' '
1482        test_create_repo nested_conflicts &&
1483        (
1484                cd nested_conflicts &&
1485
1486                # Create some related files now
1487                for i in $(test_seq 1 10)
1488                do
1489                        echo Random base content line $i
1490                done >initial &&
1491
1492                cp initial b_L1 &&
1493                cp initial b_R1 &&
1494                cp initial b_L2 &&
1495                cp initial b_R2 &&
1496                cp initial a_L1 &&
1497                cp initial a_R1 &&
1498                cp initial a_L2 &&
1499                cp initial a_R2 &&
1500
1501                test_write_lines b b_L1 >>b_L1 &&
1502                test_write_lines b b_R1 >>b_R1 &&
1503                test_write_lines b b_L2 >>b_L2 &&
1504                test_write_lines b b_R2 >>b_R2 &&
1505                test_write_lines a a_L1 >>a_L1 &&
1506                test_write_lines a a_R1 >>a_R1 &&
1507                test_write_lines a a_L2 >>a_L2 &&
1508                test_write_lines a a_R2 >>a_R2 &&
1509
1510                # Setup original commit (or merge-base), consisting of
1511                # files named "b" and "a"
1512                cp initial b &&
1513                cp initial a &&
1514                echo b >>b &&
1515                echo a >>a &&
1516                git add b a &&
1517                test_tick && git commit -m initial &&
1518
1519                git branch L &&
1520                git branch R &&
1521
1522                # Handle the left side
1523                git checkout L &&
1524                mv -f b_L1 b &&
1525                mv -f a_L1 a &&
1526                git add b a &&
1527                test_tick && git commit -m "version L1 of files" &&
1528                git tag L1 &&
1529
1530                # Handle the right side
1531                git checkout R &&
1532                mv -f b_R1 b &&
1533                mv -f a_R1 a &&
1534                git add b a &&
1535                test_tick && git commit -m "verson R1 of files" &&
1536                git tag R1 &&
1537
1538                # Create first merge on left side
1539                git checkout L &&
1540                test_must_fail git merge R1 &&
1541                mv -f b_L2 b &&
1542                mv -f a_L2 a &&
1543                git add b a &&
1544                git mv b m &&
1545                test_tick && git commit -m "left merge, rename b->m" &&
1546                git tag L2 &&
1547
1548                # Create first merge on right side
1549                git checkout R &&
1550                test_must_fail git merge L1 &&
1551                mv -f b_R2 b &&
1552                mv -f a_R2 a &&
1553                git add b a &&
1554                git mv a m &&
1555                test_tick && git commit -m "right merge, rename a->m" &&
1556                git tag R2
1557        )
1558'
1559
1560test_expect_success 'check nested conflicts' '
1561        (
1562                cd nested_conflicts &&
1563
1564                git clean -f &&
1565                git checkout L2^0 &&
1566
1567                # Merge must fail; there is a conflict
1568                test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R2^0 &&
1569
1570                # Make sure the index has the right number of entries
1571                git ls-files -s >out &&
1572                test_line_count = 2 out &&
1573                git ls-files -u >out &&
1574                test_line_count = 2 out &&
1575                # Ensure we have the correct number of untracked files
1576                git ls-files -o >out &&
1577                test_line_count = 1 out &&
1578
1579                # Create a and b from virtual merge base X
1580                git cat-file -p master:a >base &&
1581                git cat-file -p L1:a >ours &&
1582                git cat-file -p R1:a >theirs &&
1583                test_must_fail git merge-file --diff3 \
1584                        -L "Temporary merge branch 1" \
1585                        -L "merged common ancestors"  \
1586                        -L "Temporary merge branch 2" \
1587                        ours  \
1588                        base  \
1589                        theirs &&
1590                sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_a &&
1591
1592                git cat-file -p master:b >base &&
1593                git cat-file -p L1:b >ours &&
1594                git cat-file -p R1:b >theirs &&
1595                test_must_fail git merge-file --diff3 \
1596                        -L "Temporary merge branch 1" \
1597                        -L "merged common ancestors"  \
1598                        -L "Temporary merge branch 2" \
1599                        ours  \
1600                        base  \
1601                        theirs &&
1602                sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_b &&
1603
1604                # Compare :2:m to expected values
1605                git cat-file -p L2:m >ours &&
1606                git cat-file -p R2:b >theirs &&
1607                test_must_fail git merge-file --diff3  \
1608                        -L "HEAD:m"                    \
1609                        -L "merged common ancestors:b" \
1610                        -L "R2^0:b"                    \
1611                        ours                           \
1612                        vmb_b                          \
1613                        theirs                         &&
1614                sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_2 &&
1615                git cat-file -p :2:m >actual &&
1616                test_cmp m_stage_2 actual &&
1617
1618                # Compare :3:m to expected values
1619                git cat-file -p L2:a >ours &&
1620                git cat-file -p R2:m >theirs &&
1621                test_must_fail git merge-file --diff3  \
1622                        -L "HEAD:a"                    \
1623                        -L "merged common ancestors:a" \
1624                        -L "R2^0:m"                    \
1625                        ours                           \
1626                        vmb_a                          \
1627                        theirs                         &&
1628                sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_3 &&
1629                git cat-file -p :3:m >actual &&
1630                test_cmp m_stage_3 actual &&
1631
1632                # Compare m to expected contents
1633                >empty &&
1634                cp m_stage_2 expected_final_m &&
1635                test_must_fail git merge-file --diff3 \
1636                        -L "HEAD"                     \
1637                        -L "merged common ancestors"  \
1638                        -L "R2^0"                     \
1639                        expected_final_m              \
1640                        empty                         \
1641                        m_stage_3                     &&
1642                test_cmp expected_final_m m
1643        )
1644'
1645
1646# Setup:
1647#          L1---L2---L3
1648#         /  \ /  \ /  \
1649#   master    X1   X2   ?
1650#         \  / \  / \  /
1651#          R1---R2---R3
1652#
1653# Where:
1654#   master has one file named 'content'
1655#   branches L1 and R1 both modify each of the two files in conflicting ways
1656#
1657#   L<n> (n>1) is a merge of R<n-1> into L<n-1>
1658#   R<n> (n>1) is a merge of L<n-1> into R<n-1>
1659#   L<n> and R<n> resolve the conflicts differently.
1660#
1661#   X<n> is an auto-generated merge-base used when merging L<n+1> and R<n+1>.
1662#   By construction, X1 has conflict markers due to conflicting versions.
1663#   X2, due to using merge.conflictstyle=3, has nested conflict markers.
1664#
1665#   So, merging R3 into L3 using merge.conflictstyle=3 should show the
1666#   nested conflict markers from X2 in the base version -- that means we
1667#   have three levels of conflict markers.  Can we distinguish all three?
1668
1669test_expect_success 'setup virtual merge base with nested conflicts' '
1670        test_create_repo virtual_merge_base_has_nested_conflicts &&
1671        (
1672                cd virtual_merge_base_has_nested_conflicts &&
1673
1674                # Create some related files now
1675                for i in $(test_seq 1 10)
1676                do
1677                        echo Random base content line $i
1678                done >content &&
1679
1680                # Setup original commit
1681                git add content &&
1682                test_tick && git commit -m initial &&
1683
1684                git branch L &&
1685                git branch R &&
1686
1687                # Create L1
1688                git checkout L &&
1689                echo left >>content &&
1690                git add content &&
1691                test_tick && git commit -m "version L1 of content" &&
1692                git tag L1 &&
1693
1694                # Create R1
1695                git checkout R &&
1696                echo right >>content &&
1697                git add content &&
1698                test_tick && git commit -m "verson R1 of content" &&
1699                git tag R1 &&
1700
1701                # Create L2
1702                git checkout L &&
1703                test_must_fail git -c merge.conflictstyle=diff3 merge R1 &&
1704                git checkout L1 content &&
1705                test_tick && git commit -m "version L2 of content" &&
1706                git tag L2 &&
1707
1708                # Create R2
1709                git checkout R &&
1710                test_must_fail git -c merge.conflictstyle=diff3 merge L1 &&
1711                git checkout R1 content &&
1712                test_tick && git commit -m "version R2 of content" &&
1713                git tag R2 &&
1714
1715                # Create L3
1716                git checkout L &&
1717                test_must_fail git -c merge.conflictstyle=diff3 merge R2 &&
1718                git checkout L1 content &&
1719                test_tick && git commit -m "version L3 of content" &&
1720                git tag L3 &&
1721
1722                # Create R3
1723                git checkout R &&
1724                test_must_fail git -c merge.conflictstyle=diff3 merge L2 &&
1725                git checkout R1 content &&
1726                test_tick && git commit -m "version R3 of content" &&
1727                git tag R3
1728        )
1729'
1730
1731test_expect_success 'check virtual merge base with nested conflicts' '
1732        (
1733                cd virtual_merge_base_has_nested_conflicts &&
1734
1735                git checkout L3^0 &&
1736
1737                # Merge must fail; there is a conflict
1738                test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R3^0 &&
1739
1740                # Make sure the index has the right number of entries
1741                git ls-files -s >out &&
1742                test_line_count = 3 out &&
1743                git ls-files -u >out &&
1744                test_line_count = 3 out &&
1745                # Ensure we have the correct number of untracked files
1746                git ls-files -o >out &&
1747                test_line_count = 1 out &&
1748
1749                # Compare :[23]:content to expected values
1750                git rev-parse L1:content R1:content >expect &&
1751                git rev-parse :2:content :3:content >actual &&
1752                test_cmp expect actual &&
1753
1754                # Imitate X1 merge base, except without long enough conflict
1755                # markers because a subsequent sed will modify them.  Put
1756                # result into vmb.
1757                git cat-file -p master:content >base &&
1758                git cat-file -p L:content >left &&
1759                git cat-file -p R:content >right &&
1760                cp left merged-once &&
1761                test_must_fail git merge-file --diff3 \
1762                        -L "Temporary merge branch 1" \
1763                        -L "merged common ancestors"  \
1764                        -L "Temporary merge branch 2" \
1765                        merged-once \
1766                        base        \
1767                        right       &&
1768                sed -e "s/^\([<|=>]\)/\1\1\1/" merged-once >vmb &&
1769
1770                # Imitate X2 merge base, overwriting vmb.  Note that we
1771                # extend both sets of conflict markers to make them longer
1772                # with the sed command.
1773                cp left merged-twice &&
1774                test_must_fail git merge-file --diff3 \
1775                        -L "Temporary merge branch 1" \
1776                        -L "merged common ancestors"  \
1777                        -L "Temporary merge branch 2" \
1778                        merged-twice \
1779                        vmb          \
1780                        right        &&
1781                sed -e "s/^\([<|=>]\)/\1\1\1/" merged-twice >vmb &&
1782
1783                # Compare :1:content to expected value
1784                git cat-file -p :1:content >actual &&
1785                test_cmp vmb actual &&
1786
1787                # Determine expected content in final outer merge, compare to
1788                # what the merge generated.
1789                cp -f left expect &&
1790                test_must_fail git merge-file --diff3                      \
1791                        -L "HEAD"  -L "merged common ancestors"  -L "R3^0" \
1792                        expect     vmb                           right     &&
1793                test_cmp expect content
1794        )
1795'
1796
1797test_done