| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='basic git replay 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 | GIT_AUTHOR_NAME=author@name |
| 11 | GIT_AUTHOR_EMAIL=bogus@email@address |
| 12 | export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL |
| 13 | |
| 14 | test_expect_success 'setup' ' |
| 15 | test_commit A && |
| 16 | test_commit B && |
| 17 | |
| 18 | git switch -c topic1 && |
| 19 | test_commit C && |
| 20 | git switch -c topic2 && |
| 21 | test_commit D && |
| 22 | test_commit E && |
| 23 | git switch topic1 && |
| 24 | test_commit F && |
| 25 | git switch -c topic3 && |
| 26 | test_commit G && |
| 27 | test_commit H && |
| 28 | git switch -c empty && |
| 29 | git commit --allow-empty -m empty && |
| 30 | git switch -c topic4 main && |
| 31 | test_commit I && |
| 32 | test_commit J && |
| 33 | |
| 34 | git switch -c next main && |
| 35 | test_commit K && |
| 36 | git merge -m "Merge topic1" topic1 && |
| 37 | git merge -m "Merge topic2" topic2 && |
| 38 | git merge -m "Merge topic3" topic3 && |
| 39 | >evil && |
| 40 | git add evil && |
| 41 | git commit --amend && |
| 42 | git merge -m "Merge topic4" topic4 && |
| 43 | |
| 44 | git switch main && |
| 45 | test_commit L && |
| 46 | test_commit M && |
| 47 | |
| 48 | git switch --detach topic4 && |
| 49 | test_commit N && |
| 50 | test_commit O && |
| 51 | git switch -c topic-with-merge topic4 && |
| 52 | test_merge P O --no-ff && |
| 53 | git switch main && |
| 54 | |
| 55 | git switch -c conflict B && |
| 56 | test_commit C.conflict C.t conflict |
| 57 | ' |
| 58 | |
| 59 | test_expect_success 'setup bare' ' |
| 60 | git clone --bare . bare |
| 61 | ' |
| 62 | |
| 63 | test_expect_success 'argument to --advance must be a reference' ' |
| 64 | echo "fatal: argument to --advance must be a reference" >expect && |
| 65 | oid=$(git rev-parse main) && |
| 66 | test_must_fail git replay --advance=$oid topic1..topic2 2>actual && |
| 67 | test_cmp expect actual |
| 68 | ' |
| 69 | |
| 70 | test_expect_success '--onto with invalid commit-ish' ' |
| 71 | printf "fatal: ${SQ}refs/not-valid${SQ} is not " >expect && |
| 72 | printf "a valid commit-ish for --onto\n" >>expect && |
| 73 | test_must_fail git replay --onto=refs/not-valid topic1..topic2 2>actual && |
| 74 | test_cmp expect actual |
| 75 | ' |
| 76 | |
| 77 | test_expect_success 'exactly one of --onto, --advance, or --revert is required' ' |
| 78 | echo "error: exactly one of --onto, --advance, or --revert is required" >expect && |
| 79 | test_might_fail git replay -h >>expect && |
| 80 | test_must_fail git replay topic1..topic2 2>actual && |
| 81 | test_cmp expect actual |
| 82 | ' |
| 83 | |
| 84 | test_expect_success 'replay down to root onto another branch' ' |
| 85 | git replay --ref-action=print --onto main topic2 >result && |
| 86 | |
| 87 | test_line_count = 1 result && |
| 88 | |
| 89 | git log --format=%s $(cut -f 3 -d " " result) >actual && |
| 90 | test_write_lines E D C M L B A >expect && |
| 91 | test_cmp expect actual |
| 92 | ' |
| 93 | |
| 94 | test_expect_success '--advance and --contained cannot be used together' ' |
| 95 | test_must_fail git replay --advance=main --contained \ |
| 96 | topic1..topic2 2>actual && |
| 97 | test_grep "cannot be used together" actual |
| 98 | ' |
| 99 | |
| 100 | test_expect_success 'cannot advance target ... ordering would be ill-defined' ' |
| 101 | echo "fatal: ${SQ}--advance${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect && |
| 102 | test_must_fail git replay --advance=main main topic1 topic2 2>actual && |
| 103 | test_cmp expect actual |
| 104 | ' |
| 105 | |
| 106 | test_expect_success 'replaying merge commits is not supported yet' ' |
| 107 | echo "fatal: replaying merge commits is not supported yet!" >expect && |
| 108 | test_must_fail git replay --advance=main main..topic-with-merge 2>actual && |
| 109 | test_cmp expect actual |
| 110 | ' |
| 111 | |
| 112 | test_expect_success 'using replay to rebase two branches, one on top of other' ' |
| 113 | git replay --ref-action=print --onto main topic1..topic2 >result && |
| 114 | |
| 115 | test_line_count = 1 result && |
| 116 | |
| 117 | git log --format=%s $(cut -f 3 -d " " result) >actual && |
| 118 | test_write_lines E D M L B A >expect && |
| 119 | test_cmp expect actual && |
| 120 | |
| 121 | printf "update refs/heads/topic2 " >expect && |
| 122 | printf "%s " $(cut -f 3 -d " " result) >>expect && |
| 123 | git rev-parse topic2 >>expect && |
| 124 | |
| 125 | test_cmp expect result |
| 126 | ' |
| 127 | |
| 128 | test_expect_success 'using replay on bare repo to rebase two branches, one on top of other' ' |
| 129 | git -C bare replay --ref-action=print --onto main topic1..topic2 >result-bare && |
| 130 | test_cmp expect result-bare |
| 131 | ' |
| 132 | |
| 133 | test_expect_success 'using replay to rebase with a conflict' ' |
| 134 | test_expect_code 1 git replay --onto topic1 B..conflict |
| 135 | ' |
| 136 | |
| 137 | test_expect_success 'using replay on bare repo to rebase with a conflict' ' |
| 138 | test_expect_code 1 git -C bare replay --onto topic1 B..conflict |
| 139 | ' |
| 140 | |
| 141 | test_expect_success 'using replay to perform basic cherry-pick' ' |
| 142 | # The differences between this test and previous ones are: |
| 143 | # --advance vs --onto |
| 144 | # 2nd field of result is refs/heads/main vs. refs/heads/topic2 |
| 145 | # 4th field of result is hash for main instead of hash for topic2 |
| 146 | |
| 147 | git replay --ref-action=print --advance main topic1..topic2 >result && |
| 148 | |
| 149 | test_line_count = 1 result && |
| 150 | |
| 151 | git log --format=%s $(cut -f 3 -d " " result) >actual && |
| 152 | test_write_lines E D M L B A >expect && |
| 153 | test_cmp expect actual && |
| 154 | |
| 155 | printf "update refs/heads/main " >expect && |
| 156 | printf "%s " $(cut -f 3 -d " " result) >>expect && |
| 157 | git rev-parse main >>expect && |
| 158 | |
| 159 | test_cmp expect result |
| 160 | ' |
| 161 | |
| 162 | test_expect_success 'using replay on bare repo to perform basic cherry-pick' ' |
| 163 | git -C bare replay --ref-action=print --advance main topic1..topic2 >result-bare && |
| 164 | test_cmp expect result-bare |
| 165 | ' |
| 166 | |
| 167 | test_expect_success 'commits that become empty are dropped' ' |
| 168 | # Save original branches |
| 169 | git for-each-ref --format="update %(refname) %(objectname)" \ |
| 170 | refs/heads/ >original-branches && |
| 171 | test_when_finished "git update-ref --stdin <original-branches && |
| 172 | rm original-branches" && |
| 173 | # Cherry-pick tip of topic1 ("F"), from the middle of A..empty, to main |
| 174 | git replay --advance main topic1^! && |
| 175 | |
| 176 | # Replay all of A..empty onto main (which includes topic1 & thus F |
| 177 | # in the middle) |
| 178 | git replay --onto main --branches --ancestry-path=empty ^A \ |
| 179 | >result && |
| 180 | git log --format="%s%d" L..empty >actual && |
| 181 | test_write_lines >expect \ |
| 182 | "empty (empty)" "H (topic3)" G "C (topic1)" "F (main)" "M (tag: M)" && |
| 183 | test_cmp expect actual |
| 184 | ' |
| 185 | |
| 186 | test_expect_success 'replay on bare repo fails with both --advance and --onto' ' |
| 187 | test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare |
| 188 | ' |
| 189 | |
| 190 | test_expect_success 'replay fails when both --advance and --onto are omitted' ' |
| 191 | test_must_fail git replay topic1..topic2 >result |
| 192 | ' |
| 193 | |
| 194 | test_expect_success 'using replay to also rebase a contained branch' ' |
| 195 | git replay --ref-action=print --contained --onto main main..topic3 >result && |
| 196 | |
| 197 | test_line_count = 2 result && |
| 198 | cut -f 3 -d " " result >new-branch-tips && |
| 199 | |
| 200 | git log --format=%s $(head -n 1 new-branch-tips) >actual && |
| 201 | test_write_lines F C M L B A >expect && |
| 202 | test_cmp expect actual && |
| 203 | |
| 204 | git log --format=%s $(tail -n 1 new-branch-tips) >actual && |
| 205 | test_write_lines H G F C M L B A >expect && |
| 206 | test_cmp expect actual && |
| 207 | |
| 208 | printf "update refs/heads/topic1 " >expect && |
| 209 | printf "%s " $(head -n 1 new-branch-tips) >>expect && |
| 210 | git rev-parse topic1 >>expect && |
| 211 | printf "update refs/heads/topic3 " >>expect && |
| 212 | printf "%s " $(tail -n 1 new-branch-tips) >>expect && |
| 213 | git rev-parse topic3 >>expect && |
| 214 | |
| 215 | test_cmp expect result |
| 216 | ' |
| 217 | |
| 218 | test_expect_success 'using replay on bare repo to also rebase a contained branch' ' |
| 219 | git -C bare replay --ref-action=print --contained --onto main main..topic3 >result-bare && |
| 220 | test_cmp expect result-bare |
| 221 | ' |
| 222 | |
| 223 | test_expect_success 'using replay to rebase multiple divergent branches' ' |
| 224 | git replay --ref-action=print --onto main ^topic1 topic2 topic4 >result && |
| 225 | |
| 226 | test_line_count = 2 result && |
| 227 | cut -f 3 -d " " result >new-branch-tips && |
| 228 | |
| 229 | git log --format=%s $(head -n 1 new-branch-tips) >actual && |
| 230 | test_write_lines E D M L B A >expect && |
| 231 | test_cmp expect actual && |
| 232 | |
| 233 | git log --format=%s $(tail -n 1 new-branch-tips) >actual && |
| 234 | test_write_lines J I M L B A >expect && |
| 235 | test_cmp expect actual && |
| 236 | |
| 237 | printf "update refs/heads/topic2 " >expect && |
| 238 | printf "%s " $(head -n 1 new-branch-tips) >>expect && |
| 239 | git rev-parse topic2 >>expect && |
| 240 | printf "update refs/heads/topic4 " >>expect && |
| 241 | printf "%s " $(tail -n 1 new-branch-tips) >>expect && |
| 242 | git rev-parse topic4 >>expect && |
| 243 | |
| 244 | test_cmp expect result |
| 245 | ' |
| 246 | |
| 247 | test_expect_success 'using replay on bare repo to rebase multiple divergent branches, including contained ones' ' |
| 248 | git -C bare replay --ref-action=print --contained --onto main ^main topic2 topic3 topic4 >result && |
| 249 | |
| 250 | test_line_count = 4 result && |
| 251 | cut -f 3 -d " " result >new-branch-tips && |
| 252 | |
| 253 | >expect && |
| 254 | for i in 2 1 3 4 |
| 255 | do |
| 256 | printf "update refs/heads/topic$i " >>expect && |
| 257 | printf "%s " $(grep topic$i result | cut -f 3 -d " ") >>expect && |
| 258 | git -C bare rev-parse topic$i >>expect || return 1 |
| 259 | done && |
| 260 | |
| 261 | test_cmp expect result && |
| 262 | |
| 263 | test_write_lines F C M L B A >expect1 && |
| 264 | test_write_lines E D C M L B A >expect2 && |
| 265 | test_write_lines H G F C M L B A >expect3 && |
| 266 | test_write_lines J I M L B A >expect4 && |
| 267 | |
| 268 | for i in 1 2 3 4 |
| 269 | do |
| 270 | git -C bare log --format=%s $(grep topic$i result | cut -f 3 -d " ") >actual && |
| 271 | test_cmp expect$i actual || return 1 |
| 272 | done |
| 273 | ' |
| 274 | |
| 275 | test_expect_success 'using replay to update detached HEAD' ' |
| 276 | current_head=$(git branch --show-current) && |
| 277 | test_when_finished git switch "$current_head" && |
| 278 | git switch --detach && |
| 279 | test_commit something && |
| 280 | git replay --ref-action=print --onto HEAD~2 --ref-action=print HEAD~..HEAD >updates && |
| 281 | test_grep "update HEAD " updates |
| 282 | ' |
| 283 | |
| 284 | test_expect_success 'merge.directoryRenames=false' ' |
| 285 | # create a test case that stress-tests the rename caching |
| 286 | git switch -c rename-onto && |
| 287 | |
| 288 | mkdir -p to-rename && |
| 289 | test_commit to-rename/move && |
| 290 | |
| 291 | mkdir -p renamed-directory && |
| 292 | git mv to-rename/move* renamed-directory/ && |
| 293 | test_tick && |
| 294 | git commit -m renamed-directory && |
| 295 | |
| 296 | git switch -c rename-from HEAD^ && |
| 297 | test_commit to-rename/add-a-file && |
| 298 | echo modified >to-rename/add-a-file.t && |
| 299 | test_tick && |
| 300 | git commit -m modified to-rename/add-a-file.t && |
| 301 | |
| 302 | git -c merge.directoryRenames=false replay \ |
| 303 | --onto rename-onto rename-onto..rename-from |
| 304 | ' |
| 305 | |
| 306 | test_expect_success 'default atomic behavior updates refs directly' ' |
| 307 | # Use a separate branch to avoid contaminating topic2 for later tests |
| 308 | git branch test-atomic topic2 && |
| 309 | test_when_finished "git branch -D test-atomic" && |
| 310 | |
| 311 | # Test default atomic behavior (no output, refs updated) |
| 312 | git replay --onto main topic1..test-atomic >output && |
| 313 | test_must_be_empty output && |
| 314 | |
| 315 | # Verify ref was updated |
| 316 | git log --format=%s test-atomic >actual && |
| 317 | test_write_lines E D M L B A >expect && |
| 318 | test_cmp expect actual && |
| 319 | |
| 320 | # Verify reflog message includes SHA of onto commit |
| 321 | git reflog test-atomic -1 --format=%gs >reflog-msg && |
| 322 | ONTO_SHA=$(git rev-parse main) && |
| 323 | echo "replay --onto $ONTO_SHA" >expect-reflog && |
| 324 | test_cmp expect-reflog reflog-msg |
| 325 | ' |
| 326 | |
| 327 | test_expect_success 'atomic behavior in bare repository' ' |
| 328 | # Store original state for cleanup |
| 329 | START=$(git -C bare rev-parse topic2) && |
| 330 | test_when_finished "git -C bare update-ref refs/heads/topic2 $START" && |
| 331 | |
| 332 | # Test atomic updates work in bare repo |
| 333 | git -C bare replay --onto main topic1..topic2 >output && |
| 334 | test_must_be_empty output && |
| 335 | |
| 336 | # Verify ref was updated in bare repo |
| 337 | git -C bare log --format=%s topic2 >actual && |
| 338 | test_write_lines E D M L B A >expect && |
| 339 | test_cmp expect actual |
| 340 | ' |
| 341 | |
| 342 | test_expect_success 'reflog message for --advance mode' ' |
| 343 | # Store original state |
| 344 | START=$(git rev-parse main) && |
| 345 | test_when_finished "git update-ref refs/heads/main $START" && |
| 346 | |
| 347 | # Test --advance mode reflog message |
| 348 | git replay --advance main topic1..topic2 >output && |
| 349 | test_must_be_empty output && |
| 350 | |
| 351 | # Verify reflog message includes --advance and branch name |
| 352 | git reflog main -1 --format=%gs >reflog-msg && |
| 353 | echo "replay --advance main" >expect-reflog && |
| 354 | test_cmp expect-reflog reflog-msg |
| 355 | ' |
| 356 | |
| 357 | test_expect_success 'replay.refAction=print config option' ' |
| 358 | # Store original state |
| 359 | START=$(git rev-parse topic2) && |
| 360 | test_when_finished "git branch -f topic2 $START" && |
| 361 | |
| 362 | # Test with config set to print |
| 363 | test_config replay.refAction print && |
| 364 | git replay --onto main topic1..topic2 >output && |
| 365 | test_line_count = 1 output && |
| 366 | test_grep "^update refs/heads/topic2 " output |
| 367 | ' |
| 368 | |
| 369 | test_expect_success 'replay.refAction=update config option' ' |
| 370 | # Store original state |
| 371 | START=$(git rev-parse topic2) && |
| 372 | test_when_finished "git branch -f topic2 $START" && |
| 373 | |
| 374 | # Test with config set to update |
| 375 | test_config replay.refAction update && |
| 376 | git replay --onto main topic1..topic2 >output && |
| 377 | test_must_be_empty output && |
| 378 | |
| 379 | # Verify ref was updated |
| 380 | git log --format=%s topic2 >actual && |
| 381 | test_write_lines E D M L B A >expect && |
| 382 | test_cmp expect actual |
| 383 | ' |
| 384 | |
| 385 | test_expect_success 'command-line --ref-action overrides config' ' |
| 386 | # Store original state |
| 387 | START=$(git rev-parse topic2) && |
| 388 | test_when_finished "git branch -f topic2 $START" && |
| 389 | |
| 390 | # Set config to update but use --ref-action=print |
| 391 | test_config replay.refAction update && |
| 392 | git replay --ref-action=print --onto main topic1..topic2 >output && |
| 393 | test_line_count = 1 output && |
| 394 | test_grep "^update refs/heads/topic2 " output |
| 395 | ' |
| 396 | |
| 397 | test_expect_success 'invalid replay.refAction value' ' |
| 398 | test_config replay.refAction invalid && |
| 399 | test_must_fail git replay --onto main topic1..topic2 2>error && |
| 400 | test_grep "invalid.*replay.refAction.*value" error |
| 401 | ' |
| 402 | |
| 403 | test_expect_success 'argument to --revert must be a reference' ' |
| 404 | echo "fatal: argument to --revert must be a reference" >expect && |
| 405 | oid=$(git rev-parse main) && |
| 406 | test_must_fail git replay --revert=$oid topic1..topic2 2>actual && |
| 407 | test_cmp expect actual |
| 408 | ' |
| 409 | |
| 410 | test_expect_success 'cannot revert with multiple sources' ' |
| 411 | echo "fatal: ${SQ}--revert${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect && |
| 412 | test_must_fail git replay --revert main main topic1 topic2 2>actual && |
| 413 | test_cmp expect actual |
| 414 | ' |
| 415 | |
| 416 | test_expect_success 'using replay --revert to revert commits' ' |
| 417 | # Reuse existing topic4 branch (has commits I and J on top of main) |
| 418 | START=$(git rev-parse topic4) && |
| 419 | test_when_finished "git branch -f topic4 $START" && |
| 420 | |
| 421 | # Revert commits I and J |
| 422 | git replay --revert topic4 topic4~2..topic4 && |
| 423 | |
| 424 | # Verify the revert commits were created (newest-first ordering |
| 425 | # means J is reverted first, then I on top) |
| 426 | git log --format=%s -4 topic4 >actual && |
| 427 | cat >expect <<-\EOF && |
| 428 | Revert "I" |
| 429 | Revert "J" |
| 430 | J |
| 431 | I |
| 432 | EOF |
| 433 | test_cmp expect actual && |
| 434 | |
| 435 | # Verify commit message format includes hash (tip is Revert "I") |
| 436 | test_commit_message topic4 <<-EOF && |
| 437 | Revert "I" |
| 438 | |
| 439 | This reverts commit $(git rev-parse I). |
| 440 | EOF |
| 441 | |
| 442 | # Verify reflog message |
| 443 | git reflog topic4 -1 --format=%gs >reflog-msg && |
| 444 | echo "replay --revert topic4" >expect-reflog && |
| 445 | test_cmp expect-reflog reflog-msg |
| 446 | ' |
| 447 | |
| 448 | test_expect_success 'using replay --revert in bare repo' ' |
| 449 | # Reuse existing topic4 in bare repo |
| 450 | START=$(git -C bare rev-parse topic4) && |
| 451 | test_when_finished "git -C bare update-ref refs/heads/topic4 $START" && |
| 452 | |
| 453 | # Revert commit J in bare repo |
| 454 | git -C bare replay --revert topic4 topic4~1..topic4 && |
| 455 | |
| 456 | # Verify revert was created |
| 457 | git -C bare log -1 --format=%s topic4 >actual && |
| 458 | echo "Revert \"J\"" >expect && |
| 459 | test_cmp expect actual |
| 460 | ' |
| 461 | |
| 462 | test_expect_success 'revert of revert uses Reapply' ' |
| 463 | # Use topic4 and first revert J, then revert the revert |
| 464 | START=$(git rev-parse topic4) && |
| 465 | test_when_finished "git branch -f topic4 $START" && |
| 466 | |
| 467 | # First revert J |
| 468 | git replay --revert topic4 topic4~1..topic4 && |
| 469 | REVERT_J=$(git rev-parse topic4) && |
| 470 | |
| 471 | # Now revert the revert - should become Reapply |
| 472 | git replay --revert topic4 topic4~1..topic4 && |
| 473 | |
| 474 | # Verify Reapply prefix and message format |
| 475 | test_commit_message topic4 <<-EOF |
| 476 | Reapply "J" |
| 477 | |
| 478 | This reverts commit $REVERT_J. |
| 479 | EOF |
| 480 | ' |
| 481 | |
| 482 | test_expect_success 'git replay --revert with conflict' ' |
| 483 | # conflict branch has C.conflict which conflicts with topic1s C |
| 484 | test_expect_code 1 git replay --revert conflict B..topic1 |
| 485 | ' |
| 486 | |
| 487 | test_expect_success 'git replay --revert incompatible with --contained' ' |
| 488 | test_must_fail git replay --revert topic4 --contained topic4~1..topic4 2>error && |
| 489 | test_grep "cannot be used together" error |
| 490 | ' |
| 491 | |
| 492 | test_expect_success 'git replay --revert incompatible with --onto' ' |
| 493 | test_must_fail git replay --revert topic4 --onto main topic4~1..topic4 2>error && |
| 494 | test_grep "cannot be used together" error |
| 495 | ' |
| 496 | |
| 497 | test_expect_success 'git replay --revert incompatible with --advance' ' |
| 498 | test_must_fail git replay --revert topic4 --advance main topic4~1..topic4 2>error && |
| 499 | test_grep "cannot be used together" error |
| 500 | ' |
| 501 | |
| 502 | test_expect_success 'using --onto with --ref' ' |
| 503 | git branch test-ref-onto topic2 && |
| 504 | test_when_finished "git branch -D test-ref-onto" && |
| 505 | |
| 506 | git replay --ref-action=print --onto=main --ref=refs/heads/test-ref-onto topic1..topic2 >result && |
| 507 | |
| 508 | test_line_count = 1 result && |
| 509 | test_grep "^update refs/heads/test-ref-onto " result && |
| 510 | |
| 511 | git log --format=%s $(cut -f 3 -d " " result) >actual && |
| 512 | test_write_lines E D M L B A >expect && |
| 513 | test_cmp expect actual |
| 514 | ' |
| 515 | |
| 516 | test_expect_success 'using --advance with --ref' ' |
| 517 | git branch test-ref-advance main && |
| 518 | git branch test-ref-target main && |
| 519 | test_when_finished "git branch -D test-ref-advance test-ref-target" && |
| 520 | |
| 521 | git replay --ref-action=print --advance=test-ref-advance --ref=refs/heads/test-ref-target topic1..topic2 >result && |
| 522 | |
| 523 | test_line_count = 1 result && |
| 524 | test_grep "^update refs/heads/test-ref-target " result |
| 525 | ' |
| 526 | |
| 527 | test_expect_success 'using --revert with --ref' ' |
| 528 | git branch test-ref-revert topic4 && |
| 529 | git branch test-ref-revert-target topic4 && |
| 530 | test_when_finished "git branch -D test-ref-revert test-ref-revert-target" && |
| 531 | |
| 532 | git replay --ref-action=print --revert=test-ref-revert --ref=refs/heads/test-ref-revert-target topic4~1..topic4 >result && |
| 533 | |
| 534 | test_line_count = 1 result && |
| 535 | test_grep "^update refs/heads/test-ref-revert-target " result |
| 536 | ' |
| 537 | |
| 538 | test_expect_success '--ref is incompatible with --contained' ' |
| 539 | test_must_fail git replay --onto=main --ref=refs/heads/main --contained topic1..topic2 2>err && |
| 540 | test_grep "cannot be used together" err |
| 541 | ' |
| 542 | |
| 543 | test_expect_success '--ref with nonexistent fully-qualified ref' ' |
| 544 | test_when_finished "git update-ref -d refs/heads/new-branch" && |
| 545 | |
| 546 | git replay --onto=main --ref=refs/heads/new-branch topic1..topic2 && |
| 547 | |
| 548 | git log --format=%s -2 new-branch >actual && |
| 549 | test_write_lines E D >expect && |
| 550 | test_cmp expect actual |
| 551 | ' |
| 552 | |
| 553 | test_expect_success '--ref must be a valid refname' ' |
| 554 | test_must_fail git replay --onto=main --ref="refs/heads/bad..ref" topic1..topic2 2>err && |
| 555 | test_grep "is not a valid refname" err |
| 556 | ' |
| 557 | |
| 558 | test_expect_success '--ref requires fully qualified ref' ' |
| 559 | test_must_fail git replay --onto=main --ref=main topic1..topic2 2>err && |
| 560 | test_grep "is not a valid refname" err |
| 561 | ' |
| 562 | |
| 563 | test_expect_success '--onto with --ref rejects multiple revision ranges' ' |
| 564 | test_must_fail git replay --onto=main --ref=refs/heads/topic2 ^topic1 topic2 topic4 2>err && |
| 565 | test_grep "cannot be used with multiple revision ranges" err |
| 566 | ' |
| 567 | |
| 568 | test_done |