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