just playing with tangled
at ig/vimdiffwarn 2982 lines 87 kB view raw
1// Copyright 2022 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use crate::common::create_commit; 16use crate::common::CommandOutput; 17use crate::common::TestEnvironment; 18use crate::common::TestWorkDir; 19 20#[test] 21fn test_rebase_invalid() { 22 let test_env = TestEnvironment::default(); 23 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 24 let work_dir = test_env.work_dir("repo"); 25 26 create_commit(&work_dir, "a", &[]); 27 create_commit(&work_dir, "b", &["a"]); 28 29 // Missing destination 30 let output = work_dir.run_jj(["rebase"]); 31 insta::assert_snapshot!(output, @r" 32 ------- stderr ------- 33 error: the following required arguments were not provided: 34 <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 35 36 Usage: jj rebase <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 37 38 For more information, try '--help'. 39 [EOF] 40 [exit status: 2] 41 "); 42 43 // Both -r and -s 44 let output = work_dir.run_jj(["rebase", "-r", "a", "-s", "a", "-d", "b"]); 45 insta::assert_snapshot!(output, @r" 46 ------- stderr ------- 47 error: the argument '--revisions <REVSETS>' cannot be used with '--source <REVSETS>' 48 49 Usage: jj rebase --revisions <REVSETS> <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 50 51 For more information, try '--help'. 52 [EOF] 53 [exit status: 2] 54 "); 55 56 // Both -b and -s 57 let output = work_dir.run_jj(["rebase", "-b", "a", "-s", "a", "-d", "b"]); 58 insta::assert_snapshot!(output, @r" 59 ------- stderr ------- 60 error: the argument '--branch <REVSETS>' cannot be used with '--source <REVSETS>' 61 62 Usage: jj rebase --branch <REVSETS> <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 63 64 For more information, try '--help'. 65 [EOF] 66 [exit status: 2] 67 "); 68 69 // Both -d and --after 70 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b", "--after", "b"]); 71 insta::assert_snapshot!(output, @r" 72 ------- stderr ------- 73 error: the argument '--destination <REVSETS>' cannot be used with '--insert-after <REVSETS>' 74 75 Usage: jj rebase --revisions <REVSETS> <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 76 77 For more information, try '--help'. 78 [EOF] 79 [exit status: 2] 80 "); 81 82 // Both -d and --before 83 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b", "--before", "b"]); 84 insta::assert_snapshot!(output, @r" 85 ------- stderr ------- 86 error: the argument '--destination <REVSETS>' cannot be used with '--insert-before <REVSETS>' 87 88 Usage: jj rebase --revisions <REVSETS> <--destination <REVSETS>|--insert-after <REVSETS>|--insert-before <REVSETS>> 89 90 For more information, try '--help'. 91 [EOF] 92 [exit status: 2] 93 "); 94 95 // Rebase onto self with -r 96 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "a"]); 97 insta::assert_snapshot!(output, @r" 98 ------- stderr ------- 99 Error: Cannot rebase 2443ea76b0b1 onto itself 100 [EOF] 101 [exit status: 1] 102 "); 103 104 // Rebase root with -r 105 let output = work_dir.run_jj(["rebase", "-r", "root()", "-d", "a"]); 106 insta::assert_snapshot!(output, @r" 107 ------- stderr ------- 108 Error: The root commit 000000000000 is immutable 109 [EOF] 110 [exit status: 1] 111 "); 112 113 // Rebase onto descendant with -s 114 let output = work_dir.run_jj(["rebase", "-s", "a", "-d", "b"]); 115 insta::assert_snapshot!(output, @r" 116 ------- stderr ------- 117 Error: Cannot rebase 2443ea76b0b1 onto descendant 1394f625cbbd 118 [EOF] 119 [exit status: 1] 120 "); 121} 122 123#[test] 124fn test_rebase_empty_sets() { 125 let test_env = TestEnvironment::default(); 126 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 127 let work_dir = test_env.work_dir("repo"); 128 129 create_commit(&work_dir, "a", &[]); 130 create_commit(&work_dir, "b", &["a"]); 131 132 // TODO: Make all of these say "Nothing changed"? 133 let output = work_dir.run_jj(["rebase", "-r=none()", "-d=b"]); 134 insta::assert_snapshot!(output, @r" 135 ------- stderr ------- 136 Nothing changed. 137 [EOF] 138 "); 139 let output = work_dir.run_jj(["rebase", "-s=none()", "-d=b"]); 140 insta::assert_snapshot!(output, @r" 141 ------- stderr ------- 142 Error: Revset `none()` didn't resolve to any revisions 143 [EOF] 144 [exit status: 1] 145 "); 146 let output = work_dir.run_jj(["rebase", "-b=none()", "-d=b"]); 147 insta::assert_snapshot!(output, @r" 148 ------- stderr ------- 149 Error: Revset `none()` didn't resolve to any revisions 150 [EOF] 151 [exit status: 1] 152 "); 153 // Empty because "b..a" is empty 154 let output = work_dir.run_jj(["rebase", "-b=a", "-d=b"]); 155 insta::assert_snapshot!(output, @r" 156 ------- stderr ------- 157 Nothing changed. 158 [EOF] 159 "); 160} 161 162#[test] 163fn test_rebase_bookmark() { 164 let test_env = TestEnvironment::default(); 165 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 166 let work_dir = test_env.work_dir("repo"); 167 168 create_commit(&work_dir, "a", &[]); 169 create_commit(&work_dir, "b", &["a"]); 170 create_commit(&work_dir, "c", &["b"]); 171 create_commit(&work_dir, "d", &["b"]); 172 create_commit(&work_dir, "e", &["a"]); 173 // Test the setup 174 insta::assert_snapshot!(get_log_output(&work_dir), @r" 175 @ e: a 176 │ ○ d: b 177 │ │ ○ c: b 178 │ ├─╯ 179 │ ○ b: a 180 ├─╯ 181 ○ a 182 183 [EOF] 184 "); 185 186 let output = work_dir.run_jj(["rebase", "-b", "c", "-d", "e"]); 187 insta::assert_snapshot!(output, @r" 188 ------- stderr ------- 189 Rebased 3 commits onto destination 190 [EOF] 191 "); 192 insta::assert_snapshot!(get_log_output(&work_dir), @r" 193 ○ d: b 194 │ ○ c: b 195 ├─╯ 196 ○ b: e 197 @ e: a 198 ○ a 199 200 [EOF] 201 "); 202 203 // Test rebasing multiple bookmarks at once 204 work_dir.run_jj(["undo"]).success(); 205 let output = work_dir.run_jj(["rebase", "-b=e", "-b=d", "-d=b"]); 206 insta::assert_snapshot!(output, @r" 207 ------- stderr ------- 208 Skipped rebase of 1 commits that were already in place 209 Rebased 1 commits onto destination 210 Working copy (@) now at: znkkpsqq 9ca2a154 e | e 211 Parent commit (@-) : zsuskuln 1394f625 b | b 212 Added 1 files, modified 0 files, removed 0 files 213 [EOF] 214 "); 215 insta::assert_snapshot!(get_log_output(&work_dir), @r" 216 @ e: b 217 │ ○ d: b 218 ├─╯ 219 │ ○ c: b 220 ├─╯ 221 ○ b: a 222 ○ a 223 224 [EOF] 225 "); 226 227 // Same test but with more than one revision per argument 228 work_dir.run_jj(["undo"]).success(); 229 let output = work_dir.run_jj(["rebase", "-b=e|d", "-d=b"]); 230 insta::assert_snapshot!(output, @r" 231 ------- stderr ------- 232 Error: Revset `e|d` resolved to more than one revision 233 Hint: The revset `e|d` resolved to these revisions: 234 znkkpsqq e52756c8 e | e 235 vruxwmqv 514fa6b2 d | d 236 Hint: Prefix the expression with `all:` to allow any number of revisions (i.e. `all:e|d`). 237 [EOF] 238 [exit status: 1] 239 "); 240 let output = work_dir.run_jj(["rebase", "-b=all:e|d", "-d=b"]); 241 insta::assert_snapshot!(output, @r" 242 ------- stderr ------- 243 Skipped rebase of 1 commits that were already in place 244 Rebased 1 commits onto destination 245 Working copy (@) now at: znkkpsqq 817e3fb0 e | e 246 Parent commit (@-) : zsuskuln 1394f625 b | b 247 Added 1 files, modified 0 files, removed 0 files 248 [EOF] 249 "); 250 insta::assert_snapshot!(get_log_output(&work_dir), @r" 251 @ e: b 252 │ ○ d: b 253 ├─╯ 254 │ ○ c: b 255 ├─╯ 256 ○ b: a 257 ○ a 258 259 [EOF] 260 "); 261} 262 263#[test] 264fn test_rebase_bookmark_with_merge() { 265 let test_env = TestEnvironment::default(); 266 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 267 let work_dir = test_env.work_dir("repo"); 268 269 create_commit(&work_dir, "a", &[]); 270 create_commit(&work_dir, "b", &["a"]); 271 create_commit(&work_dir, "c", &[]); 272 create_commit(&work_dir, "d", &["c"]); 273 create_commit(&work_dir, "e", &["a", "d"]); 274 // Test the setup 275 insta::assert_snapshot!(get_log_output(&work_dir), @r" 276 @ e: a d 277 ├─╮ 278 │ ○ d: c 279 │ ○ c 280 │ │ ○ b: a 281 ├───╯ 282 ○ │ a 283 ├─╯ 284 285 [EOF] 286 "); 287 288 let output = work_dir.run_jj(["rebase", "-b", "d", "-d", "b"]); 289 insta::assert_snapshot!(output, @r" 290 ------- stderr ------- 291 Rebased 3 commits onto destination 292 Working copy (@) now at: znkkpsqq 5f8a3db2 e | e 293 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 294 Parent commit (@-) : vruxwmqv 1677f795 d | d 295 Added 1 files, modified 0 files, removed 0 files 296 [EOF] 297 "); 298 insta::assert_snapshot!(get_log_output(&work_dir), @r" 299 @ e: a d 300 ├─╮ 301 │ ○ d: c 302 │ ○ c: b 303 │ ○ b: a 304 ├─╯ 305 ○ a 306 307 [EOF] 308 "); 309 310 work_dir.run_jj(["undo"]).success(); 311 let output = work_dir.run_jj(["rebase", "-d", "b"]); 312 insta::assert_snapshot!(output, @r" 313 ------- stderr ------- 314 Rebased 3 commits onto destination 315 Working copy (@) now at: znkkpsqq a331ac11 e | e 316 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 317 Parent commit (@-) : vruxwmqv 3d0f3644 d | d 318 Added 1 files, modified 0 files, removed 0 files 319 [EOF] 320 "); 321 insta::assert_snapshot!(get_log_output(&work_dir), @r" 322 @ e: a d 323 ├─╮ 324 │ ○ d: c 325 │ ○ c: b 326 │ ○ b: a 327 ├─╯ 328 ○ a 329 330 [EOF] 331 "); 332} 333 334#[test] 335fn test_rebase_single_revision() { 336 let test_env = TestEnvironment::default(); 337 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 338 let work_dir = test_env.work_dir("repo"); 339 340 create_commit(&work_dir, "a", &[]); 341 create_commit(&work_dir, "b", &["a"]); 342 create_commit(&work_dir, "c", &["a"]); 343 create_commit(&work_dir, "d", &["b", "c"]); 344 create_commit(&work_dir, "e", &["d"]); 345 // Test the setup 346 insta::assert_snapshot!(get_log_output(&work_dir), @r" 347 @ e: d 348 ○ d: b c 349 ├─╮ 350 │ ○ c: a 351 ○ │ b: a 352 ├─╯ 353 ○ a 354 355 [EOF] 356 "); 357 358 // Descendants of the rebased commit "c" should be rebased onto parents. First 359 // we test with a non-merge commit. 360 let output = work_dir.run_jj(["rebase", "-r", "c", "-d", "b"]); 361 insta::assert_snapshot!(output, @r" 362 ------- stderr ------- 363 Rebased 1 commits onto destination 364 Rebased 2 descendant commits 365 Working copy (@) now at: znkkpsqq 2668ffbe e | e 366 Parent commit (@-) : vruxwmqv 7b370c85 d | d 367 Added 0 files, modified 0 files, removed 1 files 368 [EOF] 369 "); 370 insta::assert_snapshot!(get_log_output(&work_dir), @r" 371 @ e: d 372 ○ d: b a 373 ├─╮ 374 │ │ ○ c: b 375 ├───╯ 376 ○ │ b: a 377 ├─╯ 378 ○ a 379 380 [EOF] 381 "); 382 work_dir.run_jj(["undo"]).success(); 383 384 // Now, let's try moving the merge commit. After, both parents of "d" ("b" and 385 // "c") should become parents of "e". 386 let output = work_dir.run_jj(["rebase", "-r", "d", "-d", "a"]); 387 insta::assert_snapshot!(output, @r" 388 ------- stderr ------- 389 Rebased 1 commits onto destination 390 Rebased 1 descendant commits 391 Working copy (@) now at: znkkpsqq ed210c15 e | e 392 Parent commit (@-) : zsuskuln 1394f625 b | b 393 Parent commit (@-) : royxmykx c0cb3a0b c | c 394 Added 0 files, modified 0 files, removed 1 files 395 [EOF] 396 "); 397 insta::assert_snapshot!(get_log_output(&work_dir), @r" 398 @ e: b c 399 ├─╮ 400 │ ○ c: a 401 ○ │ b: a 402 ├─╯ 403 │ ○ d: a 404 ├─╯ 405 ○ a 406 407 [EOF] 408 "); 409} 410 411#[test] 412fn test_rebase_single_revision_merge_parent() { 413 let test_env = TestEnvironment::default(); 414 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 415 let work_dir = test_env.work_dir("repo"); 416 417 create_commit(&work_dir, "a", &[]); 418 create_commit(&work_dir, "b", &[]); 419 create_commit(&work_dir, "c", &["b"]); 420 create_commit(&work_dir, "d", &["a", "c"]); 421 // Test the setup 422 insta::assert_snapshot!(get_log_output(&work_dir), @r" 423 @ d: a c 424 ├─╮ 425 │ ○ c: b 426 │ ○ b 427 ○ │ a 428 ├─╯ 429 430 [EOF] 431 "); 432 433 // Descendants of the rebased commit should be rebased onto parents, and if 434 // the descendant is a merge commit, it shouldn't forget its other parents. 435 let output = work_dir.run_jj(["rebase", "-r", "c", "-d", "a"]); 436 insta::assert_snapshot!(output, @r" 437 ------- stderr ------- 438 Rebased 1 commits onto destination 439 Rebased 1 descendant commits 440 Working copy (@) now at: vruxwmqv a37531e8 d | d 441 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 442 Parent commit (@-) : zsuskuln d370aee1 b | b 443 Added 0 files, modified 0 files, removed 1 files 444 [EOF] 445 "); 446 insta::assert_snapshot!(get_log_output(&work_dir), @r" 447 @ d: a b 448 ├─╮ 449 │ ○ b 450 │ │ ○ c: a 451 ├───╯ 452 ○ │ a 453 ├─╯ 454 455 [EOF] 456 "); 457} 458 459#[test] 460fn test_rebase_multiple_revisions() { 461 let test_env = TestEnvironment::default(); 462 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 463 let work_dir = test_env.work_dir("repo"); 464 465 create_commit(&work_dir, "a", &[]); 466 create_commit(&work_dir, "b", &["a"]); 467 create_commit(&work_dir, "c", &["b"]); 468 create_commit(&work_dir, "d", &["a"]); 469 create_commit(&work_dir, "e", &["d"]); 470 create_commit(&work_dir, "f", &["c", "e"]); 471 create_commit(&work_dir, "g", &["f"]); 472 create_commit(&work_dir, "h", &["g"]); 473 create_commit(&work_dir, "i", &["f"]); 474 // Test the setup 475 insta::assert_snapshot!(get_log_output(&work_dir), @r" 476 @ i: f 477 │ ○ h: g 478 │ ○ g: f 479 ├─╯ 480 ○ f: c e 481 ├─╮ 482 │ ○ e: d 483 │ ○ d: a 484 ○ │ c: b 485 ○ │ b: a 486 ├─╯ 487 ○ a 488 489 [EOF] 490 "); 491 492 // Test with two non-related non-merge commits. 493 let output = work_dir.run_jj(["rebase", "-r", "c", "-r", "e", "-d", "a"]); 494 insta::assert_snapshot!(output, @r" 495 ------- stderr ------- 496 Rebased 2 commits onto destination 497 Rebased 4 descendant commits 498 Working copy (@) now at: xznxytkn 016685dc i | i 499 Parent commit (@-) : kmkuslsw e04d3932 f | f 500 Added 0 files, modified 0 files, removed 2 files 501 [EOF] 502 "); 503 insta::assert_snapshot!(get_log_output(&work_dir), @r" 504 @ i: f 505 │ ○ h: g 506 │ ○ g: f 507 ├─╯ 508 ○ f: b d 509 ├─╮ 510 │ ○ d: a 511 ○ │ b: a 512 ├─╯ 513 │ ○ e: a 514 ├─╯ 515 │ ○ c: a 516 ├─╯ 517 ○ a 518 519 [EOF] 520 "); 521 work_dir.run_jj(["undo"]).success(); 522 523 // Test with two related non-merge commits. Since "b" is a parent of "c", when 524 // rebasing commits "b" and "c", their ancestry relationship should be 525 // preserved. 526 let output = work_dir.run_jj(["rebase", "-r", "b", "-r", "c", "-d", "e"]); 527 insta::assert_snapshot!(output, @r" 528 ------- stderr ------- 529 Rebased 2 commits onto destination 530 Rebased 4 descendant commits 531 Working copy (@) now at: xznxytkn 94538385 i | i 532 Parent commit (@-) : kmkuslsw dae8d293 f | f 533 Added 0 files, modified 0 files, removed 2 files 534 [EOF] 535 "); 536 insta::assert_snapshot!(get_log_output(&work_dir), @r" 537 @ i: f 538 │ ○ h: g 539 │ ○ g: f 540 ├─╯ 541 ○ f: a e 542 ├─╮ 543 │ │ ○ c: b 544 │ │ ○ b: e 545 │ ├─╯ 546 │ ○ e: d 547 │ ○ d: a 548 ├─╯ 549 ○ a 550 551 [EOF] 552 "); 553 work_dir.run_jj(["undo"]).success(); 554 555 // Test with a subgraph containing a merge commit. Since the merge commit "f" 556 // was extracted, its descendants which are not part of the subgraph will 557 // inherit its descendants which are not in the subtree ("c" and "d"). 558 // "f" will retain its parent "c" since "c" is outside the target set, and not 559 // a descendant of any new children. 560 let output = work_dir.run_jj(["rebase", "-r", "e::g", "-d", "a"]); 561 insta::assert_snapshot!(output, @r" 562 ------- stderr ------- 563 Rebased 3 commits onto destination 564 Rebased 2 descendant commits 565 Working copy (@) now at: xznxytkn 1868ded4 i | i 566 Parent commit (@-) : royxmykx 7e4fbf4f c | c 567 Parent commit (@-) : vruxwmqv 4cc44fbf d | d 568 Added 0 files, modified 0 files, removed 2 files 569 [EOF] 570 "); 571 insta::assert_snapshot!(get_log_output(&work_dir), @r" 572 @ i: c d 573 ├─╮ 574 │ │ ○ h: c d 575 ╭─┬─╯ 576 │ ○ d: a 577 │ │ ○ g: f 578 │ │ ○ f: c e 579 ╭───┤ 580 │ │ ○ e: a 581 │ ├─╯ 582 ○ │ c: b 583 ○ │ b: a 584 ├─╯ 585 ○ a 586 587 [EOF] 588 "); 589 work_dir.run_jj(["undo"]).success(); 590 591 // Test with commits in a disconnected subgraph. The subgraph has the 592 // relationship d->e->f->g->h, but only "d", "f" and "h" are in the set of 593 // rebased commits. "d" should be a new parent of "f", and "f" should be a 594 // new parent of "h". "f" will retain its parent "c" since "c" is outside the 595 // target set, and not a descendant of any new children. 596 let output = work_dir.run_jj(["rebase", "-r", "d", "-r", "f", "-r", "h", "-d", "b"]); 597 insta::assert_snapshot!(output, @r" 598 ------- stderr ------- 599 Rebased 3 commits onto destination 600 Rebased 3 descendant commits 601 Working copy (@) now at: xznxytkn 9cfd1635 i | i 602 Parent commit (@-) : royxmykx 7e4fbf4f c | c 603 Parent commit (@-) : znkkpsqq ecf9a1d5 e | e 604 Added 0 files, modified 0 files, removed 2 files 605 [EOF] 606 "); 607 insta::assert_snapshot!(get_log_output(&work_dir), @r" 608 @ i: c e 609 ├─╮ 610 │ │ ○ g: c e 611 ╭─┬─╯ 612 │ ○ e: a 613 │ │ ○ h: f 614 │ │ ○ f: c d 615 ╭───┤ 616 │ │ ○ d: b 617 ○ │ │ c: b 618 ├───╯ 619 ○ │ b: a 620 ├─╯ 621 ○ a 622 623 [EOF] 624 "); 625 work_dir.run_jj(["undo"]).success(); 626 627 // Test rebasing a subgraph onto its descendants. 628 let output = work_dir.run_jj(["rebase", "-r", "d::e", "-d", "i"]); 629 insta::assert_snapshot!(output, @r" 630 ------- stderr ------- 631 Rebased 2 commits onto destination 632 Rebased 4 descendant commits 633 Working copy (@) now at: xznxytkn 5d911e5c i | i 634 Parent commit (@-) : kmkuslsw d1bfda8c f | f 635 Added 0 files, modified 0 files, removed 2 files 636 [EOF] 637 "); 638 insta::assert_snapshot!(get_log_output(&work_dir), @r" 639 ○ e: d 640 ○ d: i 641 @ i: f 642 │ ○ h: g 643 │ ○ g: f 644 ├─╯ 645 ○ f: c a 646 ├─╮ 647 ○ │ c: b 648 ○ │ b: a 649 ├─╯ 650 ○ a 651 652 [EOF] 653 "); 654} 655 656#[test] 657fn test_rebase_revision_onto_descendant() { 658 let test_env = TestEnvironment::default(); 659 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 660 let work_dir = test_env.work_dir("repo"); 661 662 create_commit(&work_dir, "base", &[]); 663 create_commit(&work_dir, "a", &["base"]); 664 create_commit(&work_dir, "b", &["base"]); 665 create_commit(&work_dir, "merge", &["b", "a"]); 666 // Test the setup 667 insta::assert_snapshot!(get_log_output(&work_dir), @r" 668 @ merge: b a 669 ├─╮ 670 │ ○ a: base 671 ○ │ b: base 672 ├─╯ 673 ○ base 674 675 [EOF] 676 "); 677 let setup_opid = work_dir.current_operation_id(); 678 679 // Simpler example 680 let output = work_dir.run_jj(["rebase", "-r", "base", "-d", "a"]); 681 insta::assert_snapshot!(output, @r" 682 ------- stderr ------- 683 Rebased 1 commits onto destination 684 Rebased 3 descendant commits 685 Working copy (@) now at: vruxwmqv bff4a4eb merge | merge 686 Parent commit (@-) : royxmykx c84e900d b | b 687 Parent commit (@-) : zsuskuln d57db87b a | a 688 Added 0 files, modified 0 files, removed 1 files 689 [EOF] 690 "); 691 insta::assert_snapshot!(get_log_output(&work_dir), @r" 692 @ merge: b a 693 ├─╮ 694 ○ │ b 695 │ │ ○ base: a 696 │ ├─╯ 697 │ ○ a 698 ├─╯ 699 700 [EOF] 701 "); 702 703 // Now, let's rebase onto the descendant merge 704 let output = work_dir.run_jj(["op", "restore", &setup_opid]); 705 insta::assert_snapshot!(output, @r" 706 ------- stderr ------- 707 Restored to operation: 60e340690be6 (2001-02-03 08:05:15) create bookmark merge pointing to commit b05964d109522cd06e48f1a2661e1a0f58be0984 708 Working copy (@) now at: vruxwmqv b05964d1 merge | merge 709 Parent commit (@-) : royxmykx cea87a87 b | b 710 Parent commit (@-) : zsuskuln 2c5b7858 a | a 711 Added 1 files, modified 0 files, removed 0 files 712 [EOF] 713 "); 714 let output = work_dir.run_jj(["rebase", "-r", "base", "-d", "merge"]); 715 insta::assert_snapshot!(output, @r" 716 ------- stderr ------- 717 Rebased 1 commits onto destination 718 Rebased 3 descendant commits 719 Working copy (@) now at: vruxwmqv 986b7a49 merge | merge 720 Parent commit (@-) : royxmykx c07c677c b | b 721 Parent commit (@-) : zsuskuln abc90087 a | a 722 Added 0 files, modified 0 files, removed 1 files 723 [EOF] 724 "); 725 insta::assert_snapshot!(get_log_output(&work_dir), @r" 726 ○ base: merge 727 @ merge: b a 728 ├─╮ 729 │ ○ a 730 ○ │ b 731 ├─╯ 732 733 [EOF] 734 "); 735 736 // TODO(ilyagr): These will be good tests for `jj rebase --insert-after` and 737 // `--insert-before`, once those are implemented. 738} 739 740#[test] 741fn test_rebase_multiple_destinations() { 742 let test_env = TestEnvironment::default(); 743 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 744 let work_dir = test_env.work_dir("repo"); 745 746 create_commit(&work_dir, "a", &[]); 747 create_commit(&work_dir, "b", &[]); 748 create_commit(&work_dir, "c", &[]); 749 // Test the setup 750 insta::assert_snapshot!(get_log_output(&work_dir), @r" 751 @ c 752 │ ○ b 753 ├─╯ 754 │ ○ a 755 ├─╯ 756 757 [EOF] 758 "); 759 760 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b", "-d", "c"]); 761 insta::assert_snapshot!(output, @r" 762 ------- stderr ------- 763 Rebased 1 commits onto destination 764 [EOF] 765 "); 766 insta::assert_snapshot!(get_log_output(&work_dir), @r" 767 ○ a: b c 768 ├─╮ 769 │ @ c 770 ○ │ b 771 ├─╯ 772 773 [EOF] 774 "); 775 776 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b|c"]); 777 insta::assert_snapshot!(output, @r" 778 ------- stderr ------- 779 Error: Revset `b|c` resolved to more than one revision 780 Hint: The revset `b|c` resolved to these revisions: 781 royxmykx fe2e8e8b c | c 782 zsuskuln d370aee1 b | b 783 Hint: Prefix the expression with `all:` to allow any number of revisions (i.e. `all:b|c`). 784 [EOF] 785 [exit status: 1] 786 "); 787 788 // try with 'all:' and succeed 789 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "all:b|c"]); 790 insta::assert_snapshot!(output, @r" 791 ------- stderr ------- 792 Rebased 1 commits onto destination 793 [EOF] 794 "); 795 insta::assert_snapshot!(get_log_output(&work_dir), @r" 796 ○ a: c b 797 ├─╮ 798 │ ○ b 799 @ │ c 800 ├─╯ 801 802 [EOF] 803 "); 804 805 // undo and do it again, but with 'ui.always-allow-large-revsets' 806 work_dir.run_jj(["undo"]).success(); 807 work_dir 808 .run_jj([ 809 "rebase", 810 "--config=ui.always-allow-large-revsets=true", 811 "-r=a", 812 "-d=b|c", 813 ]) 814 .success(); 815 insta::assert_snapshot!(get_log_output(&work_dir), @r" 816 ○ a: c b 817 ├─╮ 818 │ ○ b 819 @ │ c 820 ├─╯ 821 822 [EOF] 823 "); 824 825 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b", "-d", "b"]); 826 insta::assert_snapshot!(output, @r" 827 ------- stderr ------- 828 Error: More than one revset resolved to revision d370aee184ba 829 [EOF] 830 [exit status: 1] 831 "); 832 833 // Same error with 'all:' if there is overlap. 834 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "all:b|c", "-d", "b"]); 835 insta::assert_snapshot!(output, @r" 836 ------- stderr ------- 837 Error: More than one revset resolved to revision d370aee184ba 838 [EOF] 839 [exit status: 1] 840 "); 841 842 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "b", "-d", "root()"]); 843 insta::assert_snapshot!(output, @r" 844 ------- stderr ------- 845 Error: The Git backend does not support creating merge commits with the root commit as one of the parents. 846 [EOF] 847 [exit status: 1] 848 "); 849} 850 851#[test] 852fn test_rebase_with_descendants() { 853 let test_env = TestEnvironment::default(); 854 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 855 let work_dir = test_env.work_dir("repo"); 856 857 create_commit(&work_dir, "a", &[]); 858 create_commit(&work_dir, "b", &[]); 859 create_commit(&work_dir, "c", &["a", "b"]); 860 create_commit(&work_dir, "d", &["c"]); 861 // Test the setup 862 insta::assert_snapshot!(get_log_output(&work_dir), @r" 863 @ d: c 864 ○ c: a b 865 ├─╮ 866 │ ○ b 867 ○ │ a 868 ├─╯ 869 870 [EOF] 871 "); 872 873 let output = work_dir.run_jj(["rebase", "-s", "b", "-d", "a"]); 874 insta::assert_snapshot!(output, @r" 875 ------- stderr ------- 876 Rebased 3 commits onto destination 877 Working copy (@) now at: vruxwmqv 705832bd d | d 878 Parent commit (@-) : royxmykx 57c7246a c | c 879 [EOF] 880 "); 881 insta::assert_snapshot!(get_log_output(&work_dir), @r" 882 @ d: c 883 ○ c: a b 884 ├─╮ 885 │ ○ b: a 886 ├─╯ 887 ○ a 888 889 [EOF] 890 "); 891 892 // Rebase several subtrees at once. 893 work_dir.run_jj(["undo"]).success(); 894 let output = work_dir.run_jj(["rebase", "-s=c", "-s=d", "-d=a"]); 895 insta::assert_snapshot!(output, @r" 896 ------- stderr ------- 897 Rebased 2 commits onto destination 898 Working copy (@) now at: vruxwmqv 92c2bc9a d | d 899 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 900 Added 0 files, modified 0 files, removed 2 files 901 [EOF] 902 "); 903 insta::assert_snapshot!(get_log_output(&work_dir), @r" 904 @ d: a 905 │ ○ c: a 906 ├─╯ 907 ○ a 908 │ ○ b 909 ├─╯ 910 911 [EOF] 912 "); 913 914 work_dir.run_jj(["undo"]).success(); 915 // Reminder of the setup 916 insta::assert_snapshot!(get_log_output(&work_dir), @r" 917 @ d: c 918 ○ c: a b 919 ├─╮ 920 │ ○ b 921 ○ │ a 922 ├─╯ 923 924 [EOF] 925 "); 926 927 // `d` was a descendant of `b`, and both are moved to be direct descendants of 928 // `a`. `c` remains a descendant of `b`. 929 let output = work_dir.run_jj(["rebase", "-s=b", "-s=d", "-d=a"]); 930 insta::assert_snapshot!(output, @r" 931 ------- stderr ------- 932 Rebased 3 commits onto destination 933 Working copy (@) now at: vruxwmqv f1e71cb7 d | d 934 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 935 Added 0 files, modified 0 files, removed 2 files 936 [EOF] 937 "); 938 insta::assert_snapshot!(get_log_output(&work_dir), @r" 939 @ d: a 940 │ ○ c: a b 941 ╭─┤ 942 │ ○ b: a 943 ├─╯ 944 ○ a 945 946 [EOF] 947 "); 948 949 // Same test as above, but with multiple commits per argument 950 work_dir.run_jj(["undo"]).success(); 951 let output = work_dir.run_jj(["rebase", "-s=b|d", "-d=a"]); 952 insta::assert_snapshot!(output, @r" 953 ------- stderr ------- 954 Error: Revset `b|d` resolved to more than one revision 955 Hint: The revset `b|d` resolved to these revisions: 956 vruxwmqv df54a9fd d | d 957 zsuskuln d370aee1 b | b 958 Hint: Prefix the expression with `all:` to allow any number of revisions (i.e. `all:b|d`). 959 [EOF] 960 [exit status: 1] 961 "); 962 let output = work_dir.run_jj(["rebase", "-s=all:b|d", "-d=a"]); 963 insta::assert_snapshot!(output, @r" 964 ------- stderr ------- 965 Rebased 3 commits onto destination 966 Working copy (@) now at: vruxwmqv d17539f7 d | d 967 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 968 Added 0 files, modified 0 files, removed 2 files 969 [EOF] 970 "); 971 insta::assert_snapshot!(get_log_output(&work_dir), @r" 972 @ d: a 973 │ ○ c: a b 974 ╭─┤ 975 │ ○ b: a 976 ├─╯ 977 ○ a 978 979 [EOF] 980 "); 981} 982 983#[test] 984fn test_rebase_error_revision_does_not_exist() { 985 let test_env = TestEnvironment::default(); 986 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 987 let work_dir = test_env.work_dir("repo"); 988 989 work_dir.run_jj(["describe", "-m", "one"]).success(); 990 work_dir 991 .run_jj(["bookmark", "create", "-r@", "b-one"]) 992 .success(); 993 work_dir.run_jj(["new", "-r", "@-", "-m", "two"]).success(); 994 995 let output = work_dir.run_jj(["rebase", "-b", "b-one", "-d", "this"]); 996 insta::assert_snapshot!(output, @r" 997 ------- stderr ------- 998 Error: Revision `this` doesn't exist 999 [EOF] 1000 [exit status: 1] 1001 "); 1002 1003 let output = work_dir.run_jj(["rebase", "-b", "this", "-d", "b-one"]); 1004 insta::assert_snapshot!(output, @r" 1005 ------- stderr ------- 1006 Error: Revision `this` doesn't exist 1007 [EOF] 1008 [exit status: 1] 1009 "); 1010} 1011 1012// This behavior illustrates https://github.com/jj-vcs/jj/issues/2600 1013#[test] 1014fn test_rebase_with_child_and_descendant_bug_2600() { 1015 let test_env = TestEnvironment::default(); 1016 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1017 let work_dir = test_env.work_dir("repo"); 1018 1019 create_commit(&work_dir, "notroot", &[]); 1020 create_commit(&work_dir, "base", &["notroot"]); 1021 create_commit(&work_dir, "a", &["base"]); 1022 create_commit(&work_dir, "b", &["base", "a"]); 1023 create_commit(&work_dir, "c", &["b"]); 1024 let setup_opid = work_dir.current_operation_id(); 1025 1026 // Test the setup 1027 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1028 @ c: b 1029 ○ b: base a 1030 ├─╮ 1031 │ ○ a: base 1032 ├─╯ 1033 ○ base: notroot 1034 ○ notroot 10351036 [EOF] 1037 "); 1038 1039 // ===================== rebase -s tests ================= 1040 // This should be a no-op 1041 let output = work_dir.run_jj(["rebase", "-s", "base", "-d", "notroot"]); 1042 insta::assert_snapshot!(output, @r" 1043 ------- stderr ------- 1044 Skipped rebase of 4 commits that were already in place 1045 Nothing changed. 1046 [EOF] 1047 "); 1048 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1049 @ c: b 1050 ○ b: base a 1051 ├─╮ 1052 │ ○ a: base 1053 ├─╯ 1054 ○ base: notroot 1055 ○ notroot 10561057 [EOF] 1058 "); 1059 1060 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1061 // This should be a no-op 1062 let output = work_dir.run_jj(["rebase", "-s", "a", "-d", "base"]); 1063 insta::assert_snapshot!(output, @r" 1064 ------- stderr ------- 1065 Skipped rebase of 3 commits that were already in place 1066 Nothing changed. 1067 [EOF] 1068 "); 1069 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1070 @ c: b 1071 ○ b: base a 1072 ├─╮ 1073 │ ○ a: base 1074 ├─╯ 1075 ○ base: notroot 1076 ○ notroot 10771078 [EOF] 1079 "); 1080 1081 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1082 let output = work_dir.run_jj(["rebase", "-s", "a", "-d", "root()"]); 1083 insta::assert_snapshot!(output, @r" 1084 ------- stderr ------- 1085 Rebased 3 commits onto destination 1086 Working copy (@) now at: znkkpsqq cf8ecff5 c | c 1087 Parent commit (@-) : vruxwmqv 24e1a270 b | b 1088 [EOF] 1089 "); 1090 // Commit "a" should be rebased onto the root commit. Commit "b" should have 1091 // "base" and "a" as parents as before. 1092 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1093 @ c: b 1094 ○ b: base a 1095 ├─╮ 1096 │ ○ a 1097 ○ │ base: notroot 1098 ○ │ notroot 1099 ├─╯ 11001101 [EOF] 1102 "); 1103 1104 // ===================== rebase -b tests ================= 1105 // ====== Reminder of the setup ========= 1106 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1107 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1108 @ c: b 1109 ○ b: base a 1110 ├─╮ 1111 │ ○ a: base 1112 ├─╯ 1113 ○ base: notroot 1114 ○ notroot 11151116 [EOF] 1117 "); 1118 1119 // The commits in roots(base..c), i.e. commit "a" should be rebased onto "base", 1120 // which is a no-op 1121 let output = work_dir.run_jj(["rebase", "-b", "c", "-d", "base"]); 1122 insta::assert_snapshot!(output, @r" 1123 ------- stderr ------- 1124 Skipped rebase of 3 commits that were already in place 1125 Nothing changed. 1126 [EOF] 1127 "); 1128 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1129 @ c: b 1130 ○ b: base a 1131 ├─╮ 1132 │ ○ a: base 1133 ├─╯ 1134 ○ base: notroot 1135 ○ notroot 11361137 [EOF] 1138 "); 1139 1140 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1141 let output = work_dir.run_jj(["rebase", "-b", "c", "-d", "a"]); 1142 insta::assert_snapshot!(output, @r" 1143 ------- stderr ------- 1144 Rebased 2 commits onto destination 1145 Working copy (@) now at: znkkpsqq 76914dcc c | c 1146 Parent commit (@-) : vruxwmqv f73f03c7 b | b 1147 [EOF] 1148 "); 1149 // The commits in roots(a..c), i.e. commit "b" should be rebased onto "a", 1150 // which means "b" loses its "base" parent 1151 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1152 @ c: b 1153 ○ b: a 1154 ○ a: base 1155 ○ base: notroot 1156 ○ notroot 11571158 [EOF] 1159 "); 1160 1161 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1162 // This should be a no-op 1163 let output = work_dir.run_jj(["rebase", "-b", "a", "-d", "root()"]); 1164 insta::assert_snapshot!(output, @r" 1165 ------- stderr ------- 1166 Skipped rebase of 5 commits that were already in place 1167 Nothing changed. 1168 [EOF] 1169 "); 1170 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1171 @ c: b 1172 ○ b: base a 1173 ├─╮ 1174 │ ○ a: base 1175 ├─╯ 1176 ○ base: notroot 1177 ○ notroot 11781179 [EOF] 1180 "); 1181 1182 // ===================== rebase -r tests ================= 1183 // ====== Reminder of the setup ========= 1184 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1185 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1186 @ c: b 1187 ○ b: base a 1188 ├─╮ 1189 │ ○ a: base 1190 ├─╯ 1191 ○ base: notroot 1192 ○ notroot 11931194 [EOF] 1195 "); 1196 1197 let output = work_dir.run_jj(["rebase", "-r", "base", "-d", "root()"]); 1198 insta::assert_snapshot!(output, @r" 1199 ------- stderr ------- 1200 Rebased 1 commits onto destination 1201 Rebased 3 descendant commits 1202 Working copy (@) now at: znkkpsqq 45371aaf c | c 1203 Parent commit (@-) : vruxwmqv c0a76bf4 b | b 1204 Added 0 files, modified 0 files, removed 1 files 1205 [EOF] 1206 "); 1207 // The user would expect unsimplified ancestry here. 1208 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1209 @ c: b 1210 ○ b: notroot a 1211 ├─╮ 1212 │ ○ a: notroot 1213 ├─╯ 1214 ○ notroot 1215 │ ○ base 1216 ├─╯ 12171218 [EOF] 1219 "); 1220 1221 // This tests the algorithm for rebasing onto descendants. The result should 1222 // have unsimplified ancestry. 1223 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1224 let output = work_dir.run_jj(["rebase", "-r", "base", "-d", "b"]); 1225 insta::assert_snapshot!(output, @r" 1226 ------- stderr ------- 1227 Rebased 1 commits onto destination 1228 Rebased 3 descendant commits 1229 Working copy (@) now at: znkkpsqq e28fa972 c | c 1230 Parent commit (@-) : vruxwmqv 8d0eeb6a b | b 1231 Added 0 files, modified 0 files, removed 1 files 1232 [EOF] 1233 "); 1234 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1235 @ c: b 1236 │ ○ base: b 1237 ├─╯ 1238 ○ b: notroot a 1239 ├─╮ 1240 │ ○ a: notroot 1241 ├─╯ 1242 ○ notroot 12431244 [EOF] 1245 "); 1246 1247 // This tests the algorithm for rebasing onto descendants. The result should 1248 // have unsimplified ancestry. 1249 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1250 let output = work_dir.run_jj(["rebase", "-r", "base", "-d", "a"]); 1251 insta::assert_snapshot!(output, @r" 1252 ------- stderr ------- 1253 Rebased 1 commits onto destination 1254 Rebased 3 descendant commits 1255 Working copy (@) now at: znkkpsqq a9da974c c | c 1256 Parent commit (@-) : vruxwmqv 0072139c b | b 1257 Added 0 files, modified 0 files, removed 1 files 1258 [EOF] 1259 "); 1260 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1261 @ c: b 1262 ○ b: notroot a 1263 ├─╮ 1264 │ │ ○ base: a 1265 │ ├─╯ 1266 │ ○ a: notroot 1267 ├─╯ 1268 ○ notroot 12691270 [EOF] 1271 "); 1272 1273 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1274 // ====== Reminder of the setup ========= 1275 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1276 @ c: b 1277 ○ b: base a 1278 ├─╮ 1279 │ ○ a: base 1280 ├─╯ 1281 ○ base: notroot 1282 ○ notroot 12831284 [EOF] 1285 "); 1286 1287 let output = work_dir.run_jj(["rebase", "-r", "a", "-d", "root()"]); 1288 insta::assert_snapshot!(output, @r" 1289 ------- stderr ------- 1290 Rebased 1 commits onto destination 1291 Rebased 2 descendant commits 1292 Working copy (@) now at: znkkpsqq 7210b05e c | c 1293 Parent commit (@-) : vruxwmqv da3f7511 b | b 1294 Added 0 files, modified 0 files, removed 1 files 1295 [EOF] 1296 "); 1297 // In this case, it is unclear whether the user would always prefer unsimplified 1298 // ancestry (whether `b` should also be a direct child of the root commit). 1299 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1300 @ c: b 1301 ○ b: base 1302 ○ base: notroot 1303 ○ notroot 1304 │ ○ a 1305 ├─╯ 13061307 [EOF] 1308 "); 1309 1310 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1311 let output = work_dir.run_jj(["rebase", "-r", "b", "-d", "root()"]); 1312 insta::assert_snapshot!(output, @r" 1313 ------- stderr ------- 1314 Rebased 1 commits onto destination 1315 Rebased 1 descendant commits 1316 Working copy (@) now at: znkkpsqq f280545e c | c 1317 Parent commit (@-) : zsuskuln 0a7fb8f6 base | base 1318 Parent commit (@-) : royxmykx 86a06598 a | a 1319 Added 0 files, modified 0 files, removed 1 files 1320 [EOF] 1321 "); 1322 // The user would expect unsimplified ancestry here. 1323 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1324 @ c: base a 1325 ├─╮ 1326 │ ○ a: base 1327 ├─╯ 1328 ○ base: notroot 1329 ○ notroot 1330 │ ○ b 1331 ├─╯ 13321333 [EOF] 1334 "); 1335 1336 // This tests the algorithm for rebasing onto descendants. The result should 1337 // have unsimplified ancestry. 1338 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1339 let output = work_dir.run_jj(["rebase", "-r", "b", "-d", "c"]); 1340 insta::assert_snapshot!(output, @r" 1341 ------- stderr ------- 1342 Rebased 1 commits onto destination 1343 Rebased 1 descendant commits 1344 Working copy (@) now at: znkkpsqq c0a7cd80 c | c 1345 Parent commit (@-) : zsuskuln 0a7fb8f6 base | base 1346 Parent commit (@-) : royxmykx 86a06598 a | a 1347 Added 0 files, modified 0 files, removed 1 files 1348 [EOF] 1349 "); 1350 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1351 ○ b: c 1352 @ c: base a 1353 ├─╮ 1354 │ ○ a: base 1355 ├─╯ 1356 ○ base: notroot 1357 ○ notroot 13581359 [EOF] 1360 "); 1361 1362 // In this test, the commit with weird ancestry is not rebased (neither directly 1363 // nor indirectly). 1364 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1365 let output = work_dir.run_jj(["rebase", "-r", "c", "-d", "a"]); 1366 insta::assert_snapshot!(output, @r" 1367 ------- stderr ------- 1368 Rebased 1 commits onto destination 1369 Working copy (@) now at: znkkpsqq 7a3bc050 c | c 1370 Parent commit (@-) : royxmykx 86a06598 a | a 1371 Added 0 files, modified 0 files, removed 1 files 1372 [EOF] 1373 "); 1374 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1375 @ c: a 1376 │ ○ b: base a 1377 ╭─┤ 1378 ○ │ a: base 1379 ├─╯ 1380 ○ base: notroot 1381 ○ notroot 13821383 [EOF] 1384 "); 1385} 1386 1387#[test] 1388fn test_rebase_after() { 1389 let test_env = TestEnvironment::default(); 1390 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1391 let work_dir = test_env.work_dir("repo"); 1392 1393 create_commit(&work_dir, "a", &[]); 1394 create_commit(&work_dir, "b1", &["a"]); 1395 create_commit(&work_dir, "b2", &["b1"]); 1396 create_commit(&work_dir, "b3", &["a"]); 1397 create_commit(&work_dir, "b4", &["b3"]); 1398 create_commit(&work_dir, "c", &["b2", "b4"]); 1399 create_commit(&work_dir, "d", &["c"]); 1400 create_commit(&work_dir, "e", &["c"]); 1401 create_commit(&work_dir, "f", &["e"]); 1402 // Test the setup 1403 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1404 @ f: e 1405 ○ e: c 1406 │ ○ d: c 1407 ├─╯ 1408 ○ c: b2 b4 1409 ├─╮ 1410 │ ○ b4: b3 1411 │ ○ b3: a 1412 ○ │ b2: b1 1413 ○ │ b1: a 1414 ├─╯ 1415 ○ a 14161417 [EOF] 1418 "); 1419 let setup_opid = work_dir.current_operation_id(); 1420 1421 // Rebasing a commit after its parents should be a no-op. 1422 let output = work_dir.run_jj(["rebase", "-r", "c", "--after", "b2", "--after", "b4"]); 1423 insta::assert_snapshot!(output, @r" 1424 ------- stderr ------- 1425 Skipped rebase of 4 commits that were already in place 1426 Nothing changed. 1427 [EOF] 1428 "); 1429 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1430 @ f: e 1431 ○ e: c 1432 │ ○ d: c 1433 ├─╯ 1434 ○ c: b2 b4 1435 ├─╮ 1436 │ ○ b4: b3 1437 │ ○ b3: a 1438 ○ │ b2: b1 1439 ○ │ b1: a 1440 ├─╯ 1441 ○ a 14421443 [EOF] 1444 "); 1445 1446 // Rebasing a commit after itself should be a no-op. 1447 let output = work_dir.run_jj(["rebase", "-r", "c", "--after", "c"]); 1448 insta::assert_snapshot!(output, @r" 1449 ------- stderr ------- 1450 Skipped rebase of 4 commits that were already in place 1451 Nothing changed. 1452 [EOF] 1453 "); 1454 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1455 @ f: e 1456 ○ e: c 1457 │ ○ d: c 1458 ├─╯ 1459 ○ c: b2 b4 1460 ├─╮ 1461 │ ○ b4: b3 1462 │ ○ b3: a 1463 ○ │ b2: b1 1464 ○ │ b1: a 1465 ├─╯ 1466 ○ a 14671468 [EOF] 1469 "); 1470 1471 // Rebase a commit after another commit. "c" has parents "b2" and "b4", so its 1472 // children "d" and "e" should be rebased onto "b2" and "b4" respectively. 1473 let output = work_dir.run_jj(["rebase", "-r", "c", "--after", "e"]); 1474 insta::assert_snapshot!(output, @r" 1475 ------- stderr ------- 1476 Rebased 1 commits onto destination 1477 Rebased 3 descendant commits 1478 Working copy (@) now at: xznxytkn e0e873c8 f | f 1479 Parent commit (@-) : kmkuslsw 754793f3 c | c 1480 [EOF] 1481 "); 1482 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1483 @ f: c 1484 ○ c: e 1485 ○ e: b2 b4 1486 ├─╮ 1487 │ │ ○ d: b2 b4 1488 ╭─┬─╯ 1489 │ ○ b4: b3 1490 │ ○ b3: a 1491 ○ │ b2: b1 1492 ○ │ b1: a 1493 ├─╯ 1494 ○ a 14951496 [EOF] 1497 "); 1498 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1499 1500 // Rebase a commit after a leaf commit. 1501 let output = work_dir.run_jj(["rebase", "-r", "e", "--after", "f"]); 1502 insta::assert_snapshot!(output, @r" 1503 ------- stderr ------- 1504 Rebased 1 commits onto destination 1505 Rebased 1 descendant commits 1506 Working copy (@) now at: xznxytkn 9804b742 f | f 1507 Parent commit (@-) : kmkuslsw cd86b3e4 c | c 1508 Added 0 files, modified 0 files, removed 1 files 1509 [EOF] 1510 "); 1511 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1512 ○ e: f 1513 @ f: c 1514 │ ○ d: c 1515 ├─╯ 1516 ○ c: b2 b4 1517 ├─╮ 1518 │ ○ b4: b3 1519 │ ○ b3: a 1520 ○ │ b2: b1 1521 ○ │ b1: a 1522 ├─╯ 1523 ○ a 15241525 [EOF] 1526 "); 1527 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1528 1529 // Rebase a commit after a commit in a bookmark of a merge commit. 1530 let output = work_dir.run_jj(["rebase", "-r", "f", "--after", "b1"]); 1531 insta::assert_snapshot!(output, @r" 1532 ------- stderr ------- 1533 Rebased 1 commits onto destination 1534 Rebased 4 descendant commits 1535 Working copy (@) now at: xznxytkn 80c27408 f | f 1536 Parent commit (@-) : zsuskuln 072d5ae1 b1 | b1 1537 Added 0 files, modified 0 files, removed 5 files 1538 [EOF] 1539 "); 1540 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1541 ○ e: c 1542 │ ○ d: c 1543 ├─╯ 1544 ○ c: b2 b4 1545 ├─╮ 1546 │ ○ b4: b3 1547 │ ○ b3: a 1548 ○ │ b2: f 1549 @ │ f: b1 1550 ○ │ b1: a 1551 ├─╯ 1552 ○ a 15531554 [EOF] 1555 "); 1556 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1557 1558 // Rebase a commit after the last commit in a bookmark of a merge commit. 1559 let output = work_dir.run_jj(["rebase", "-r", "f", "--after", "b2"]); 1560 insta::assert_snapshot!(output, @r" 1561 ------- stderr ------- 1562 Rebased 1 commits onto destination 1563 Rebased 3 descendant commits 1564 Working copy (@) now at: xznxytkn ebbc24b1 f | f 1565 Parent commit (@-) : royxmykx 2b8e1148 b2 | b2 1566 Added 0 files, modified 0 files, removed 4 files 1567 [EOF] 1568 "); 1569 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1570 ○ e: c 1571 │ ○ d: c 1572 ├─╯ 1573 ○ c: f b4 1574 ├─╮ 1575 │ ○ b4: b3 1576 │ ○ b3: a 1577 @ │ f: b2 1578 ○ │ b2: b1 1579 ○ │ b1: a 1580 ├─╯ 1581 ○ a 15821583 [EOF] 1584 "); 1585 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1586 1587 // Rebase a commit after a commit with multiple children. 1588 // "c" has two children "d" and "e", so the rebased commit "f" will inherit the 1589 // two children. 1590 let output = work_dir.run_jj(["rebase", "-r", "f", "--after", "c"]); 1591 insta::assert_snapshot!(output, @r" 1592 ------- stderr ------- 1593 Rebased 1 commits onto destination 1594 Rebased 2 descendant commits 1595 Working copy (@) now at: xznxytkn 8f8c91d3 f | f 1596 Parent commit (@-) : kmkuslsw cd86b3e4 c | c 1597 Added 0 files, modified 0 files, removed 1 files 1598 [EOF] 1599 "); 1600 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1601 ○ e: f 1602 │ ○ d: f 1603 ├─╯ 1604 @ f: c 1605 ○ c: b2 b4 1606 ├─╮ 1607 │ ○ b4: b3 1608 │ ○ b3: a 1609 ○ │ b2: b1 1610 ○ │ b1: a 1611 ├─╯ 1612 ○ a 16131614 [EOF] 1615 "); 1616 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1617 1618 // Rebase a commit after multiple commits. 1619 let output = work_dir.run_jj(["rebase", "-r", "f", "--after", "e", "--after", "d"]); 1620 insta::assert_snapshot!(output, @r" 1621 ------- stderr ------- 1622 Rebased 1 commits onto destination 1623 Working copy (@) now at: xznxytkn 7784e5a0 f | f 1624 Parent commit (@-) : nkmrtpmo 858693f7 e | e 1625 Parent commit (@-) : lylxulpl 7d0512e5 d | d 1626 Added 1 files, modified 0 files, removed 0 files 1627 [EOF] 1628 "); 1629 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1630 @ f: e d 1631 ├─╮ 1632 │ ○ d: c 1633 ○ │ e: c 1634 ├─╯ 1635 ○ c: b2 b4 1636 ├─╮ 1637 │ ○ b4: b3 1638 │ ○ b3: a 1639 ○ │ b2: b1 1640 ○ │ b1: a 1641 ├─╯ 1642 ○ a 16431644 [EOF] 1645 "); 1646 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1647 1648 // Rebase two unrelated commits. 1649 let output = work_dir.run_jj(["rebase", "-r", "d", "-r", "e", "--after", "a"]); 1650 insta::assert_snapshot!(output, @r" 1651 ------- stderr ------- 1652 Rebased 2 commits onto destination 1653 Rebased 6 descendant commits 1654 Working copy (@) now at: xznxytkn 0b53613e f | f 1655 Parent commit (@-) : kmkuslsw 193687bb c | c 1656 Added 1 files, modified 0 files, removed 0 files 1657 [EOF] 1658 "); 1659 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1660 @ f: c 1661 ○ c: b2 b4 1662 ├─╮ 1663 │ ○ b4: b3 1664 │ ○ b3: d e 1665 │ ├─╮ 1666 ○ │ │ b2: b1 1667 ○ │ │ b1: d e 1668 ╰─┬─╮ 1669 │ ○ e: a 1670 ○ │ d: a 1671 ├─╯ 1672 ○ a 16731674 [EOF] 1675 "); 1676 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1677 1678 // Rebase a subgraph with merge commit and two parents, which should preserve 1679 // the merge. 1680 let output = work_dir.run_jj(["rebase", "-r", "b2", "-r", "b4", "-r", "c", "--after", "f"]); 1681 insta::assert_snapshot!(output, @r" 1682 ------- stderr ------- 1683 Rebased 3 commits onto destination 1684 Rebased 3 descendant commits 1685 Working copy (@) now at: xznxytkn eaf1d6b8 f | f 1686 Parent commit (@-) : nkmrtpmo 0d7e4ce9 e | e 1687 Added 0 files, modified 0 files, removed 3 files 1688 [EOF] 1689 "); 1690 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1691 ○ c: b2 b4 1692 ├─╮ 1693 │ ○ b4: f 1694 ○ │ b2: f 1695 ├─╯ 1696 @ f: e 1697 ○ e: b1 b3 1698 ├─╮ 1699 │ │ ○ d: b1 b3 1700 ╭─┬─╯ 1701 │ ○ b3: a 1702 ○ │ b1: a 1703 ├─╯ 1704 ○ a 17051706 [EOF] 1707 "); 1708 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1709 1710 // Rebase a subgraph with four commits after one of the commits itself. 1711 let output = work_dir.run_jj(["rebase", "-r", "b1::d", "--after", "c"]); 1712 insta::assert_snapshot!(output, @r" 1713 ------- stderr ------- 1714 Rebased 4 commits onto destination 1715 Rebased 2 descendant commits 1716 Working copy (@) now at: xznxytkn 9bc7e54c f | f 1717 Parent commit (@-) : nkmrtpmo 0f80251b e | e 1718 Added 1 files, modified 0 files, removed 0 files 1719 [EOF] 1720 "); 1721 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1722 @ f: e 1723 ○ e: d 1724 ○ d: c 1725 ○ c: b2 b4 1726 ├─╮ 1727 ○ │ b2: b1 1728 ○ │ b1: a b4 1729 ├─╮ 1730 │ ○ b4: b3 1731 │ ○ b3: a 1732 ├─╯ 1733 ○ a 17341735 [EOF] 1736 "); 1737 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1738 1739 // Rebase a subgraph before the parents of one of the commits in the subgraph. 1740 // "c" had parents "b2" and "b4", but no longer has "b4" as a parent since 1741 // "b4" would be a descendant of "c" after the rebase. 1742 let output = work_dir.run_jj(["rebase", "-r", "b2::d", "--after", "root()"]); 1743 insta::assert_snapshot!(output, @r" 1744 ------- stderr ------- 1745 Rebased 3 commits onto destination 1746 Rebased 6 descendant commits 1747 Working copy (@) now at: xznxytkn 0875aabc f | f 1748 Parent commit (@-) : nkmrtpmo d429661b e | e 1749 Added 1 files, modified 0 files, removed 0 files 1750 [EOF] 1751 "); 1752 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1753 @ f: e 1754 ○ e: b1 b4 1755 ├─╮ 1756 │ ○ b4: b3 1757 │ ○ b3: a 1758 ○ │ b1: a 1759 ├─╯ 1760 ○ a: d 1761 ○ d: c 1762 ○ c: b2 1763 ○ b2 17641765 [EOF] 1766 "); 1767 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1768 1769 // Rebase a subgraph with disconnected commits. Since "b2" is an ancestor of 1770 // "e", "b2" should be a parent of "e" after the rebase. 1771 let output = work_dir.run_jj(["rebase", "-r", "e", "-r", "b2", "--after", "d"]); 1772 insta::assert_snapshot!(output, @r" 1773 ------- stderr ------- 1774 Rebased 2 commits onto destination 1775 Rebased 3 descendant commits 1776 Working copy (@) now at: xznxytkn 3238a418 f | f 1777 Parent commit (@-) : kmkuslsw 6a51bd41 c | c 1778 Added 0 files, modified 0 files, removed 2 files 1779 [EOF] 1780 "); 1781 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1782 @ f: c 1783 │ ○ e: b2 1784 │ ○ b2: d 1785 │ ○ d: c 1786 ├─╯ 1787 ○ c: b1 b4 1788 ├─╮ 1789 │ ○ b4: b3 1790 │ ○ b3: a 1791 ○ │ b1: a 1792 ├─╯ 1793 ○ a 17941795 [EOF] 1796 "); 1797 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1798 1799 // `rebase -s` of commit "c" and its descendants after itself should be a no-op. 1800 let output = work_dir.run_jj(["rebase", "-s", "c", "--after", "c"]); 1801 insta::assert_snapshot!(output, @r" 1802 ------- stderr ------- 1803 Skipped rebase of 4 commits that were already in place 1804 Nothing changed. 1805 [EOF] 1806 "); 1807 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1808 @ f: e 1809 ○ e: c 1810 │ ○ d: c 1811 ├─╯ 1812 ○ c: b2 b4 1813 ├─╮ 1814 │ ○ b4: b3 1815 │ ○ b3: a 1816 ○ │ b2: b1 1817 ○ │ b1: a 1818 ├─╯ 1819 ○ a 18201821 [EOF] 1822 "); 1823 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1824 1825 // `rebase -s` of a commit and its descendants after multiple commits. 1826 let output = work_dir.run_jj(["rebase", "-s", "c", "--after", "b1", "--after", "b3"]); 1827 insta::assert_snapshot!(output, @r" 1828 ------- stderr ------- 1829 Rebased 4 commits onto destination 1830 Rebased 2 descendant commits 1831 Working copy (@) now at: xznxytkn a4ace41c f | f 1832 Parent commit (@-) : nkmrtpmo c7744d08 e | e 1833 Added 0 files, modified 0 files, removed 2 files 1834 [EOF] 1835 "); 1836 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1837 ○ b4: d f 1838 ├─╮ 1839 │ │ ○ b2: d f 1840 ╭─┬─╯ 1841 │ @ f: e 1842 │ ○ e: c 1843 ○ │ d: c 1844 ├─╯ 1845 ○ c: b1 b3 1846 ├─╮ 1847 │ ○ b3: a 1848 ○ │ b1: a 1849 ├─╯ 1850 ○ a 18511852 [EOF] 1853 "); 1854 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1855 1856 // `rebase -b` of commit "b3" after "b1" moves its descendants which are not 1857 // already descendants of "b1" (just "b3" and "b4") in between "b1" and its 1858 // child "b2". 1859 let output = work_dir.run_jj(["rebase", "-b", "b3", "--after", "b1"]); 1860 insta::assert_snapshot!(output, @r" 1861 ------- stderr ------- 1862 Rebased 6 commits onto destination 1863 Rebased 1 descendant commits 1864 Working copy (@) now at: xznxytkn b4078b57 f | f 1865 Parent commit (@-) : nkmrtpmo 1b95558f e | e 1866 Added 0 files, modified 0 files, removed 1 files 1867 [EOF] 1868 "); 1869 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1870 ○ b2: d f 1871 ├─╮ 1872 │ @ f: e 1873 │ ○ e: c 1874 ○ │ d: c 1875 ├─╯ 1876 ○ c: b4 1877 ○ b4: b3 1878 ○ b3: b1 1879 ○ b1: a 1880 ○ a 18811882 [EOF] 1883 "); 1884 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 1885 1886 // Should error if a loop will be created. 1887 let output = work_dir.run_jj(["rebase", "-r", "e", "--after", "a", "--after", "b2"]); 1888 insta::assert_snapshot!(output, @r" 1889 ------- stderr ------- 1890 Error: Refusing to create a loop: commit 2b8e1148290f would be both an ancestor and a descendant of the rebased commits 1891 [EOF] 1892 [exit status: 1] 1893 "); 1894} 1895 1896#[test] 1897fn test_rebase_before() { 1898 let test_env = TestEnvironment::default(); 1899 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1900 let work_dir = test_env.work_dir("repo"); 1901 1902 create_commit(&work_dir, "a", &[]); 1903 create_commit(&work_dir, "b1", &["a"]); 1904 create_commit(&work_dir, "b2", &["b1"]); 1905 create_commit(&work_dir, "b3", &["a"]); 1906 create_commit(&work_dir, "b4", &["b3"]); 1907 create_commit(&work_dir, "c", &["b2", "b4"]); 1908 create_commit(&work_dir, "d", &["c"]); 1909 create_commit(&work_dir, "e", &["c"]); 1910 create_commit(&work_dir, "f", &["e"]); 1911 // Test the setup 1912 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1913 @ f: e 1914 ○ e: c 1915 │ ○ d: c 1916 ├─╯ 1917 ○ c: b2 b4 1918 ├─╮ 1919 │ ○ b4: b3 1920 │ ○ b3: a 1921 ○ │ b2: b1 1922 ○ │ b1: a 1923 ├─╯ 1924 ○ a 19251926 [EOF] 1927 "); 1928 let setup_opid = work_dir.current_operation_id(); 1929 1930 // Rebasing a commit before its children should be a no-op. 1931 let output = work_dir.run_jj(["rebase", "-r", "c", "--before", "d", "--before", "e"]); 1932 insta::assert_snapshot!(output, @r" 1933 ------- stderr ------- 1934 Skipped rebase of 4 commits that were already in place 1935 Nothing changed. 1936 [EOF] 1937 "); 1938 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1939 @ f: e 1940 ○ e: c 1941 │ ○ d: c 1942 ├─╯ 1943 ○ c: b2 b4 1944 ├─╮ 1945 │ ○ b4: b3 1946 │ ○ b3: a 1947 ○ │ b2: b1 1948 ○ │ b1: a 1949 ├─╯ 1950 ○ a 19511952 [EOF] 1953 "); 1954 1955 // Rebasing a commit before itself should be a no-op. 1956 let output = work_dir.run_jj(["rebase", "-r", "c", "--before", "c"]); 1957 insta::assert_snapshot!(output, @r" 1958 ------- stderr ------- 1959 Skipped rebase of 4 commits that were already in place 1960 Nothing changed. 1961 [EOF] 1962 "); 1963 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1964 @ f: e 1965 ○ e: c 1966 │ ○ d: c 1967 ├─╯ 1968 ○ c: b2 b4 1969 ├─╮ 1970 │ ○ b4: b3 1971 │ ○ b3: a 1972 ○ │ b2: b1 1973 ○ │ b1: a 1974 ├─╯ 1975 ○ a 19761977 [EOF] 1978 "); 1979 1980 // Rebasing a commit before the root commit should error. 1981 let output = work_dir.run_jj(["rebase", "-r", "c", "--before", "root()"]); 1982 insta::assert_snapshot!(output, @r" 1983 ------- stderr ------- 1984 Error: The root commit 000000000000 is immutable 1985 [EOF] 1986 [exit status: 1] 1987 "); 1988 1989 // Rebase a commit before another commit. "c" has parents "b2" and "b4", so its 1990 // children "d" and "e" should be rebased onto "b2" and "b4" respectively. 1991 let output = work_dir.run_jj(["rebase", "-r", "c", "--before", "a"]); 1992 insta::assert_snapshot!(output, @r" 1993 ------- stderr ------- 1994 Rebased 1 commits onto destination 1995 Rebased 8 descendant commits 1996 Working copy (@) now at: xznxytkn 24335685 f | f 1997 Parent commit (@-) : nkmrtpmo e9a28d4b e | e 1998 [EOF] 1999 "); 2000 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2001 @ f: e 2002 ○ e: b2 b4 2003 ├─╮ 2004 │ │ ○ d: b2 b4 2005 ╭─┬─╯ 2006 │ ○ b4: b3 2007 │ ○ b3: a 2008 ○ │ b2: b1 2009 ○ │ b1: a 2010 ├─╯ 2011 ○ a: c 2012 ○ c 20132014 [EOF] 2015 "); 2016 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2017 2018 // Rebase a commit before its parent. 2019 let output = work_dir.run_jj(["rebase", "-r", "f", "--before", "e"]); 2020 insta::assert_snapshot!(output, @r" 2021 ------- stderr ------- 2022 Rebased 1 commits onto destination 2023 Rebased 1 descendant commits 2024 Working copy (@) now at: xznxytkn 8e3b728a f | f 2025 Parent commit (@-) : kmkuslsw cd86b3e4 c | c 2026 Added 0 files, modified 0 files, removed 1 files 2027 [EOF] 2028 "); 2029 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2030 ○ e: f 2031 @ f: c 2032 │ ○ d: c 2033 ├─╯ 2034 ○ c: b2 b4 2035 ├─╮ 2036 │ ○ b4: b3 2037 │ ○ b3: a 2038 ○ │ b2: b1 2039 ○ │ b1: a 2040 ├─╯ 2041 ○ a 20422043 [EOF] 2044 "); 2045 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2046 2047 // Rebase a commit before a commit in a bookmark of a merge commit. 2048 let output = work_dir.run_jj(["rebase", "-r", "f", "--before", "b2"]); 2049 insta::assert_snapshot!(output, @r" 2050 ------- stderr ------- 2051 Rebased 1 commits onto destination 2052 Rebased 4 descendant commits 2053 Working copy (@) now at: xznxytkn 2b4f48f8 f | f 2054 Parent commit (@-) : zsuskuln 072d5ae1 b1 | b1 2055 Added 0 files, modified 0 files, removed 5 files 2056 [EOF] 2057 "); 2058 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2059 ○ e: c 2060 │ ○ d: c 2061 ├─╯ 2062 ○ c: b2 b4 2063 ├─╮ 2064 │ ○ b4: b3 2065 │ ○ b3: a 2066 ○ │ b2: f 2067 @ │ f: b1 2068 ○ │ b1: a 2069 ├─╯ 2070 ○ a 20712072 [EOF] 2073 "); 2074 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2075 2076 // Rebase a commit before the first commit in a bookmark of a merge commit. 2077 let output = work_dir.run_jj(["rebase", "-r", "f", "--before", "b1"]); 2078 insta::assert_snapshot!(output, @r" 2079 ------- stderr ------- 2080 Rebased 1 commits onto destination 2081 Rebased 5 descendant commits 2082 Working copy (@) now at: xznxytkn 488ebb95 f | f 2083 Parent commit (@-) : rlvkpnrz 2443ea76 a | a 2084 Added 0 files, modified 0 files, removed 6 files 2085 [EOF] 2086 "); 2087 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2088 ○ e: c 2089 │ ○ d: c 2090 ├─╯ 2091 ○ c: b2 b4 2092 ├─╮ 2093 │ ○ b4: b3 2094 │ ○ b3: a 2095 ○ │ b2: b1 2096 ○ │ b1: f 2097 @ │ f: a 2098 ├─╯ 2099 ○ a 21002101 [EOF] 2102 "); 2103 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2104 2105 // Rebase a commit before a merge commit. "c" has two parents "b2" and "b4", so 2106 // the rebased commit "f" will have the two commits "b2" and "b4" as its 2107 // parents. 2108 let output = work_dir.run_jj(["rebase", "-r", "f", "--before", "c"]); 2109 insta::assert_snapshot!(output, @r" 2110 ------- stderr ------- 2111 Rebased 1 commits onto destination 2112 Rebased 3 descendant commits 2113 Working copy (@) now at: xznxytkn aae1bc10 f | f 2114 Parent commit (@-) : royxmykx 2b8e1148 b2 | b2 2115 Parent commit (@-) : znkkpsqq a52a83a4 b4 | b4 2116 Added 0 files, modified 0 files, removed 2 files 2117 [EOF] 2118 "); 2119 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2120 ○ e: c 2121 │ ○ d: c 2122 ├─╯ 2123 ○ c: f 2124 @ f: b2 b4 2125 ├─╮ 2126 │ ○ b4: b3 2127 │ ○ b3: a 2128 ○ │ b2: b1 2129 ○ │ b1: a 2130 ├─╯ 2131 ○ a 21322133 [EOF] 2134 "); 2135 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2136 2137 // Rebase a commit before multiple commits. 2138 let output = work_dir.run_jj(["rebase", "-r", "b1", "--before", "d", "--before", "e"]); 2139 insta::assert_snapshot!(output, @r" 2140 ------- stderr ------- 2141 Rebased 1 commits onto destination 2142 Rebased 5 descendant commits 2143 Working copy (@) now at: xznxytkn 8268ec4d f | f 2144 Parent commit (@-) : nkmrtpmo fd26fbd4 e | e 2145 [EOF] 2146 "); 2147 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2148 @ f: e 2149 ○ e: b1 2150 │ ○ d: b1 2151 ├─╯ 2152 ○ b1: c 2153 ○ c: b2 b4 2154 ├─╮ 2155 │ ○ b4: b3 2156 │ ○ b3: a 2157 ○ │ b2: a 2158 ├─╯ 2159 ○ a 21602161 [EOF] 2162 "); 2163 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2164 2165 // Rebase a commit before two commits in separate bookmarks to create a merge 2166 // commit. 2167 let output = work_dir.run_jj(["rebase", "-r", "f", "--before", "b2", "--before", "b4"]); 2168 insta::assert_snapshot!(output, @r" 2169 ------- stderr ------- 2170 Rebased 1 commits onto destination 2171 Rebased 5 descendant commits 2172 Working copy (@) now at: xznxytkn 7ba8014f f | f 2173 Parent commit (@-) : zsuskuln 072d5ae1 b1 | b1 2174 Parent commit (@-) : vruxwmqv 523e6a8b b3 | b3 2175 Added 0 files, modified 0 files, removed 4 files 2176 [EOF] 2177 "); 2178 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2179 ○ e: c 2180 │ ○ d: c 2181 ├─╯ 2182 ○ c: b2 b4 2183 ├─╮ 2184 │ ○ b4: f 2185 ○ │ b2: f 2186 ├─╯ 2187 @ f: b1 b3 2188 ├─╮ 2189 │ ○ b3: a 2190 ○ │ b1: a 2191 ├─╯ 2192 ○ a 21932194 [EOF] 2195 "); 2196 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2197 2198 // Rebase two unrelated commits "b2" and "b4" before a single commit "a". This 2199 // creates a merge commit "a" with the two parents "b2" and "b4". 2200 let output = work_dir.run_jj(["rebase", "-r", "b2", "-r", "b4", "--before", "a"]); 2201 insta::assert_snapshot!(output, @r" 2202 ------- stderr ------- 2203 Rebased 2 commits onto destination 2204 Rebased 7 descendant commits 2205 Working copy (@) now at: xznxytkn fabd8dd7 f | f 2206 Parent commit (@-) : nkmrtpmo b5933877 e | e 2207 [EOF] 2208 "); 2209 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2210 @ f: e 2211 ○ e: c 2212 │ ○ d: c 2213 ├─╯ 2214 ○ c: b1 b3 2215 ├─╮ 2216 │ ○ b3: a 2217 ○ │ b1: a 2218 ├─╯ 2219 ○ a: b2 b4 2220 ├─╮ 2221 │ ○ b4 2222 ○ │ b2 2223 ├─╯ 22242225 [EOF] 2226 "); 2227 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2228 2229 // Rebase a subgraph with a merge commit and two parents. 2230 let output = work_dir.run_jj(["rebase", "-r", "b2", "-r", "b4", "-r", "c", "--before", "e"]); 2231 insta::assert_snapshot!(output, @r" 2232 ------- stderr ------- 2233 Rebased 3 commits onto destination 2234 Rebased 3 descendant commits 2235 Working copy (@) now at: xznxytkn cbe2be58 f | f 2236 Parent commit (@-) : nkmrtpmo e31053d1 e | e 2237 [EOF] 2238 "); 2239 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2240 @ f: e 2241 ○ e: c 2242 ○ c: b2 b4 2243 ├─╮ 2244 │ ○ b4: b1 b3 2245 │ ├─╮ 2246 ○ │ │ b2: b1 b3 2247 ╰─┬─╮ 2248 ○ │ │ d: b1 b3 2249 ╰─┬─╮ 2250 │ ○ b3: a 2251 ○ │ b1: a 2252 ├─╯ 2253 ○ a 22542255 [EOF] 2256 "); 2257 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2258 2259 // Rebase a subgraph with disconnected commits. Since "b1" is an ancestor of 2260 // "e", "b1" should be a parent of "e" after the rebase. 2261 let output = work_dir.run_jj(["rebase", "-r", "b1", "-r", "e", "--before", "a"]); 2262 insta::assert_snapshot!(output, @r" 2263 ------- stderr ------- 2264 Rebased 2 commits onto destination 2265 Rebased 7 descendant commits 2266 Working copy (@) now at: xznxytkn 1c48b514 f | f 2267 Parent commit (@-) : kmkuslsw c0fd979a c | c 2268 [EOF] 2269 "); 2270 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2271 @ f: c 2272 │ ○ d: c 2273 ├─╯ 2274 ○ c: b2 b4 2275 ├─╮ 2276 │ ○ b4: b3 2277 │ ○ b3: a 2278 ○ │ b2: a 2279 ├─╯ 2280 ○ a: e 2281 ○ e: b1 2282 ○ b1 22832284 [EOF] 2285 "); 2286 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2287 2288 // Rebase a subgraph before the parents of one of the commits in the subgraph. 2289 // "c" had parents "b2" and "b4", but no longer has "b4" as a parent since 2290 // "b4" would be a descendant of "c" after the rebase. 2291 let output = work_dir.run_jj(["rebase", "-r", "b2::d", "--before", "a"]); 2292 insta::assert_snapshot!(output, @r" 2293 ------- stderr ------- 2294 Rebased 3 commits onto destination 2295 Rebased 6 descendant commits 2296 Working copy (@) now at: xznxytkn f5991dc7 f | f 2297 Parent commit (@-) : nkmrtpmo 37894e3c e | e 2298 Added 1 files, modified 0 files, removed 0 files 2299 [EOF] 2300 "); 2301 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2302 @ f: e 2303 ○ e: b1 b4 2304 ├─╮ 2305 │ ○ b4: b3 2306 │ ○ b3: a 2307 ○ │ b1: a 2308 ├─╯ 2309 ○ a: d 2310 ○ d: c 2311 ○ c: b2 2312 ○ b2 23132314 [EOF] 2315 "); 2316 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2317 2318 // Rebase a subgraph before the parents of one of the commits in the subgraph. 2319 // "c" had parents "b2" and "b4", but no longer has "b4" as a parent since 2320 // "b4" would be a descendant of "c" after the rebase. 2321 let output = work_dir.run_jj(["rebase", "-r", "b2::d", "--before", "a"]); 2322 insta::assert_snapshot!(output, @r" 2323 ------- stderr ------- 2324 Rebased 3 commits onto destination 2325 Rebased 6 descendant commits 2326 Working copy (@) now at: xznxytkn 308a31e9 f | f 2327 Parent commit (@-) : nkmrtpmo 538444a5 e | e 2328 Added 1 files, modified 0 files, removed 0 files 2329 [EOF] 2330 "); 2331 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2332 @ f: e 2333 ○ e: b1 b4 2334 ├─╮ 2335 │ ○ b4: b3 2336 │ ○ b3: a 2337 ○ │ b1: a 2338 ├─╯ 2339 ○ a: d 2340 ○ d: c 2341 ○ c: b2 2342 ○ b2 23432344 [EOF] 2345 "); 2346 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2347 2348 // `rebase -s` of commit "c" and its descendants before itself should be a 2349 // no-op. 2350 let output = work_dir.run_jj(["rebase", "-s", "c", "--before", "c"]); 2351 insta::assert_snapshot!(output, @r" 2352 ------- stderr ------- 2353 Skipped rebase of 4 commits that were already in place 2354 Nothing changed. 2355 [EOF] 2356 "); 2357 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2358 @ f: e 2359 ○ e: c 2360 │ ○ d: c 2361 ├─╯ 2362 ○ c: b2 b4 2363 ├─╮ 2364 │ ○ b4: b3 2365 │ ○ b3: a 2366 ○ │ b2: b1 2367 ○ │ b1: a 2368 ├─╯ 2369 ○ a 23702371 [EOF] 2372 "); 2373 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2374 2375 // `rebase -s` of a commit and its descendants before multiple commits. 2376 let output = work_dir.run_jj(["rebase", "-s", "c", "--before", "b2", "--before", "b4"]); 2377 insta::assert_snapshot!(output, @r" 2378 ------- stderr ------- 2379 Rebased 4 commits onto destination 2380 Rebased 2 descendant commits 2381 Working copy (@) now at: xznxytkn 84704387 f | f 2382 Parent commit (@-) : nkmrtpmo cff61821 e | e 2383 Added 0 files, modified 0 files, removed 2 files 2384 [EOF] 2385 "); 2386 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2387 ○ b4: d f 2388 ├─╮ 2389 │ │ ○ b2: d f 2390 ╭─┬─╯ 2391 │ @ f: e 2392 │ ○ e: c 2393 ○ │ d: c 2394 ├─╯ 2395 ○ c: b1 b3 2396 ├─╮ 2397 │ ○ b3: a 2398 ○ │ b1: a 2399 ├─╯ 2400 ○ a 24012402 [EOF] 2403 "); 2404 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2405 2406 // `rebase -b` of commit "b3" before "b2" moves its descendants which are not 2407 // already descendants of its parent "b1" (just "b3" and "b4") in between "b1" 2408 // and its child "b2". 2409 let output = work_dir.run_jj(["rebase", "-b", "b3", "--before", "b1"]); 2410 insta::assert_snapshot!(output, @r" 2411 ------- stderr ------- 2412 Skipped rebase of 2 commits that were already in place 2413 Rebased 4 commits onto destination 2414 Rebased 2 descendant commits 2415 Working copy (@) now at: xznxytkn 16422f85 f | f 2416 Parent commit (@-) : nkmrtpmo ef9dea83 e | e 2417 Added 0 files, modified 0 files, removed 2 files 2418 [EOF] 2419 "); 2420 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2421 ○ b2: b1 2422 ○ b1: d f 2423 ├─╮ 2424 │ @ f: e 2425 │ ○ e: c 2426 ○ │ d: c 2427 ├─╯ 2428 ○ c: b4 2429 ○ b4: b3 2430 ○ b3: a 2431 ○ a 24322433 [EOF] 2434 "); 2435 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2436 2437 // Should error if a loop will be created. 2438 let output = work_dir.run_jj(["rebase", "-r", "e", "--before", "b2", "--before", "c"]); 2439 insta::assert_snapshot!(output, @r" 2440 ------- stderr ------- 2441 Error: Refusing to create a loop: commit 2b8e1148290f would be both an ancestor and a descendant of the rebased commits 2442 [EOF] 2443 [exit status: 1] 2444 "); 2445} 2446 2447#[test] 2448fn test_rebase_after_before() { 2449 let test_env = TestEnvironment::default(); 2450 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2451 let work_dir = test_env.work_dir("repo"); 2452 2453 create_commit(&work_dir, "x", &[]); 2454 create_commit(&work_dir, "y", &["x"]); 2455 create_commit(&work_dir, "z", &["y"]); 2456 create_commit(&work_dir, "a", &[]); 2457 create_commit(&work_dir, "b1", &["a"]); 2458 create_commit(&work_dir, "b2", &["a"]); 2459 create_commit(&work_dir, "c", &["b1", "b2"]); 2460 create_commit(&work_dir, "d", &["c"]); 2461 create_commit(&work_dir, "e", &["c"]); 2462 create_commit(&work_dir, "f", &["e"]); 2463 // Test the setup 2464 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2465 @ f: e 2466 ○ e: c 2467 │ ○ d: c 2468 ├─╯ 2469 ○ c: b1 b2 2470 ├─╮ 2471 │ ○ b2: a 2472 ○ │ b1: a 2473 ├─╯ 2474 ○ a 2475 │ ○ z: y 2476 │ ○ y: x 2477 │ ○ x 2478 ├─╯ 24792480 [EOF] 2481 "); 2482 let setup_opid = work_dir.current_operation_id(); 2483 2484 // Rebase a commit after another commit and before that commit's child to 2485 // insert directly between the two commits. 2486 let output = work_dir.run_jj(["rebase", "-r", "d", "--after", "e", "--before", "f"]); 2487 insta::assert_snapshot!(output, @r" 2488 ------- stderr ------- 2489 Rebased 1 commits onto destination 2490 Rebased 1 descendant commits 2491 Working copy (@) now at: nmzmmopx 56c81c6d f | f 2492 Parent commit (@-) : nkmrtpmo ff196f69 d | d 2493 Added 1 files, modified 0 files, removed 0 files 2494 [EOF] 2495 "); 2496 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2497 @ f: d 2498 ○ d: e 2499 ○ e: c 2500 ○ c: b1 b2 2501 ├─╮ 2502 │ ○ b2: a 2503 ○ │ b1: a 2504 ├─╯ 2505 ○ a 2506 │ ○ z: y 2507 │ ○ y: x 2508 │ ○ x 2509 ├─╯ 25102511 [EOF] 2512 "); 2513 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2514 2515 // Rebase a commit after another commit and before that commit's descendant to 2516 // create a new merge commit. 2517 let output = work_dir.run_jj(["rebase", "-r", "d", "--after", "a", "--before", "f"]); 2518 insta::assert_snapshot!(output, @r" 2519 ------- stderr ------- 2520 Rebased 1 commits onto destination 2521 Rebased 1 descendant commits 2522 Working copy (@) now at: nmzmmopx 398173ed f | f 2523 Parent commit (@-) : xznxytkn b3e6aadf e | e 2524 Parent commit (@-) : nkmrtpmo db529447 d | d 2525 Added 1 files, modified 0 files, removed 0 files 2526 [EOF] 2527 "); 2528 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2529 @ f: e d 2530 ├─╮ 2531 │ ○ d: a 2532 ○ │ e: c 2533 ○ │ c: b1 b2 2534 ├───╮ 2535 │ │ ○ b2: a 2536 │ ├─╯ 2537 ○ │ b1: a 2538 ├─╯ 2539 ○ a 2540 │ ○ z: y 2541 │ ○ y: x 2542 │ ○ x 2543 ├─╯ 25442545 [EOF] 2546 "); 2547 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2548 2549 // "c" has parents "b1" and "b2", so when it is rebased, its children "d" and 2550 // "e" should have "b1" and "b2" as parents as well. "c" is then inserted in 2551 // between "d" and "e", making "e" a merge commit with 3 parents "b1", "b2", 2552 // and "c". 2553 let output = work_dir.run_jj(["rebase", "-r", "c", "--after", "d", "--before", "e"]); 2554 insta::assert_snapshot!(output, @r" 2555 ------- stderr ------- 2556 Rebased 1 commits onto destination 2557 Rebased 3 descendant commits 2558 Working copy (@) now at: nmzmmopx 2be98daf f | f 2559 Parent commit (@-) : xznxytkn 911fc846 e | e 2560 Added 1 files, modified 0 files, removed 0 files 2561 [EOF] 2562 "); 2563 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2564 @ f: e 2565 ○ e: b1 b2 c 2566 ├─┬─╮ 2567 │ │ ○ c: d 2568 │ │ ○ d: b1 b2 2569 ╭─┬─╯ 2570 │ ○ b2: a 2571 ○ │ b1: a 2572 ├─╯ 2573 ○ a 2574 │ ○ z: y 2575 │ ○ y: x 2576 │ ○ x 2577 ├─╯ 25782579 [EOF] 2580 "); 2581 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2582 2583 // Rebase multiple commits and preserve their ancestry. Apart from the heads of 2584 // the target commits ("d" and "e"), "f" also has commits "b1" and "b2" as 2585 // parents since its parents "d" and "e" were in the target set and were 2586 // replaced by their closest ancestors outside the target set. 2587 let output = work_dir.run_jj([ 2588 "rebase", "-r", "c", "-r", "d", "-r", "e", "--after", "a", "--before", "f", 2589 ]); 2590 insta::assert_snapshot!(output, @r" 2591 ------- stderr ------- 2592 Rebased 3 commits onto destination 2593 Rebased 1 descendant commits 2594 Working copy (@) now at: nmzmmopx bee09b10 f | f 2595 Parent commit (@-) : znkkpsqq 9167144b b1 | b1 2596 Parent commit (@-) : kmkuslsw 87fed139 b2 | b2 2597 Parent commit (@-) : nkmrtpmo 4a8ca156 d | d 2598 Parent commit (@-) : xznxytkn 0cc1825e e | e 2599 Added 1 files, modified 0 files, removed 0 files 2600 [EOF] 2601 "); 2602 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2603 @ f: b1 b2 d e 2604 ├─┬─┬─╮ 2605 │ │ │ ○ e: c 2606 │ │ ○ │ d: c 2607 │ │ ├─╯ 2608 │ │ ○ c: a 2609 │ ○ │ b2: a 2610 │ ├─╯ 2611 ○ │ b1: a 2612 ├─╯ 2613 ○ a 2614 │ ○ z: y 2615 │ ○ y: x 2616 │ ○ x 2617 ├─╯ 26182619 [EOF] 2620 "); 2621 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2622 2623 // `rebase -s` of a commit and its descendants. 2624 let output = work_dir.run_jj(["rebase", "-s", "c", "--before", "b1", "--after", "b2"]); 2625 insta::assert_snapshot!(output, @r" 2626 ------- stderr ------- 2627 Rebased 4 commits onto destination 2628 Rebased 1 descendant commits 2629 Working copy (@) now at: nmzmmopx 951204cf f | f 2630 Parent commit (@-) : xznxytkn fe8ec4e2 e | e 2631 Added 0 files, modified 0 files, removed 1 files 2632 [EOF] 2633 "); 2634 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2635 ○ b1: a d f 2636 ├─┬─╮ 2637 │ │ @ f: e 2638 │ │ ○ e: c 2639 │ ○ │ d: c 2640 │ ├─╯ 2641 │ ○ c: b2 2642 │ ○ b2: a 2643 ├─╯ 2644 ○ a 2645 │ ○ z: y 2646 │ ○ y: x 2647 │ ○ x 2648 ├─╯ 26492650 [EOF] 2651 "); 2652 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2653 2654 // `rebase -b` of a commit "y" to a destination after "a" will rebase all 2655 // commits in "roots(a..y)" and their descendants, corresponding to "x", "y" 2656 // and "z". They will be inserted in a new branch after "a" and before "c". 2657 let output = work_dir.run_jj(["rebase", "-b", "y", "--after", "a", "--before", "c"]); 2658 insta::assert_snapshot!(output, @r" 2659 ------- stderr ------- 2660 Rebased 3 commits onto destination 2661 Rebased 4 descendant commits 2662 Working copy (@) now at: nmzmmopx 4496f88e f | f 2663 Parent commit (@-) : xznxytkn a85404a6 e | e 2664 Added 3 files, modified 0 files, removed 0 files 2665 [EOF] 2666 "); 2667 insta::assert_snapshot!(get_log_output(&work_dir), @r" 2668 @ f: e 2669 ○ e: c 2670 │ ○ d: c 2671 ├─╯ 2672 ○ c: b1 b2 z 2673 ├─┬─╮ 2674 │ │ ○ z: y 2675 │ │ ○ y: x 2676 │ │ ○ x: a 2677 │ ○ │ b2: a 2678 │ ├─╯ 2679 ○ │ b1: a 2680 ├─╯ 2681 ○ a 26822683 [EOF] 2684 "); 2685 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2686 2687 // Should error if a loop will be created. 2688 let output = work_dir.run_jj(["rebase", "-r", "e", "--after", "c", "--before", "a"]); 2689 insta::assert_snapshot!(output, @r" 2690 ------- stderr ------- 2691 Error: Refusing to create a loop: commit 31b84afe1c8f would be both an ancestor and a descendant of the rebased commits 2692 [EOF] 2693 [exit status: 1] 2694 "); 2695} 2696 2697#[test] 2698fn test_rebase_skip_emptied() { 2699 let test_env = TestEnvironment::default(); 2700 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2701 let work_dir = test_env.work_dir("repo"); 2702 2703 create_commit(&work_dir, "a", &[]); 2704 create_commit(&work_dir, "b", &["a"]); 2705 work_dir 2706 .run_jj(["new", "a", "-m", "will become empty"]) 2707 .success(); 2708 work_dir.run_jj(["restore", "--from=b"]).success(); 2709 work_dir.run_jj(["new", "-m", "already empty"]).success(); 2710 work_dir 2711 .run_jj(["new", "-m", "also already empty"]) 2712 .success(); 2713 let setup_opid = work_dir.current_operation_id(); 2714 2715 // Test the setup 2716 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2717 @ also already empty 2718 ○ already empty 2719 ○ will become empty 2720 │ ○ b 2721 ├─╯ 2722 ○ a 27232724 [EOF] 2725 "); 2726 2727 let output = work_dir.run_jj(["rebase", "-d=b", "--skip-emptied"]); 2728 insta::assert_snapshot!(output, @r" 2729 ------- stderr ------- 2730 Rebased 2 commits onto destination 2731 Abandoned 1 newly emptied commits 2732 Working copy (@) now at: yostqsxw bc4222f2 (empty) also already empty 2733 Parent commit (@-) : vruxwmqv 6b41ecb2 (empty) already empty 2734 [EOF] 2735 "); 2736 2737 // The parent commit became empty and was dropped, but the already empty commits 2738 // were kept 2739 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2740 @ also already empty 2741 ○ already empty 2742 ○ b 2743 ○ a 27442745 [EOF] 2746 "); 2747 2748 work_dir.run_jj(["op", "restore", &setup_opid]).success(); 2749 // Test the setup 2750 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2751 @ also already empty 2752 ○ already empty 2753 ○ will become empty 2754 │ ○ b 2755 ├─╯ 2756 ○ a 27572758 [EOF] 2759 "); 2760 2761 let output = work_dir.run_jj([ 2762 "rebase", 2763 "-r=description('will become empty')", 2764 "-d=b", 2765 "--skip-emptied", 2766 ]); 2767 insta::assert_snapshot!(output, @r" 2768 ------- stderr ------- 2769 Rebased 2 descendant commits 2770 Abandoned 1 newly emptied commits 2771 Working copy (@) now at: yostqsxw 74149b9b (empty) also already empty 2772 Parent commit (@-) : vruxwmqv 3bdb2801 (empty) already empty 2773 Added 0 files, modified 0 files, removed 1 files 2774 [EOF] 2775 "); 2776 2777 // Rebasing a single commit which becomes empty abandons that commit, whilst its 2778 // already empty descendants were kept 2779 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2780 @ also already empty 2781 ○ already empty 2782 │ ○ b 2783 ├─╯ 2784 ○ a 27852786 [EOF] 2787 "); 2788} 2789 2790#[test] 2791fn test_rebase_skip_emptied_descendants() { 2792 let test_env = TestEnvironment::default(); 2793 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2794 let work_dir = test_env.work_dir("repo"); 2795 2796 create_commit(&work_dir, "a", &[]); 2797 create_commit(&work_dir, "b", &["a"]); 2798 work_dir 2799 .run_jj(["new", "a", "-m", "c (will become empty)"]) 2800 .success(); 2801 work_dir.run_jj(["restore", "--from=b"]).success(); 2802 work_dir 2803 .run_jj(["bookmark", "create", "-r@", "c"]) 2804 .success(); 2805 work_dir.run_jj(["new", "-m", "already empty"]).success(); 2806 work_dir 2807 .run_jj(["new", "-m", "also already empty"]) 2808 .success(); 2809 2810 // Test the setup 2811 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2812 @ also already empty 2813 ○ already empty 2814 ○ c (will become empty) 2815 │ ○ b 2816 ├─╯ 2817 ○ a 28182819 [EOF] 2820 "); 2821 2822 let output = work_dir.run_jj(["rebase", "-r", "b", "--before", "c", "--skip-emptied"]); 2823 insta::assert_snapshot!(output, @r" 2824 ------- stderr ------- 2825 Skipped rebase of 1 commits that were already in place 2826 Rebased 3 descendant commits 2827 Working copy (@) now at: znkkpsqq 353bac5c (empty) also already empty 2828 Parent commit (@-) : yostqsxw 0a3f76fd (empty) already empty 2829 [EOF] 2830 "); 2831 2832 // Commits not in the rebase target set should not be abandoned even if they 2833 // were emptied. 2834 insta::assert_snapshot!(work_dir.run_jj(["log", "-T", "description"]), @r" 2835 @ also already empty 2836 ○ already empty 2837 ○ c (will become empty) 2838 ○ b 2839 ○ a 28402841 [EOF] 2842 "); 2843} 2844 2845#[test] 2846fn test_rebase_skip_if_on_destination() { 2847 let test_env = TestEnvironment::default(); 2848 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2849 let work_dir = test_env.work_dir("repo"); 2850 2851 create_commit(&work_dir, "a", &[]); 2852 create_commit(&work_dir, "b1", &["a"]); 2853 create_commit(&work_dir, "b2", &["a"]); 2854 create_commit(&work_dir, "c", &["b1", "b2"]); 2855 create_commit(&work_dir, "d", &["c"]); 2856 create_commit(&work_dir, "e", &["c"]); 2857 create_commit(&work_dir, "f", &["e"]); 2858 // Test the setup 2859 insta::assert_snapshot!(get_long_log_output(&work_dir), @r" 2860 @ f lylxulpl 88f778c5: e 2861 ○ e kmkuslsw 48dd9e3f: c 2862 │ ○ d znkkpsqq 92438fc9: c 2863 ├─╯ 2864 ○ c vruxwmqv c41e416e: b1 b2 2865 ├─╮ 2866 │ ○ b2 royxmykx 903ab0d6: a 2867 ○ │ b1 zsuskuln 072d5ae1: a 2868 ├─╯ 2869 ○ a rlvkpnrz 2443ea76 2870 ◆ zzzzzzzz 00000000 2871 [EOF] 2872 "); 2873 2874 // Skip rebase with -b 2875 let output = work_dir.run_jj(["rebase", "-b", "d", "-d", "a"]); 2876 insta::assert_snapshot!(output, @r" 2877 ------- stderr ------- 2878 Skipped rebase of 6 commits that were already in place 2879 Nothing changed. 2880 [EOF] 2881 "); 2882 insta::assert_snapshot!(get_long_log_output(&work_dir), @r" 2883 @ f lylxulpl 88f778c5: e 2884 ○ e kmkuslsw 48dd9e3f: c 2885 │ ○ d znkkpsqq 92438fc9: c 2886 ├─╯ 2887 ○ c vruxwmqv c41e416e: b1 b2 2888 ├─╮ 2889 │ ○ b2 royxmykx 903ab0d6: a 2890 ○ │ b1 zsuskuln 072d5ae1: a 2891 ├─╯ 2892 ○ a rlvkpnrz 2443ea76 2893 ◆ zzzzzzzz 00000000 2894 [EOF] 2895 "); 2896 2897 // Skip rebase with -s 2898 let output = work_dir.run_jj(["rebase", "-s", "c", "-d", "b1", "-d", "b2"]); 2899 insta::assert_snapshot!(output, @r" 2900 ------- stderr ------- 2901 Skipped rebase of 4 commits that were already in place 2902 Nothing changed. 2903 [EOF] 2904 "); 2905 insta::assert_snapshot!(get_long_log_output(&work_dir), @r" 2906 @ f lylxulpl 88f778c5: e 2907 ○ e kmkuslsw 48dd9e3f: c 2908 │ ○ d znkkpsqq 92438fc9: c 2909 ├─╯ 2910 ○ c vruxwmqv c41e416e: b1 b2 2911 ├─╮ 2912 │ ○ b2 royxmykx 903ab0d6: a 2913 ○ │ b1 zsuskuln 072d5ae1: a 2914 ├─╯ 2915 ○ a rlvkpnrz 2443ea76 2916 ◆ zzzzzzzz 00000000 2917 [EOF] 2918 "); 2919 2920 // Skip rebase with -r since commit has no children 2921 let output = work_dir.run_jj(["rebase", "-r", "d", "-d", "c"]); 2922 insta::assert_snapshot!(output, @r" 2923 ------- stderr ------- 2924 Skipped rebase of 1 commits that were already in place 2925 Nothing changed. 2926 [EOF] 2927 "); 2928 insta::assert_snapshot!(get_long_log_output(&work_dir), @r" 2929 @ f lylxulpl 88f778c5: e 2930 ○ e kmkuslsw 48dd9e3f: c 2931 │ ○ d znkkpsqq 92438fc9: c 2932 ├─╯ 2933 ○ c vruxwmqv c41e416e: b1 b2 2934 ├─╮ 2935 │ ○ b2 royxmykx 903ab0d6: a 2936 ○ │ b1 zsuskuln 072d5ae1: a 2937 ├─╯ 2938 ○ a rlvkpnrz 2443ea76 2939 ◆ zzzzzzzz 00000000 2940 [EOF] 2941 "); 2942 2943 // Skip rebase of commit, but rebases children onto destination with -r 2944 let output = work_dir.run_jj(["rebase", "-r", "e", "-d", "c"]); 2945 insta::assert_snapshot!(output, @r" 2946 ------- stderr ------- 2947 Skipped rebase of 1 commits that were already in place 2948 Rebased 1 descendant commits 2949 Working copy (@) now at: lylxulpl 77cb229f f | f 2950 Parent commit (@-) : vruxwmqv c41e416e c | c 2951 Added 0 files, modified 0 files, removed 1 files 2952 [EOF] 2953 "); 2954 insta::assert_snapshot!(get_long_log_output(&work_dir), @r" 2955 @ f lylxulpl 77cb229f: c 2956 │ ○ e kmkuslsw 48dd9e3f: c 2957 ├─╯ 2958 │ ○ d znkkpsqq 92438fc9: c 2959 ├─╯ 2960 ○ c vruxwmqv c41e416e: b1 b2 2961 ├─╮ 2962 │ ○ b2 royxmykx 903ab0d6: a 2963 ○ │ b1 zsuskuln 072d5ae1: a 2964 ├─╯ 2965 ○ a rlvkpnrz 2443ea76 2966 ◆ zzzzzzzz 00000000 2967 [EOF] 2968 "); 2969} 2970 2971#[must_use] 2972fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { 2973 let template = "bookmarks ++ surround(': ', '', parents.map(|c| c.bookmarks()))"; 2974 work_dir.run_jj(["log", "-T", template]) 2975} 2976 2977#[must_use] 2978fn get_long_log_output(work_dir: &TestWorkDir) -> CommandOutput { 2979 let template = "bookmarks ++ ' ' ++ change_id.shortest(8) ++ ' ' ++ commit_id.shortest(8) \ 2980 ++ surround(': ', '', parents.map(|c| c.bookmarks()))"; 2981 work_dir.run_jj(["log", "-T", template]) 2982}