t / t3430-rebase-merges.shon commit Merge branch 'tg/doc-sec-list' (7fe48cb)
   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        cp script-from-scratch script-from-scratch-orig &&
  74        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
  75        test_tick &&
  76        git rebase -i -r A &&
  77        test_cmp_graph <<-\EOF
  78        *   Merge the topic branch '\''onebranch'\''
  79        |\
  80        | * D
  81        | * G
  82        * |   H
  83        |\ \
  84        | |/
  85        |/|
  86        | * B
  87        |/
  88        * A
  89        EOF
  90'
  91
  92test_expect_success 'generate correct todo list' '
  93        cat >expect <<-\EOF &&
  94        label onto
  95
  96        reset onto
  97        pick d9df450 B
  98        label E
  99
 100        reset onto
 101        pick 5dee784 C
 102        label branch-point
 103        pick ca2c861 F
 104        pick 088b00a G
 105        label H
 106
 107        reset branch-point # C
 108        pick 12bd07b D
 109        merge -C 2051b56 E # E
 110        merge -C 233d48a H # H
 111
 112        EOF
 113
 114        grep -v "^#" <.git/ORIGINAL-TODO >output &&
 115        test_cmp expect output
 116'
 117
 118test_expect_success '`reset` refuses to overwrite untracked files' '
 119        git checkout -b refuse-to-reset &&
 120        test_commit dont-overwrite-untracked &&
 121        git checkout @{-1} &&
 122        : >dont-overwrite-untracked.t &&
 123        echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
 124        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 125        test_must_fail git rebase -r HEAD &&
 126        git rebase --abort
 127'
 128
 129test_expect_success 'failed `merge` writes patch (may be rescheduled, too)' '
 130        test_when_finished "test_might_fail git rebase --abort" &&
 131        git checkout -b conflicting-merge A &&
 132
 133        : fail because of conflicting untracked file &&
 134        >G.t &&
 135        echo "merge -C H G" >script-from-scratch &&
 136        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 137        test_tick &&
 138        test_must_fail git rebase -ir HEAD &&
 139        grep "^merge -C .* G$" .git/rebase-merge/done &&
 140        grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 141        test_path_is_file .git/rebase-merge/patch &&
 142
 143        : fail because of merge conflict &&
 144        rm G.t .git/rebase-merge/patch &&
 145        git reset --hard &&
 146        test_commit conflicting-G G.t not-G conflicting-G &&
 147        test_must_fail git rebase --continue &&
 148        ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 149        test_path_is_file .git/rebase-merge/patch
 150'
 151
 152test_expect_success 'with a branch tip that was cherry-picked already' '
 153        git checkout -b already-upstream master &&
 154        base="$(git rev-parse --verify HEAD)" &&
 155
 156        test_commit A1 &&
 157        test_commit A2 &&
 158        git reset --hard $base &&
 159        test_commit B1 &&
 160        test_tick &&
 161        git merge -m "Merge branch A" A2 &&
 162
 163        git checkout -b upstream-with-a2 $base &&
 164        test_tick &&
 165        git cherry-pick A2 &&
 166
 167        git checkout already-upstream &&
 168        test_tick &&
 169        git rebase -i -r upstream-with-a2 &&
 170        test_cmp_graph upstream-with-a2.. <<-\EOF
 171        *   Merge branch A
 172        |\
 173        | * A1
 174        * | B1
 175        |/
 176        o A2
 177        EOF
 178'
 179
 180test_expect_success 'do not rebase cousins unless asked for' '
 181        git checkout -b cousins master &&
 182        before="$(git rev-parse --verify HEAD)" &&
 183        test_tick &&
 184        git rebase -r HEAD^ &&
 185        test_cmp_rev HEAD $before &&
 186        test_tick &&
 187        git rebase --rebase-merges=rebase-cousins HEAD^ &&
 188        test_cmp_graph HEAD^.. <<-\EOF
 189        *   Merge the topic branch '\''onebranch'\''
 190        |\
 191        | * D
 192        | * G
 193        |/
 194        o H
 195        EOF
 196'
 197
 198test_expect_success 'refs/rewritten/* is worktree-local' '
 199        git worktree add wt &&
 200        cat >wt/script-from-scratch <<-\EOF &&
 201        label xyz
 202        exec GIT_DIR=../.git git rev-parse --verify refs/rewritten/xyz >a || :
 203        exec git rev-parse --verify refs/rewritten/xyz >b
 204        EOF
 205
 206        test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
 207        git -C wt rebase -i HEAD &&
 208        test_must_be_empty wt/a &&
 209        test_cmp_rev HEAD "$(cat wt/b)"
 210'
 211
 212test_expect_success 'post-rewrite hook and fixups work for merges' '
 213        git checkout -b post-rewrite &&
 214        test_commit same1 &&
 215        git reset --hard HEAD^ &&
 216        test_commit same2 &&
 217        git merge -m "to fix up" same1 &&
 218        echo same old same old >same2.t &&
 219        test_tick &&
 220        git commit --fixup HEAD same2.t &&
 221        fixup="$(git rev-parse HEAD)" &&
 222
 223        mkdir -p .git/hooks &&
 224        test_when_finished "rm .git/hooks/post-rewrite" &&
 225        echo "cat >actual" | write_script .git/hooks/post-rewrite &&
 226
 227        test_tick &&
 228        git rebase -i --autosquash -r HEAD^^^ &&
 229        printf "%s %s\n%s %s\n%s %s\n%s %s\n" >expect $(git rev-parse \
 230                $fixup^^2 HEAD^2 \
 231                $fixup^^ HEAD^ \
 232                $fixup^ HEAD \
 233                $fixup HEAD) &&
 234        test_cmp expect actual
 235'
 236
 237test_expect_success 'refuse to merge ancestors of HEAD' '
 238        echo "merge HEAD^" >script-from-scratch &&
 239        test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
 240        before="$(git rev-parse HEAD)" &&
 241        git rebase -i HEAD &&
 242        test_cmp_rev HEAD $before
 243'
 244
 245test_expect_success 'root commits' '
 246        git checkout --orphan unrelated &&
 247        (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
 248         test_commit second-root) &&
 249        test_commit third-root &&
 250        cat >script-from-scratch <<-\EOF &&
 251        pick third-root
 252        label first-branch
 253        reset [new root]
 254        pick second-root
 255        merge first-branch # Merge the 3rd root
 256        EOF
 257        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 258        test_tick &&
 259        git rebase -i --force --root -r &&
 260        test "Parsnip" = "$(git show -s --format=%an HEAD^)" &&
 261        test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) &&
 262        test $(git rev-parse second-root:second-root.t) = \
 263                $(git rev-parse HEAD^:second-root.t) &&
 264        test_cmp_graph HEAD <<-\EOF &&
 265        *   Merge the 3rd root
 266        |\
 267        | * third-root
 268        * second-root
 269        EOF
 270
 271        : fast forward if possible &&
 272        before="$(git rev-parse --verify HEAD)" &&
 273        test_might_fail git config --unset sequence.editor &&
 274        test_tick &&
 275        git rebase -i --root -r &&
 276        test_cmp_rev HEAD $before
 277'
 278
 279test_expect_success 'a "merge" into a root commit is a fast-forward' '
 280        head=$(git rev-parse HEAD) &&
 281        cat >script-from-scratch <<-EOF &&
 282        reset [new root]
 283        merge $head
 284        EOF
 285        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 286        test_tick &&
 287        git rebase -i -r HEAD^ &&
 288        test_cmp_rev HEAD $head
 289'
 290
 291test_expect_success 'A root commit can be a cousin, treat it that way' '
 292        git checkout --orphan khnum &&
 293        test_commit yama &&
 294        git checkout -b asherah master &&
 295        test_commit shamkat &&
 296        git merge --allow-unrelated-histories khnum &&
 297        test_tick &&
 298        git rebase -f -r HEAD^ &&
 299        ! test_cmp_rev HEAD^2 khnum &&
 300        test_cmp_graph HEAD^.. <<-\EOF &&
 301        *   Merge branch '\''khnum'\'' into asherah
 302        |\
 303        | * yama
 304        o shamkat
 305        EOF
 306        test_tick &&
 307        git rebase --rebase-merges=rebase-cousins HEAD^ &&
 308        test_cmp_graph HEAD^.. <<-\EOF
 309        *   Merge branch '\''khnum'\'' into asherah
 310        |\
 311        | * yama
 312        |/
 313        o shamkat
 314        EOF
 315'
 316
 317test_expect_success 'labels that are object IDs are rewritten' '
 318        git checkout -b third B &&
 319        test_tick &&
 320        test_commit I &&
 321        third=$(git rev-parse HEAD) &&
 322        git checkout -b labels master &&
 323        git merge --no-commit third &&
 324        test_tick &&
 325        git commit -m "Merge commit '\''$third'\'' into labels" &&
 326        cp script-from-scratch-orig script-from-scratch &&
 327        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 328        test_tick &&
 329        git rebase -i -r A &&
 330        ! grep "^label $third$" .git/ORIGINAL-TODO
 331'
 332
 333test_done