| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='git rebase --continue tests' |
| 4 | |
| 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
| 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | . "$TEST_DIRECTORY"/lib-rebase.sh |
| 11 | |
| 12 | set_fake_editor |
| 13 | |
| 14 | test_expect_success 'setup' ' |
| 15 | test_commit "commit-new-file-F1" F1 1 && |
| 16 | test_commit "commit-new-file-F2" F2 2 && |
| 17 | |
| 18 | git checkout -b topic HEAD^ && |
| 19 | test_commit "commit-new-file-F2-on-topic-branch" F2 22 && |
| 20 | |
| 21 | git checkout main |
| 22 | ' |
| 23 | |
| 24 | test_expect_success 'merge based rebase --continue with works with touched file' ' |
| 25 | rm -fr .git/rebase-* && |
| 26 | git reset --hard && |
| 27 | git checkout main && |
| 28 | |
| 29 | FAKE_LINES="edit 1" git rebase -i HEAD^ && |
| 30 | test-tool chmtime =-60 F1 && |
| 31 | git rebase --continue |
| 32 | ' |
| 33 | |
| 34 | test_expect_success 'merge based rebase --continue removes .git/MERGE_MSG' ' |
| 35 | git checkout -f --detach topic && |
| 36 | |
| 37 | test_must_fail git rebase --onto main HEAD^ && |
| 38 | git read-tree --reset -u HEAD && |
| 39 | test_path_is_file .git/MERGE_MSG && |
| 40 | git rebase --continue && |
| 41 | test_path_is_missing .git/MERGE_MSG |
| 42 | ' |
| 43 | |
| 44 | test_expect_success 'apply based rebase --continue works with touched file' ' |
| 45 | rm -fr .git/rebase-* && |
| 46 | git reset --hard && |
| 47 | git checkout main && |
| 48 | |
| 49 | test_must_fail git rebase --apply --onto main main topic && |
| 50 | echo "Resolved" >F2 && |
| 51 | git add F2 && |
| 52 | test-tool chmtime =-60 F1 && |
| 53 | git rebase --continue |
| 54 | ' |
| 55 | |
| 56 | test_expect_success 'rebase --continue can not be used with other options' ' |
| 57 | test_must_fail git rebase -v --continue && |
| 58 | test_must_fail git rebase --continue -v |
| 59 | ' |
| 60 | |
| 61 | test_expect_success 'rebase --continue remembers merge strategy and options' ' |
| 62 | rm -fr .git/rebase-* && |
| 63 | git reset --hard commit-new-file-F2-on-topic-branch && |
| 64 | test_commit "commit-new-file-F3-on-topic-branch" F3 32 && |
| 65 | test_when_finished "rm -fr test-bin" && |
| 66 | mkdir test-bin && |
| 67 | |
| 68 | write_script test-bin/git-merge-funny <<-\EOF && |
| 69 | printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual |
| 70 | shift 3 && |
| 71 | exec git merge-recursive "$@" |
| 72 | EOF |
| 73 | |
| 74 | cat >expect <<-\EOF && |
| 75 | [7] |
| 76 | [--option=arg with space] |
| 77 | [--op"tion\] |
| 78 | [--new |
| 79 | line ] |
| 80 | [--] |
| 81 | EOF |
| 82 | |
| 83 | rm -f actual && |
| 84 | ( |
| 85 | PATH=./test-bin:$PATH && |
| 86 | test_must_fail git rebase -s funny -X"option=arg with space" \ |
| 87 | -Xop\"tion\\ -X"new${LF}line " main topic |
| 88 | ) && |
| 89 | test_cmp expect actual && |
| 90 | rm actual && |
| 91 | echo "Resolved" >F2 && |
| 92 | git add F2 && |
| 93 | ( |
| 94 | PATH=./test-bin:$PATH && |
| 95 | git rebase --continue |
| 96 | ) && |
| 97 | test_cmp expect actual |
| 98 | ' |
| 99 | |
| 100 | test_expect_success 'rebase -r passes merge strategy options correctly' ' |
| 101 | rm -fr .git/rebase-* && |
| 102 | git reset --hard commit-new-file-F3-on-topic-branch && |
| 103 | test_commit merge-theirs && |
| 104 | git reset --hard HEAD^ && |
| 105 | test_commit some-other-commit && |
| 106 | test_tick && |
| 107 | git merge --no-ff merge-theirs && |
| 108 | FAKE_LINES="1 3 edit 4 5 7 8 9" git rebase -i -f -r -m \ |
| 109 | -s recursive --strategy-option=theirs HEAD~2 && |
| 110 | test_commit force-change-ours && |
| 111 | git rebase --continue |
| 112 | ' |
| 113 | |
| 114 | test_expect_success '--skip after failed fixup cleans commit message' ' |
| 115 | test_when_finished "test_might_fail git rebase --abort" && |
| 116 | git checkout -b with-conflicting-fixup && |
| 117 | test_commit wants-fixup && |
| 118 | test_commit "fixup 1" wants-fixup.t 1 wants-fixup-1 && |
| 119 | test_commit "fixup 2" wants-fixup.t 2 wants-fixup-2 && |
| 120 | test_commit "fixup 3" wants-fixup.t 3 wants-fixup-3 && |
| 121 | test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \ |
| 122 | git rebase -i HEAD~4 && |
| 123 | |
| 124 | : now there is a conflict, and comments in the commit message && |
| 125 | test_commit_message HEAD <<-\EOF && |
| 126 | # This is a combination of 2 commits. |
| 127 | # This is the 1st commit message: |
| 128 | |
| 129 | wants-fixup |
| 130 | |
| 131 | # The commit message #2 will be skipped: |
| 132 | |
| 133 | # fixup 1 |
| 134 | EOF |
| 135 | |
| 136 | : skip and continue && |
| 137 | echo "cp \"\$1\" .git/copy.txt" | write_script copy-editor.sh && |
| 138 | (test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) && |
| 139 | |
| 140 | : the user should not have had to edit the commit message && |
| 141 | test_path_is_missing .git/copy.txt && |
| 142 | |
| 143 | : now the comments in the commit message should have been cleaned up && |
| 144 | test_commit_message HEAD -m wants-fixup && |
| 145 | |
| 146 | : now, let us ensure that "squash" is handled correctly && |
| 147 | git reset --hard wants-fixup-3 && |
| 148 | test_must_fail env FAKE_LINES="1 squash 2 squash 1 squash 3 squash 1" \ |
| 149 | git rebase -i HEAD~4 && |
| 150 | |
| 151 | : the second squash failed, but there are two more in the chain && |
| 152 | (test_set_editor "$PWD/copy-editor.sh" && |
| 153 | test_must_fail git rebase --skip) && |
| 154 | |
| 155 | : not the final squash, no need to edit the commit message && |
| 156 | test_path_is_missing .git/copy.txt && |
| 157 | |
| 158 | : The first and third squashes succeeded, therefore: && |
| 159 | test_commit_message HEAD <<-\EOF && |
| 160 | # This is a combination of 3 commits. |
| 161 | # This is the 1st commit message: |
| 162 | |
| 163 | wants-fixup |
| 164 | |
| 165 | # This is the commit message #2: |
| 166 | |
| 167 | fixup 1 |
| 168 | |
| 169 | # This is the commit message #3: |
| 170 | |
| 171 | fixup 2 |
| 172 | EOF |
| 173 | |
| 174 | (test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) && |
| 175 | test_commit_message HEAD <<-\EOF && |
| 176 | wants-fixup |
| 177 | |
| 178 | fixup 1 |
| 179 | |
| 180 | fixup 2 |
| 181 | EOF |
| 182 | |
| 183 | : Final squash failed, but there was still a squash && |
| 184 | head -n1 .git/copy.txt >first-line && |
| 185 | test_grep "# This is a combination of 3 commits" first-line && |
| 186 | test_grep "# This is the commit message #3:" .git/copy.txt |
| 187 | ' |
| 188 | |
| 189 | test_expect_success 'setup rerere database' ' |
| 190 | rm -fr .git/rebase-* && |
| 191 | git reset --hard commit-new-file-F3-on-topic-branch && |
| 192 | git checkout main && |
| 193 | test_commit "commit-new-file-F3" F3 3 && |
| 194 | test_config rerere.enabled true && |
| 195 | git update-ref refs/heads/topic commit-new-file-F3-on-topic-branch && |
| 196 | test_must_fail git rebase -m main topic && |
| 197 | echo "Resolved" >F2 && |
| 198 | cp F2 expected-F2 && |
| 199 | git add F2 && |
| 200 | test_must_fail git rebase --continue && |
| 201 | echo "Resolved" >F3 && |
| 202 | cp F3 expected-F3 && |
| 203 | git add F3 && |
| 204 | git rebase --continue && |
| 205 | git reset --hard topic@{1} |
| 206 | ' |
| 207 | |
| 208 | prepare () { |
| 209 | rm -fr .git/rebase-* && |
| 210 | git reset --hard commit-new-file-F3-on-topic-branch && |
| 211 | git checkout main && |
| 212 | test_config rerere.enabled true |
| 213 | } |
| 214 | |
| 215 | test_rerere_autoupdate () { |
| 216 | action=$1 && |
| 217 | test_expect_success "rebase $action --continue remembers --rerere-autoupdate" ' |
| 218 | prepare && |
| 219 | test_must_fail git rebase $action --rerere-autoupdate main topic && |
| 220 | test_cmp expected-F2 F2 && |
| 221 | git diff-files --quiet && |
| 222 | test_must_fail git rebase --continue && |
| 223 | test_cmp expected-F3 F3 && |
| 224 | git diff-files --quiet && |
| 225 | git rebase --continue |
| 226 | ' |
| 227 | |
| 228 | test_expect_success "rebase $action --continue honors rerere.autoUpdate" ' |
| 229 | prepare && |
| 230 | test_config rerere.autoupdate true && |
| 231 | test_must_fail git rebase $action main topic && |
| 232 | test_cmp expected-F2 F2 && |
| 233 | git diff-files --quiet && |
| 234 | test_must_fail git rebase --continue && |
| 235 | test_cmp expected-F3 F3 && |
| 236 | git diff-files --quiet && |
| 237 | git rebase --continue |
| 238 | ' |
| 239 | |
| 240 | test_expect_success "rebase $action --continue remembers --no-rerere-autoupdate" ' |
| 241 | prepare && |
| 242 | test_config rerere.autoupdate true && |
| 243 | test_must_fail git rebase $action --no-rerere-autoupdate main topic && |
| 244 | test_cmp expected-F2 F2 && |
| 245 | test_must_fail git diff-files --quiet && |
| 246 | git add F2 && |
| 247 | test_must_fail git rebase --continue && |
| 248 | test_cmp expected-F3 F3 && |
| 249 | test_must_fail git diff-files --quiet && |
| 250 | git add F3 && |
| 251 | git rebase --continue |
| 252 | ' |
| 253 | } |
| 254 | |
| 255 | test_rerere_autoupdate --apply |
| 256 | test_rerere_autoupdate -m |
| 257 | GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR |
| 258 | test_rerere_autoupdate -i |
| 259 | unset GIT_SEQUENCE_EDITOR |
| 260 | |
| 261 | test_expect_success 'the todo command "break" works' ' |
| 262 | rm -f execed && |
| 263 | FAKE_LINES="break b exec_>execed" git rebase -i HEAD && |
| 264 | test_path_is_missing execed && |
| 265 | git rebase --continue && |
| 266 | test_path_is_missing execed && |
| 267 | git rebase --continue && |
| 268 | test_path_is_file execed |
| 269 | ' |
| 270 | |
| 271 | test_expect_success 'patch file is removed before break command' ' |
| 272 | test_when_finished "git rebase --abort" && |
| 273 | cat >todo <<-\EOF && |
| 274 | pick commit-new-file-F2-on-topic-branch |
| 275 | break |
| 276 | EOF |
| 277 | |
| 278 | ( |
| 279 | set_replace_editor todo && |
| 280 | test_must_fail git rebase -i --onto commit-new-file-F2 HEAD |
| 281 | ) && |
| 282 | test_path_is_file .git/rebase-merge/patch && |
| 283 | echo 22>F2 && |
| 284 | git add F2 && |
| 285 | git rebase --continue && |
| 286 | test_path_is_missing .git/rebase-merge/patch |
| 287 | ' |
| 288 | |
| 289 | test_expect_success '--reschedule-failed-exec' ' |
| 290 | test_when_finished "git rebase --abort" && |
| 291 | test_must_fail git rebase -x false --reschedule-failed-exec HEAD^ && |
| 292 | grep "^exec false" .git/rebase-merge/git-rebase-todo && |
| 293 | git rebase --abort && |
| 294 | test_must_fail git -c rebase.rescheduleFailedExec=true \ |
| 295 | rebase -x false HEAD^ 2>err && |
| 296 | grep "^exec false" .git/rebase-merge/git-rebase-todo && |
| 297 | test_grep "has been rescheduled" err |
| 298 | ' |
| 299 | |
| 300 | test_expect_success 'rebase.rescheduleFailedExec only affects `rebase -i`' ' |
| 301 | test_config rebase.rescheduleFailedExec true && |
| 302 | test_must_fail git rebase -x false HEAD^ && |
| 303 | grep "^exec false" .git/rebase-merge/git-rebase-todo && |
| 304 | git rebase --abort && |
| 305 | git rebase HEAD^ |
| 306 | ' |
| 307 | |
| 308 | test_expect_success 'rebase.rescheduleFailedExec=true & --no-reschedule-failed-exec' ' |
| 309 | test_when_finished "git rebase --abort" && |
| 310 | test_config rebase.rescheduleFailedExec true && |
| 311 | test_must_fail git rebase -x false --no-reschedule-failed-exec HEAD~2 && |
| 312 | test_must_fail git rebase --continue 2>err && |
| 313 | ! grep "has been rescheduled" err |
| 314 | ' |
| 315 | |
| 316 | test_expect_success 'new rebase.rescheduleFailedExec=true setting in an ongoing rebase is ignored' ' |
| 317 | test_when_finished "git rebase --abort" && |
| 318 | test_must_fail git rebase -x false HEAD~2 && |
| 319 | test_config rebase.rescheduleFailedExec true && |
| 320 | test_must_fail git rebase --continue 2>err && |
| 321 | ! grep "has been rescheduled" err |
| 322 | ' |
| 323 | |
| 324 | test_expect_success 'there is no --no-reschedule-failed-exec in an ongoing rebase' ' |
| 325 | test_when_finished "git rebase --abort" && |
| 326 | test_must_fail git rebase -x false HEAD~2 && |
| 327 | test_expect_code 129 git rebase --continue --no-reschedule-failed-exec && |
| 328 | test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec |
| 329 | ' |
| 330 | |
| 331 | test_expect_success !WITH_BREAKING_CHANGES 'no change in comment character due to conflicts markers with core.commentChar=auto' ' |
| 332 | git checkout -b branch-a && |
| 333 | test_commit A F1 && |
| 334 | git checkout -b branch-b HEAD^ && |
| 335 | test_commit B F1 && |
| 336 | test_must_fail git rebase branch-a && |
| 337 | printf "B\nA\n" >F1 && |
| 338 | git add F1 && |
| 339 | GIT_EDITOR="cat >actual" git -c core.commentChar=auto rebase --continue && |
| 340 | # Check that "#" is still the comment character. |
| 341 | test_grep "^# Changes to be committed" actual |
| 342 | ' |
| 343 | |
| 344 | test_orig_head_helper () { |
| 345 | test_when_finished 'git rebase --abort && |
| 346 | git checkout topic && |
| 347 | git reset --hard commit-new-file-F2-on-topic-branch' && |
| 348 | git update-ref -d ORIG_HEAD && |
| 349 | test_must_fail git rebase "$@" && |
| 350 | test_cmp_rev ORIG_HEAD commit-new-file-F2-on-topic-branch |
| 351 | } |
| 352 | |
| 353 | test_orig_head () { |
| 354 | type=$1 |
| 355 | test_expect_success "rebase $type sets ORIG_HEAD correctly" ' |
| 356 | git checkout topic && |
| 357 | git reset --hard commit-new-file-F2-on-topic-branch && |
| 358 | test_orig_head_helper $type main |
| 359 | ' |
| 360 | |
| 361 | test_expect_success "rebase $type <upstream> <branch> sets ORIG_HEAD correctly" ' |
| 362 | git checkout main && |
| 363 | test_orig_head_helper $type main topic |
| 364 | ' |
| 365 | } |
| 366 | |
| 367 | test_orig_head --apply |
| 368 | test_orig_head --merge |
| 369 | |
| 370 | test_done |