t / t7405-submodule-merge.shon commit Merge branch 'bb/unicode-12.1-reiwa' (3dc47c4)
   1#!/bin/sh
   2
   3test_description='merging with submodules'
   4
   5. ./test-lib.sh
   6
   7#
   8# history
   9#
  10#        a --- c
  11#      /   \ /
  12# root      X
  13#      \   / \
  14#        b --- d
  15#
  16
  17test_expect_success setup '
  18
  19        mkdir sub &&
  20        (cd sub &&
  21         git init &&
  22         echo original > file &&
  23         git add file &&
  24         test_tick &&
  25         git commit -m sub-root) &&
  26        git add sub &&
  27        test_tick &&
  28        git commit -m root &&
  29
  30        git checkout -b a master &&
  31        (cd sub &&
  32         echo A > file &&
  33         git add file &&
  34         test_tick &&
  35         git commit -m sub-a) &&
  36        git add sub &&
  37        test_tick &&
  38        git commit -m a &&
  39
  40        git checkout -b b master &&
  41        (cd sub &&
  42         echo B > file &&
  43         git add file &&
  44         test_tick &&
  45         git commit -m sub-b) &&
  46        git add sub &&
  47        test_tick &&
  48        git commit -m b &&
  49
  50        git checkout -b c a &&
  51        git merge -s ours b &&
  52
  53        git checkout -b d b &&
  54        git merge -s ours a
  55'
  56
  57# History setup
  58#
  59#             b
  60#           /   \
  61#  init -- a     d
  62#    \      \   /
  63#     g       c
  64#
  65# a in the main repository records to sub-a in the submodule and
  66# analogous b and c. d should be automatically found by merging c into
  67# b in the main repository.
  68test_expect_success 'setup for merge search' '
  69        mkdir merge-search &&
  70        (cd merge-search &&
  71        git init &&
  72        mkdir sub &&
  73        (cd sub &&
  74         git init &&
  75         echo "file-a" > file-a &&
  76         git add file-a &&
  77         git commit -m "sub-a" &&
  78         git branch sub-a) &&
  79        git commit --allow-empty -m init &&
  80        git branch init &&
  81        git add sub &&
  82        git commit -m "a" &&
  83        git branch a &&
  84
  85        git checkout -b b &&
  86        (cd sub &&
  87         git checkout -b sub-b &&
  88         echo "file-b" > file-b &&
  89         git add file-b &&
  90         git commit -m "sub-b") &&
  91        git commit -a -m "b" &&
  92
  93        git checkout -b c a &&
  94        (cd sub &&
  95         git checkout -b sub-c sub-a &&
  96         echo "file-c" > file-c &&
  97         git add file-c &&
  98         git commit -m "sub-c") &&
  99        git commit -a -m "c" &&
 100
 101        git checkout -b d a &&
 102        (cd sub &&
 103         git checkout -b sub-d sub-b &&
 104         git merge sub-c) &&
 105        git commit -a -m "d" &&
 106        git branch test b &&
 107
 108        git checkout -b g init &&
 109        (cd sub &&
 110         git checkout -b sub-g sub-c) &&
 111        git add sub &&
 112        git commit -a -m "g")
 113'
 114
 115test_expect_success 'merge with one side as a fast-forward of the other' '
 116        (cd merge-search &&
 117         git checkout -b test-forward b &&
 118         git merge d &&
 119         git ls-tree test-forward sub | cut -f1 | cut -f3 -d" " > actual &&
 120         (cd sub &&
 121          git rev-parse sub-d > ../expect) &&
 122         test_cmp expect actual)
 123'
 124
 125test_expect_success 'merging should conflict for non fast-forward' '
 126        (cd merge-search &&
 127         git checkout -b test-nonforward b &&
 128         (cd sub &&
 129          git rev-parse sub-d > ../expect) &&
 130         test_must_fail git merge c 2> actual  &&
 131         grep $(cat expect) actual > /dev/null &&
 132         git reset --hard)
 133'
 134
 135test_expect_success 'merging should fail for ambiguous common parent' '
 136        (cd merge-search &&
 137        git checkout -b test-ambiguous b &&
 138        (cd sub &&
 139         git checkout -b ambiguous sub-b &&
 140         git merge sub-c &&
 141         git rev-parse sub-d > ../expect1 &&
 142         git rev-parse ambiguous > ../expect2) &&
 143        test_must_fail git merge c 2> actual &&
 144        grep $(cat expect1) actual > /dev/null &&
 145        grep $(cat expect2) actual > /dev/null &&
 146        git reset --hard)
 147'
 148
 149# in a situation like this
 150#
 151# submodule tree:
 152#
 153#    sub-a --- sub-b --- sub-d
 154#
 155# main tree:
 156#
 157#    e (sub-a)
 158#   /
 159#  bb (sub-b)
 160#   \
 161#    f (sub-d)
 162#
 163# A merge between e and f should fail because one of the submodule
 164# commits (sub-a) does not descend from the submodule merge-base (sub-b).
 165#
 166test_expect_success 'merging should fail for changes that are backwards' '
 167        (cd merge-search &&
 168        git checkout -b bb a &&
 169        (cd sub &&
 170         git checkout sub-b) &&
 171        git commit -a -m "bb" &&
 172
 173        git checkout -b e bb &&
 174        (cd sub &&
 175         git checkout sub-a) &&
 176        git commit -a -m "e" &&
 177
 178        git checkout -b f bb &&
 179        (cd sub &&
 180         git checkout sub-d) &&
 181        git commit -a -m "f" &&
 182
 183        git checkout -b test-backward e &&
 184        test_must_fail git merge f)
 185'
 186
 187
 188# Check that the conflicting submodule is detected when it is
 189# in the common ancestor. status should be 'U00...00"
 190test_expect_success 'git submodule status should display the merge conflict properly with merge base' '
 191       (cd merge-search &&
 192       cat >.gitmodules <<EOF &&
 193[submodule "sub"]
 194       path = sub
 195       url = $TRASH_DIRECTORY/sub
 196EOF
 197       cat >expect <<EOF &&
 198U0000000000000000000000000000000000000000 sub
 199EOF
 200       git submodule status > actual &&
 201       test_cmp expect actual &&
 202        git reset --hard)
 203'
 204
 205# Check that the conflicting submodule is detected when it is
 206# not in the common ancestor. status should be 'U00...00"
 207test_expect_success 'git submodule status should display the merge conflict properly without merge-base' '
 208       (cd merge-search &&
 209        git checkout -b test-no-merge-base g &&
 210        test_must_fail git merge b &&
 211       cat >.gitmodules <<EOF &&
 212[submodule "sub"]
 213       path = sub
 214       url = $TRASH_DIRECTORY/sub
 215EOF
 216       cat >expect <<EOF &&
 217U0000000000000000000000000000000000000000 sub
 218EOF
 219       git submodule status > actual &&
 220       test_cmp expect actual &&
 221       git reset --hard)
 222'
 223
 224
 225test_expect_success 'merging with a modify/modify conflict between merge bases' '
 226        git reset --hard HEAD &&
 227        git checkout -b test2 c &&
 228        git merge d
 229'
 230
 231# canonical criss-cross history in top and submodule
 232test_expect_success 'setup for recursive merge with submodule' '
 233        mkdir merge-recursive &&
 234        (cd merge-recursive &&
 235         git init &&
 236         mkdir sub &&
 237         (cd sub &&
 238          git init &&
 239          test_commit a &&
 240          git checkout -b sub-b master &&
 241          test_commit b &&
 242          git checkout -b sub-c master &&
 243          test_commit c &&
 244          git checkout -b sub-bc sub-b &&
 245          git merge sub-c &&
 246          git checkout -b sub-cb sub-c &&
 247          git merge sub-b &&
 248          git checkout master) &&
 249         git add sub &&
 250         git commit -m a &&
 251         git checkout -b top-b master &&
 252         (cd sub && git checkout sub-b) &&
 253         git add sub &&
 254         git commit -m b &&
 255         git checkout -b top-c master &&
 256         (cd sub && git checkout sub-c) &&
 257         git add sub &&
 258         git commit -m c &&
 259         git checkout -b top-bc top-b &&
 260         git merge -s ours --no-commit top-c &&
 261         (cd sub && git checkout sub-bc) &&
 262         git add sub &&
 263         git commit -m bc &&
 264         git checkout -b top-cb top-c &&
 265         git merge -s ours --no-commit top-b &&
 266         (cd sub && git checkout sub-cb) &&
 267         git add sub &&
 268         git commit -m cb)
 269'
 270
 271# merge should leave submodule unmerged in index
 272test_expect_success 'recursive merge with submodule' '
 273        (cd merge-recursive &&
 274         test_must_fail git merge top-bc &&
 275         echo "160000 $(git rev-parse top-cb:sub) 2     sub" > expect2 &&
 276         echo "160000 $(git rev-parse top-bc:sub) 3     sub" > expect3 &&
 277         git ls-files -u > actual &&
 278         grep "$(cat expect2)" actual > /dev/null &&
 279         grep "$(cat expect3)" actual > /dev/null)
 280'
 281
 282# File/submodule conflict
 283#   Commit O: <empty>
 284#   Commit A: path (submodule)
 285#   Commit B: path
 286#   Expected: path/ is submodule and file contents for B's path are somewhere
 287
 288test_expect_success 'setup file/submodule conflict' '
 289        test_create_repo file-submodule &&
 290        (
 291                cd file-submodule &&
 292
 293                git commit --allow-empty -m O &&
 294
 295                git branch A &&
 296                git branch B &&
 297
 298                git checkout B &&
 299                echo content >path &&
 300                git add path &&
 301                git commit -m B &&
 302
 303                git checkout A &&
 304                test_create_repo path &&
 305                test_commit -C path world &&
 306                git submodule add ./path &&
 307                git commit -m A
 308        )
 309'
 310
 311test_expect_failure 'file/submodule conflict' '
 312        test_when_finished "git -C file-submodule reset --hard" &&
 313        (
 314                cd file-submodule &&
 315
 316                git checkout A^0 &&
 317                test_must_fail git merge B^0 &&
 318
 319                git ls-files -s >out &&
 320                test_line_count = 3 out &&
 321                git ls-files -u >out &&
 322                test_line_count = 2 out &&
 323
 324                # path/ is still a submodule
 325                test_path_is_dir path/.git &&
 326
 327                # There is a submodule at "path", so B:path cannot be written
 328                # there.  We expect it to be written somewhere in the same
 329                # directory, though, so just grep for its content in all
 330                # files, and ignore "grep: path: Is a directory" message
 331                echo Checking if contents from B:path showed up anywhere &&
 332                grep -q content * 2>/dev/null
 333        )
 334'
 335
 336test_expect_success 'file/submodule conflict; merge --abort works afterward' '
 337        test_when_finished "git -C file-submodule reset --hard" &&
 338        (
 339                cd file-submodule &&
 340
 341                git checkout A^0 &&
 342                test_must_fail git merge B^0 >out 2>err &&
 343
 344                test_path_is_file .git/MERGE_HEAD &&
 345                git merge --abort
 346        )
 347'
 348
 349# Directory/submodule conflict
 350#   Commit O: <empty>
 351#   Commit A: path (submodule), with sole tracked file named 'world'
 352#   Commit B1: path/file
 353#   Commit B2: path/world
 354#
 355#   Expected from merge of A & B1:
 356#     Contents under path/ from commit B1 are renamed elsewhere; we do not
 357#     want to write files from one of our tracked directories into a submodule
 358#
 359#   Expected from merge of A & B2:
 360#     Similar to last merge, but with a slight twist: we don't want paths
 361#     under the submodule to be treated as untracked or in the way.
 362
 363test_expect_success 'setup directory/submodule conflict' '
 364        test_create_repo directory-submodule &&
 365        (
 366                cd directory-submodule &&
 367
 368                git commit --allow-empty -m O &&
 369
 370                git branch A &&
 371                git branch B1 &&
 372                git branch B2 &&
 373
 374                git checkout B1 &&
 375                mkdir path &&
 376                echo contents >path/file &&
 377                git add path/file &&
 378                git commit -m B1 &&
 379
 380                git checkout B2 &&
 381                mkdir path &&
 382                echo contents >path/world &&
 383                git add path/world &&
 384                git commit -m B2 &&
 385
 386                git checkout A &&
 387                test_create_repo path &&
 388                test_commit -C path hello world &&
 389                git submodule add ./path &&
 390                git commit -m A
 391        )
 392'
 393
 394test_expect_failure 'directory/submodule conflict; keep submodule clean' '
 395        test_when_finished "git -C directory-submodule reset --hard" &&
 396        (
 397                cd directory-submodule &&
 398
 399                git checkout A^0 &&
 400                test_must_fail git merge B1^0 &&
 401
 402                git ls-files -s >out &&
 403                test_line_count = 3 out &&
 404                git ls-files -u >out &&
 405                test_line_count = 1 out &&
 406
 407                # path/ is still a submodule
 408                test_path_is_dir path/.git &&
 409
 410                echo Checking if contents from B1:path/file showed up &&
 411                # Would rather use grep -r, but that is GNU extension...
 412                git ls-files -co | xargs grep -q contents 2>/dev/null &&
 413
 414                # However, B1:path/file should NOT have shown up at path/file,
 415                # because we should not write into the submodule
 416                test_path_is_missing path/file
 417        )
 418'
 419
 420test_expect_failure !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '
 421        test_when_finished "git -C directory-submodule/path reset --hard" &&
 422        test_when_finished "git -C directory-submodule reset --hard" &&
 423        (
 424                cd directory-submodule &&
 425
 426                git checkout A^0 &&
 427                test_must_fail git merge B2^0 >out 2>err &&
 428
 429                # We do not want files within the submodule to prevent the
 430                # merge from starting; we should not be writing to such paths
 431                # anyway.
 432                test_i18ngrep ! "refusing to lose untracked file at" err
 433        )
 434'
 435
 436test_expect_failure 'directory/submodule conflict; merge --abort works afterward' '
 437        test_when_finished "git -C directory-submodule/path reset --hard" &&
 438        test_when_finished "git -C directory-submodule reset --hard" &&
 439        (
 440                cd directory-submodule &&
 441
 442                git checkout A^0 &&
 443                test_must_fail git merge B2^0 &&
 444                test_path_is_file .git/MERGE_HEAD &&
 445
 446                # merge --abort should succeed, should clear .git/MERGE_HEAD,
 447                # and should not leave behind any conflicted files
 448                git merge --abort &&
 449                test_path_is_missing .git/MERGE_HEAD &&
 450                git ls-files -u >conflicts &&
 451                test_must_be_empty conflicts
 452        )
 453'
 454
 455test_done