t / t3430-rebase-merges.shon commit Merge branch 'sg/fast-import-dump-refs-on-checkpoint-fix' (1638a62)
   1#!/bin/sh
   2#
   3# Copyright (c) 2018 Johannes E. Schindelin
   4#
   5
   6test_description='git rebase -i --rebase-merges
   7
   8This test runs git rebase "interactively", retaining the branch structure by
   9recreating merge commits.
  10
  11Initial setup:
  12
  13    -- B --                   (first)
  14   /       \
  15 A - C - D - E - H            (master)
  16       \       /
  17         F - G                (second)
  18'
  19. ./test-lib.sh
  20. "$TEST_DIRECTORY"/lib-rebase.sh
  21
  22test_cmp_graph () {
  23        cat >expect &&
  24        git log --graph --boundary --format=%s "$@" >output &&
  25        sed "s/ *$//" <output >output.trimmed &&
  26        test_cmp expect output.trimmed
  27}
  28
  29test_expect_success 'setup' '
  30        write_script replace-editor.sh <<-\EOF &&
  31        mv "$1" "$(git rev-parse --git-path ORIGINAL-TODO)"
  32        cp script-from-scratch "$1"
  33        EOF
  34
  35        test_commit A &&
  36        git checkout -b first &&
  37        test_commit B &&
  38        git checkout master &&
  39        test_commit C &&
  40        test_commit D &&
  41        git merge --no-commit B &&
  42        test_tick &&
  43        git commit -m E &&
  44        git tag -m E E &&
  45        git checkout -b second C &&
  46        test_commit F &&
  47        test_commit G &&
  48        git checkout master &&
  49        git merge --no-commit G &&
  50        test_tick &&
  51        git commit -m H &&
  52        git tag -m H H
  53'
  54
  55test_expect_success 'create completely different structure' '
  56        cat >script-from-scratch <<-\EOF &&
  57        label onto
  58
  59        # onebranch
  60        pick G
  61        pick D
  62        label onebranch
  63
  64        # second
  65        reset onto
  66        pick B
  67        label second
  68
  69        reset onto
  70        merge -C H second
  71        merge onebranch # Merge the topic branch '\''onebranch'\''
  72        EOF
  73        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
  74        test_tick &&
  75        git rebase -i -r A &&
  76        test_cmp_graph <<-\EOF
  77        *   Merge the topic branch '\''onebranch'\''
  78        |\
  79        | * D
  80        | * G
  81        * |   H
  82        |\ \
  83        | |/
  84        |/|
  85        | * B
  86        |/
  87        * A
  88        EOF
  89'
  90
  91test_expect_success 'generate correct todo list' '
  92        cat >expect <<-\EOF &&
  93        label onto
  94
  95        reset onto
  96        pick d9df450 B
  97        label E
  98
  99        reset onto
 100        pick 5dee784 C
 101        label branch-point
 102        pick ca2c861 F
 103        pick 088b00a G
 104        label H
 105
 106        reset branch-point # C
 107        pick 12bd07b D
 108        merge -C 2051b56 E # E
 109        merge -C 233d48a H # H
 110
 111        EOF
 112
 113        grep -v "^#" <.git/ORIGINAL-TODO >output &&
 114        test_cmp expect output
 115'
 116
 117test_expect_success '`reset` refuses to overwrite untracked files' '
 118        git checkout -b refuse-to-reset &&
 119        test_commit dont-overwrite-untracked &&
 120        git checkout @{-1} &&
 121        : >dont-overwrite-untracked.t &&
 122        echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
 123        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 124        test_must_fail git rebase -r HEAD &&
 125        git rebase --abort
 126'
 127
 128test_expect_success 'failed `merge` writes patch (may be rescheduled, too)' '
 129        test_when_finished "test_might_fail git rebase --abort" &&
 130        git checkout -b conflicting-merge A &&
 131
 132        : fail because of conflicting untracked file &&
 133        >G.t &&
 134        echo "merge -C H G" >script-from-scratch &&
 135        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 136        test_tick &&
 137        test_must_fail git rebase -ir HEAD &&
 138        grep "^merge -C .* G$" .git/rebase-merge/done &&
 139        grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 140        test_path_is_file .git/rebase-merge/patch &&
 141
 142        : fail because of merge conflict &&
 143        rm G.t .git/rebase-merge/patch &&
 144        git reset --hard &&
 145        test_commit conflicting-G G.t not-G conflicting-G &&
 146        test_must_fail git rebase --continue &&
 147        ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 148        test_path_is_file .git/rebase-merge/patch
 149'
 150
 151test_expect_success 'with a branch tip that was cherry-picked already' '
 152        git checkout -b already-upstream master &&
 153        base="$(git rev-parse --verify HEAD)" &&
 154
 155        test_commit A1 &&
 156        test_commit A2 &&
 157        git reset --hard $base &&
 158        test_commit B1 &&
 159        test_tick &&
 160        git merge -m "Merge branch A" A2 &&
 161
 162        git checkout -b upstream-with-a2 $base &&
 163        test_tick &&
 164        git cherry-pick A2 &&
 165
 166        git checkout already-upstream &&
 167        test_tick &&
 168        git rebase -i -r upstream-with-a2 &&
 169        test_cmp_graph upstream-with-a2.. <<-\EOF
 170        *   Merge branch A
 171        |\
 172        | * A1
 173        * | B1
 174        |/
 175        o A2
 176        EOF
 177'
 178
 179test_expect_success 'do not rebase cousins unless asked for' '
 180        git checkout -b cousins master &&
 181        before="$(git rev-parse --verify HEAD)" &&
 182        test_tick &&
 183        git rebase -r HEAD^ &&
 184        test_cmp_rev HEAD $before &&
 185        test_tick &&
 186        git rebase --rebase-merges=rebase-cousins HEAD^ &&
 187        test_cmp_graph HEAD^.. <<-\EOF
 188        *   Merge the topic branch '\''onebranch'\''
 189        |\
 190        | * D
 191        | * G
 192        |/
 193        o H
 194        EOF
 195'
 196
 197test_expect_success 'refs/rewritten/* is worktree-local' '
 198        git worktree add wt &&
 199        cat >wt/script-from-scratch <<-\EOF &&
 200        label xyz
 201        exec GIT_DIR=../.git git rev-parse --verify refs/rewritten/xyz >a || :
 202        exec git rev-parse --verify refs/rewritten/xyz >b
 203        EOF
 204
 205        test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
 206        git -C wt rebase -i HEAD &&
 207        test_must_be_empty wt/a &&
 208        test_cmp_rev HEAD "$(cat wt/b)"
 209'
 210
 211test_expect_success 'post-rewrite hook and fixups work for merges' '
 212        git checkout -b post-rewrite &&
 213        test_commit same1 &&
 214        git reset --hard HEAD^ &&
 215        test_commit same2 &&
 216        git merge -m "to fix up" same1 &&
 217        echo same old same old >same2.t &&
 218        test_tick &&
 219        git commit --fixup HEAD same2.t &&
 220        fixup="$(git rev-parse HEAD)" &&
 221
 222        mkdir -p .git/hooks &&
 223        test_when_finished "rm .git/hooks/post-rewrite" &&
 224        echo "cat >actual" | write_script .git/hooks/post-rewrite &&
 225
 226        test_tick &&
 227        git rebase -i --autosquash -r HEAD^^^ &&
 228        printf "%s %s\n%s %s\n%s %s\n%s %s\n" >expect $(git rev-parse \
 229                $fixup^^2 HEAD^2 \
 230                $fixup^^ HEAD^ \
 231                $fixup^ HEAD \
 232                $fixup HEAD) &&
 233        test_cmp expect actual
 234'
 235
 236test_expect_success 'refuse to merge ancestors of HEAD' '
 237        echo "merge HEAD^" >script-from-scratch &&
 238        test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
 239        before="$(git rev-parse HEAD)" &&
 240        git rebase -i HEAD &&
 241        test_cmp_rev HEAD $before
 242'
 243
 244test_expect_success 'root commits' '
 245        git checkout --orphan unrelated &&
 246        (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
 247         test_commit second-root) &&
 248        test_commit third-root &&
 249        cat >script-from-scratch <<-\EOF &&
 250        pick third-root
 251        label first-branch
 252        reset [new root]
 253        pick second-root
 254        merge first-branch # Merge the 3rd root
 255        EOF
 256        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 257        test_tick &&
 258        git rebase -i --force --root -r &&
 259        test "Parsnip" = "$(git show -s --format=%an HEAD^)" &&
 260        test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) &&
 261        test $(git rev-parse second-root:second-root.t) = \
 262                $(git rev-parse HEAD^:second-root.t) &&
 263        test_cmp_graph HEAD <<-\EOF &&
 264        *   Merge the 3rd root
 265        |\
 266        | * third-root
 267        * second-root
 268        EOF
 269
 270        : fast forward if possible &&
 271        before="$(git rev-parse --verify HEAD)" &&
 272        test_might_fail git config --unset sequence.editor &&
 273        test_tick &&
 274        git rebase -i --root -r &&
 275        test_cmp_rev HEAD $before
 276'
 277
 278test_expect_success 'a "merge" into a root commit is a fast-forward' '
 279        head=$(git rev-parse HEAD) &&
 280        cat >script-from-scratch <<-EOF &&
 281        reset [new root]
 282        merge $head
 283        EOF
 284        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 285        test_tick &&
 286        git rebase -i -r HEAD^ &&
 287        test_cmp_rev HEAD $head
 288'
 289
 290test_expect_success 'A root commit can be a cousin, treat it that way' '
 291        git checkout --orphan khnum &&
 292        test_commit yama &&
 293        git checkout -b asherah master &&
 294        test_commit shamkat &&
 295        git merge --allow-unrelated-histories khnum &&
 296        test_tick &&
 297        git rebase -f -r HEAD^ &&
 298        ! test_cmp_rev HEAD^2 khnum &&
 299        test_cmp_graph HEAD^.. <<-\EOF &&
 300        *   Merge branch '\''khnum'\'' into asherah
 301        |\
 302        | * yama
 303        o shamkat
 304        EOF
 305        test_tick &&
 306        git rebase --rebase-merges=rebase-cousins HEAD^ &&
 307        test_cmp_graph HEAD^.. <<-\EOF
 308        *   Merge branch '\''khnum'\'' into asherah
 309        |\
 310        | * yama
 311        |/
 312        o shamkat
 313        EOF
 314'
 315
 316test_expect_success 'labels that are object IDs are rewritten' '
 317        git checkout -b third B &&
 318        test_commit I &&
 319        third=$(git rev-parse HEAD) &&
 320        git checkout -b labels master &&
 321        git merge --no-commit third &&
 322        test_tick &&
 323        git commit -m "Merge commit '\''$third'\'' into labels" &&
 324        echo noop >script-from-scratch &&
 325        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 326        test_tick &&
 327        git rebase -i -r A &&
 328        grep "^label $third-" .git/ORIGINAL-TODO &&
 329        ! grep "^label $third$" .git/ORIGINAL-TODO
 330'
 331
 332test_expect_success 'octopus merges' '
 333        git checkout -b three &&
 334        test_commit before-octopus &&
 335        test_commit three &&
 336        git checkout -b two HEAD^ &&
 337        test_commit two &&
 338        git checkout -b one HEAD^ &&
 339        test_commit one &&
 340        test_tick &&
 341        (GIT_AUTHOR_NAME="Hank" GIT_AUTHOR_EMAIL="hank@sea.world" \
 342         git merge -m "Tüntenfüsch" two three) &&
 343
 344        : fast forward if possible &&
 345        before="$(git rev-parse --verify HEAD)" &&
 346        test_tick &&
 347        git rebase -i -r HEAD^^ &&
 348        test_cmp_rev HEAD $before &&
 349
 350        test_tick &&
 351        git rebase -i --force -r HEAD^^ &&
 352        test "Hank" = "$(git show -s --format=%an HEAD)" &&
 353        test "$before" != $(git rev-parse HEAD) &&
 354        test_cmp_graph HEAD^^.. <<-\EOF
 355        *-.   Tüntenfüsch
 356        |\ \
 357        | | * three
 358        | * | two
 359        | |/
 360        * | one
 361        |/
 362        o before-octopus
 363        EOF
 364'
 365
 366test_done