just playing with tangled
at diffedit3 2400 lines 83 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 std::path::Path; 16 17use crate::common::TestEnvironment; 18 19fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) { 20 if parents.is_empty() { 21 test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]); 22 } else { 23 let mut args = vec!["new", "-m", name]; 24 args.extend(parents); 25 test_env.jj_cmd_ok(repo_path, &args); 26 } 27 std::fs::write(repo_path.join(name), format!("{name}\n")).unwrap(); 28 test_env.jj_cmd_ok(repo_path, &["branch", "create", name]); 29} 30 31#[test] 32fn test_rebase_invalid() { 33 let test_env = TestEnvironment::default(); 34 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 35 let repo_path = test_env.env_root().join("repo"); 36 37 create_commit(&test_env, &repo_path, "a", &[]); 38 create_commit(&test_env, &repo_path, "b", &["a"]); 39 40 // Missing destination 41 let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase"]); 42 insta::assert_snapshot!(stderr, @r###" 43 error: the following required arguments were not provided: 44 <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 45 46 Usage: jj rebase <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 47 48 For more information, try '--help'. 49 "###); 50 51 // Both -r and -s 52 let stderr = 53 test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-r", "a", "-s", "a", "-d", "b"]); 54 insta::assert_snapshot!(stderr, @r###" 55 error: the argument '--revisions <REVISIONS>' cannot be used with '--source <SOURCE>' 56 57 Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 58 59 For more information, try '--help'. 60 "###); 61 62 // Both -b and -s 63 let stderr = 64 test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-b", "a", "-s", "a", "-d", "b"]); 65 insta::assert_snapshot!(stderr, @r###" 66 error: the argument '--branch <BRANCH>' cannot be used with '--source <SOURCE>' 67 68 Usage: jj rebase --branch <BRANCH> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 69 70 For more information, try '--help'. 71 "###); 72 73 // Both -r and --skip-empty 74 let stderr = test_env.jj_cmd_cli_error( 75 &repo_path, 76 &["rebase", "-r", "a", "-d", "b", "--skip-empty"], 77 ); 78 insta::assert_snapshot!(stderr, @r###" 79 error: the argument '--revisions <REVISIONS>' cannot be used with '--skip-empty' 80 81 Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 82 83 For more information, try '--help'. 84 "###); 85 86 // Both -d and --after 87 let stderr = test_env.jj_cmd_cli_error( 88 &repo_path, 89 &["rebase", "-r", "a", "-d", "b", "--after", "b"], 90 ); 91 insta::assert_snapshot!(stderr, @r###" 92 error: the argument '--destination <DESTINATION>' cannot be used with '--insert-after <INSERT_AFTER>' 93 94 Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 95 96 For more information, try '--help'. 97 "###); 98 99 // -s with --after 100 let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-s", "a", "--after", "b"]); 101 insta::assert_snapshot!(stderr, @r###" 102 error: the argument '--source <SOURCE>' cannot be used with '--insert-after <INSERT_AFTER>' 103 104 Usage: jj rebase --source <SOURCE> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 105 106 For more information, try '--help'. 107 "###); 108 109 // -b with --after 110 let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-b", "a", "--after", "b"]); 111 insta::assert_snapshot!(stderr, @r###" 112 error: the argument '--branch <BRANCH>' cannot be used with '--insert-after <INSERT_AFTER>' 113 114 Usage: jj rebase --branch <BRANCH> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 115 116 For more information, try '--help'. 117 "###); 118 119 // Both -d and --before 120 let stderr = test_env.jj_cmd_cli_error( 121 &repo_path, 122 &["rebase", "-r", "a", "-d", "b", "--before", "b"], 123 ); 124 insta::assert_snapshot!(stderr, @r###" 125 error: the argument '--destination <DESTINATION>' cannot be used with '--insert-before <INSERT_BEFORE>' 126 127 Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 128 129 For more information, try '--help'. 130 "###); 131 132 // -s with --before 133 let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-s", "a", "--before", "b"]); 134 insta::assert_snapshot!(stderr, @r###" 135 error: the argument '--source <SOURCE>' cannot be used with '--insert-before <INSERT_BEFORE>' 136 137 Usage: jj rebase --source <SOURCE> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 138 139 For more information, try '--help'. 140 "###); 141 142 // -b with --before 143 let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-b", "a", "--before", "b"]); 144 insta::assert_snapshot!(stderr, @r###" 145 error: the argument '--branch <BRANCH>' cannot be used with '--insert-before <INSERT_BEFORE>' 146 147 Usage: jj rebase --branch <BRANCH> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> 148 149 For more information, try '--help'. 150 "###); 151 152 // Rebase onto self with -r 153 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "a"]); 154 insta::assert_snapshot!(stderr, @r###" 155 Error: Cannot rebase 2443ea76b0b1 onto itself 156 "###); 157 158 // Rebase root with -r 159 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "root()", "-d", "a"]); 160 insta::assert_snapshot!(stderr, @r###" 161 Error: The root commit 000000000000 is immutable 162 "###); 163 164 // Rebase onto descendant with -s 165 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-s", "a", "-d", "b"]); 166 insta::assert_snapshot!(stderr, @r###" 167 Error: Cannot rebase 2443ea76b0b1 onto descendant 1394f625cbbd 168 "###); 169} 170 171#[test] 172fn test_rebase_branch() { 173 let test_env = TestEnvironment::default(); 174 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 175 let repo_path = test_env.env_root().join("repo"); 176 177 create_commit(&test_env, &repo_path, "a", &[]); 178 create_commit(&test_env, &repo_path, "b", &["a"]); 179 create_commit(&test_env, &repo_path, "c", &["b"]); 180 create_commit(&test_env, &repo_path, "d", &["b"]); 181 create_commit(&test_env, &repo_path, "e", &["a"]); 182 // Test the setup 183 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 184 @ e 185 │ ◉ d 186 │ │ ◉ c 187 │ ├─╯ 188 │ ◉ b 189 ├─╯ 190 ◉ a 191 192 "###); 193 194 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "c", "-d", "e"]); 195 insta::assert_snapshot!(stdout, @""); 196 insta::assert_snapshot!(stderr, @r###" 197 Rebased 3 commits 198 "###); 199 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 200 ◉ d 201 │ ◉ c 202 ├─╯ 203 ◉ b 204 @ e 205 ◉ a 206 207 "###); 208 209 // Test rebasing multiple branches at once 210 test_env.jj_cmd_ok(&repo_path, &["undo"]); 211 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=e", "-b=d", "-d=b"]); 212 insta::assert_snapshot!(stdout, @""); 213 insta::assert_snapshot!(stderr, @r###" 214 Skipped rebase of 1 commits that were already in place 215 Rebased 1 commits 216 Working copy now at: znkkpsqq 9ca2a154 e | e 217 Parent commit : zsuskuln 1394f625 b | b 218 Added 1 files, modified 0 files, removed 0 files 219 "###); 220 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 221 @ e 222 │ ◉ d 223 ├─╯ 224 │ ◉ c 225 ├─╯ 226 ◉ b 227 ◉ a 228 229 "###); 230 231 // Same test but with more than one revision per argument 232 test_env.jj_cmd_ok(&repo_path, &["undo"]); 233 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b=e|d", "-d=b"]); 234 insta::assert_snapshot!(stderr, @r###" 235 Error: Revset "e|d" resolved to more than one revision 236 Hint: The revset "e|d" resolved to these revisions: 237 znkkpsqq e52756c8 e | e 238 vruxwmqv 514fa6b2 d | d 239 Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:e|d'). 240 "###); 241 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=all:e|d", "-d=b"]); 242 insta::assert_snapshot!(stdout, @""); 243 insta::assert_snapshot!(stderr, @r###" 244 Skipped rebase of 1 commits that were already in place 245 Rebased 1 commits 246 Working copy now at: znkkpsqq 817e3fb0 e | e 247 Parent commit : zsuskuln 1394f625 b | b 248 Added 1 files, modified 0 files, removed 0 files 249 "###); 250 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 251 @ e 252 │ ◉ d 253 ├─╯ 254 │ ◉ c 255 ├─╯ 256 ◉ b 257 ◉ a 258 259 "###); 260} 261 262#[test] 263fn test_rebase_branch_with_merge() { 264 let test_env = TestEnvironment::default(); 265 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 266 let repo_path = test_env.env_root().join("repo"); 267 268 create_commit(&test_env, &repo_path, "a", &[]); 269 create_commit(&test_env, &repo_path, "b", &["a"]); 270 create_commit(&test_env, &repo_path, "c", &[]); 271 create_commit(&test_env, &repo_path, "d", &["c"]); 272 create_commit(&test_env, &repo_path, "e", &["a", "d"]); 273 // Test the setup 274 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 275 @ e 276 ├─╮ 277 │ ◉ d 278 │ ◉ c 279 │ │ ◉ b 280 ├───╯ 281 ◉ │ a 282 ├─╯ 283 284 "###); 285 286 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "d", "-d", "b"]); 287 insta::assert_snapshot!(stdout, @""); 288 insta::assert_snapshot!(stderr, @r###" 289 Rebased 3 commits 290 Working copy now at: znkkpsqq 5f8a3db2 e | e 291 Parent commit : rlvkpnrz 2443ea76 a | a 292 Parent commit : vruxwmqv 1677f795 d | d 293 Added 1 files, modified 0 files, removed 0 files 294 "###); 295 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 296 @ e 297 ├─╮ 298 │ ◉ d 299 │ ◉ c 300 │ ◉ b 301 ├─╯ 302 ◉ a 303 304 "###); 305 306 test_env.jj_cmd_ok(&repo_path, &["undo"]); 307 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-d", "b"]); 308 insta::assert_snapshot!(stdout, @""); 309 insta::assert_snapshot!(stderr, @r###" 310 Rebased 3 commits 311 Working copy now at: znkkpsqq a331ac11 e | e 312 Parent commit : rlvkpnrz 2443ea76 a | a 313 Parent commit : vruxwmqv 3d0f3644 d | d 314 Added 1 files, modified 0 files, removed 0 files 315 "###); 316 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 317 @ e 318 ├─╮ 319 │ ◉ d 320 │ ◉ c 321 │ ◉ b 322 ├─╯ 323 ◉ a 324 325 "###); 326} 327 328#[test] 329fn test_rebase_single_revision() { 330 let test_env = TestEnvironment::default(); 331 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 332 let repo_path = test_env.env_root().join("repo"); 333 334 create_commit(&test_env, &repo_path, "a", &[]); 335 create_commit(&test_env, &repo_path, "b", &["a"]); 336 create_commit(&test_env, &repo_path, "c", &["a"]); 337 create_commit(&test_env, &repo_path, "d", &["b", "c"]); 338 create_commit(&test_env, &repo_path, "e", &["d"]); 339 // Test the setup 340 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 341 @ e 342 ◉ d 343 ├─╮ 344 │ ◉ c 345 ◉ │ b 346 ├─╯ 347 ◉ a 348 349 "###); 350 351 // Descendants of the rebased commit "c" should be rebased onto parents. First 352 // we test with a non-merge commit. 353 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "b"]); 354 insta::assert_snapshot!(stdout, @""); 355 insta::assert_snapshot!(stderr, @r###" 356 Rebased 1 commits onto destination 357 Rebased 2 descendant commits 358 Working copy now at: znkkpsqq 2668ffbe e | e 359 Parent commit : vruxwmqv 7b370c85 d | d 360 Added 0 files, modified 0 files, removed 1 files 361 "###); 362 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 363 @ e 364 ◉ d 365 ├─╮ 366 │ │ ◉ c 367 ├───╯ 368 ◉ │ b 369 ├─╯ 370 ◉ a 371 372 "###); 373 test_env.jj_cmd_ok(&repo_path, &["undo"]); 374 375 // Now, let's try moving the merge commit. After, both parents of "d" ("b" and 376 // "c") should become parents of "e". 377 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "d", "-d", "a"]); 378 insta::assert_snapshot!(stdout, @""); 379 insta::assert_snapshot!(stderr, @r###" 380 Rebased 1 commits onto destination 381 Rebased 1 descendant commits 382 Working copy now at: znkkpsqq ed210c15 e | e 383 Parent commit : zsuskuln 1394f625 b | b 384 Parent commit : royxmykx c0cb3a0b c | c 385 Added 0 files, modified 0 files, removed 1 files 386 "###); 387 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 388 @ e 389 ├─╮ 390 │ ◉ c 391 ◉ │ b 392 ├─╯ 393 │ ◉ d 394 ├─╯ 395 ◉ a 396 397 "###); 398} 399 400#[test] 401fn test_rebase_single_revision_merge_parent() { 402 let test_env = TestEnvironment::default(); 403 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 404 let repo_path = test_env.env_root().join("repo"); 405 406 create_commit(&test_env, &repo_path, "a", &[]); 407 create_commit(&test_env, &repo_path, "b", &[]); 408 create_commit(&test_env, &repo_path, "c", &["b"]); 409 create_commit(&test_env, &repo_path, "d", &["a", "c"]); 410 // Test the setup 411 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 412 @ d 413 ├─╮ 414 │ ◉ c 415 │ ◉ b 416 ◉ │ a 417 ├─╯ 418 419 "###); 420 421 // Descendants of the rebased commit should be rebased onto parents, and if 422 // the descendant is a merge commit, it shouldn't forget its other parents. 423 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "a"]); 424 insta::assert_snapshot!(stdout, @""); 425 insta::assert_snapshot!(stderr, @r###" 426 Rebased 1 commits onto destination 427 Rebased 1 descendant commits 428 Working copy now at: vruxwmqv a37531e8 d | d 429 Parent commit : rlvkpnrz 2443ea76 a | a 430 Parent commit : zsuskuln d370aee1 b | b 431 Added 0 files, modified 0 files, removed 1 files 432 "###); 433 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 434 @ d 435 ├─╮ 436 │ ◉ b 437 │ │ ◉ c 438 ├───╯ 439 ◉ │ a 440 ├─╯ 441 442 "###); 443} 444 445#[test] 446fn test_rebase_multiple_revisions() { 447 let test_env = TestEnvironment::default(); 448 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 449 let repo_path = test_env.env_root().join("repo"); 450 451 create_commit(&test_env, &repo_path, "a", &[]); 452 create_commit(&test_env, &repo_path, "b", &["a"]); 453 create_commit(&test_env, &repo_path, "c", &["b"]); 454 create_commit(&test_env, &repo_path, "d", &["a"]); 455 create_commit(&test_env, &repo_path, "e", &["d"]); 456 create_commit(&test_env, &repo_path, "f", &["c", "e"]); 457 create_commit(&test_env, &repo_path, "g", &["f"]); 458 create_commit(&test_env, &repo_path, "h", &["g"]); 459 create_commit(&test_env, &repo_path, "i", &["f"]); 460 // Test the setup 461 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 462 @ i 463 │ ◉ h 464 │ ◉ g 465 ├─╯ 466 ◉ f 467 ├─╮ 468 │ ◉ e 469 │ ◉ d 470 ◉ │ c 471 ◉ │ b 472 ├─╯ 473 ◉ a 474 475 "###); 476 477 // Test with two non-related non-merge commits. 478 let (stdout, stderr) = 479 test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-r", "e", "-d", "a"]); 480 insta::assert_snapshot!(stdout, @""); 481 insta::assert_snapshot!(stderr, @r###" 482 Rebased 2 commits onto destination 483 Rebased 4 descendant commits 484 Working copy now at: xznxytkn 016685dc i | i 485 Parent commit : kmkuslsw e04d3932 f | f 486 Added 0 files, modified 0 files, removed 2 files 487 "###); 488 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 489 @ i 490 │ ◉ h 491 │ ◉ g 492 ├─╯ 493 ◉ f 494 ├─╮ 495 │ ◉ d 496 ◉ │ b 497 ├─╯ 498 │ ◉ e 499 ├─╯ 500 │ ◉ c 501 ├─╯ 502 ◉ a 503 504 "###); 505 test_env.jj_cmd_ok(&repo_path, &["undo"]); 506 507 // Test with two related non-merge commits. Since "b" is a parent of "c", when 508 // rebasing commits "b" and "c", their ancestry relationship should be 509 // preserved. 510 let (stdout, stderr) = 511 test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-r", "c", "-d", "e"]); 512 insta::assert_snapshot!(stdout, @""); 513 insta::assert_snapshot!(stderr, @r###" 514 Rebased 2 commits onto destination 515 Rebased 4 descendant commits 516 Working copy now at: xznxytkn 94538385 i | i 517 Parent commit : kmkuslsw dae8d293 f | f 518 Added 0 files, modified 0 files, removed 2 files 519 "###); 520 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 521 @ i 522 │ ◉ h 523 │ ◉ g 524 ├─╯ 525 ◉ f 526 ├─╮ 527 │ │ ◉ c 528 │ │ ◉ b 529 │ ├─╯ 530 │ ◉ e 531 │ ◉ d 532 ├─╯ 533 ◉ a 534 535 "###); 536 test_env.jj_cmd_ok(&repo_path, &["undo"]); 537 538 // Test with a subgraph containing a merge commit. Since the merge commit "f" 539 // was extracted, its descendants which are not part of the subgraph will 540 // inherit its descendants which are not in the subtree ("c" and "d"). 541 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "e::g", "-d", "a"]); 542 insta::assert_snapshot!(stdout, @""); 543 insta::assert_snapshot!(stderr, @r###" 544 Rebased 3 commits onto destination 545 Rebased 2 descendant commits 546 Working copy now at: xznxytkn 1868ded4 i | i 547 Parent commit : royxmykx 7e4fbf4f c | c 548 Parent commit : vruxwmqv 4cc44fbf d | d 549 Added 0 files, modified 0 files, removed 2 files 550 "###); 551 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 552 @ i 553 ├─╮ 554 │ │ ◉ h 555 ╭─┬─╯ 556 │ ◉ d 557 ◉ │ c 558 ◉ │ b 559 ├─╯ 560 │ ◉ g 561 │ ◉ f 562 │ ◉ e 563 ├─╯ 564 ◉ a 565 566 "###); 567 test_env.jj_cmd_ok(&repo_path, &["undo"]); 568 569 // Test with commits in a disconnected subgraph. The subgraph has the 570 // relationship d->e->f->g->h, but only "d", "f" and "h" are in the set of 571 // rebased commits. "d" should be a new parent of "f", and "f" should be a 572 // new parent of "g". 573 let (stdout, stderr) = test_env.jj_cmd_ok( 574 &repo_path, 575 &["rebase", "-r", "d", "-r", "f", "-r", "h", "-d", "b"], 576 ); 577 insta::assert_snapshot!(stdout, @""); 578 insta::assert_snapshot!(stderr, @r###" 579 Rebased 3 commits onto destination 580 Rebased 3 descendant commits 581 Working copy now at: xznxytkn 9cfd1635 i | i 582 Parent commit : royxmykx 7e4fbf4f c | c 583 Parent commit : znkkpsqq ecf9a1d5 e | e 584 Added 0 files, modified 0 files, removed 2 files 585 "###); 586 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 587 @ i 588 ├─╮ 589 │ │ ◉ g 590 ╭─┬─╯ 591 │ ◉ e 592 ◉ │ c 593 │ │ ◉ h 594 │ │ ◉ f 595 │ │ ◉ d 596 ├───╯ 597 ◉ │ b 598 ├─╯ 599 ◉ a 600 601 "###); 602 test_env.jj_cmd_ok(&repo_path, &["undo"]); 603 604 // Test rebasing a subgraph onto its descendants. 605 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "d::e", "-d", "i"]); 606 insta::assert_snapshot!(stdout, @""); 607 insta::assert_snapshot!(stderr, @r###" 608 Rebased 2 commits onto destination 609 Rebased 4 descendant commits 610 Working copy now at: xznxytkn 5d911e5c i | i 611 Parent commit : kmkuslsw d1bfda8c f | f 612 Added 0 files, modified 0 files, removed 2 files 613 "###); 614 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 615 ◉ h 616 ◉ g 617 │ ◉ e 618 │ ◉ d 619 │ @ i 620 ├─╯ 621 ◉ f 622 ├─╮ 623 ◉ │ c 624 ◉ │ b 625 ├─╯ 626 ◉ a 627 628 "###); 629} 630 631#[test] 632fn test_rebase_revision_onto_descendant() { 633 let test_env = TestEnvironment::default(); 634 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 635 let repo_path = test_env.env_root().join("repo"); 636 637 create_commit(&test_env, &repo_path, "base", &[]); 638 create_commit(&test_env, &repo_path, "a", &["base"]); 639 create_commit(&test_env, &repo_path, "b", &["base"]); 640 create_commit(&test_env, &repo_path, "merge", &["b", "a"]); 641 // Test the setup 642 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 643 @ merge 644 ├─╮ 645 │ ◉ a 646 ◉ │ b 647 ├─╯ 648 ◉ base 649 650 "###); 651 let setup_opid = test_env.current_operation_id(&repo_path); 652 653 // Simpler example 654 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "a"]); 655 insta::assert_snapshot!(stdout, @""); 656 insta::assert_snapshot!(stderr, @r###" 657 Rebased 1 commits onto destination 658 Rebased 3 descendant commits 659 Working copy now at: vruxwmqv bff4a4eb merge | merge 660 Parent commit : royxmykx c84e900d b | b 661 Parent commit : zsuskuln d57db87b a | a 662 Added 0 files, modified 0 files, removed 1 files 663 "###); 664 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 665 @ merge 666 ├─╮ 667 ◉ │ b 668 │ │ ◉ base 669 │ ├─╯ 670 │ ◉ a 671 ├─╯ 672 673 "###); 674 675 // Now, let's rebase onto the descendant merge 676 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 677 insta::assert_snapshot!(stdout, @""); 678 insta::assert_snapshot!(stderr, @r###" 679 Working copy now at: vruxwmqv b05964d1 merge | merge 680 Parent commit : royxmykx cea87a87 b | b 681 Parent commit : zsuskuln 2c5b7858 a | a 682 Added 1 files, modified 0 files, removed 0 files 683 "###); 684 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "merge"]); 685 insta::assert_snapshot!(stdout, @""); 686 insta::assert_snapshot!(stderr, @r###" 687 Rebased 1 commits onto destination 688 Rebased 3 descendant commits 689 Working copy now at: vruxwmqv 986b7a49 merge | merge 690 Parent commit : royxmykx c07c677c b | b 691 Parent commit : zsuskuln abc90087 a | a 692 Added 0 files, modified 0 files, removed 1 files 693 "###); 694 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 695 ◉ base 696 @ merge 697 ├─╮ 698 │ ◉ a 699 ◉ │ b 700 ├─╯ 701 702 "###); 703 704 // TODO(ilyagr): These will be good tests for `jj rebase --insert-after` and 705 // `--insert-before`, once those are implemented. 706} 707 708#[test] 709fn test_rebase_multiple_destinations() { 710 let test_env = TestEnvironment::default(); 711 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 712 let repo_path = test_env.env_root().join("repo"); 713 714 create_commit(&test_env, &repo_path, "a", &[]); 715 create_commit(&test_env, &repo_path, "b", &[]); 716 create_commit(&test_env, &repo_path, "c", &[]); 717 // Test the setup 718 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 719 @ c 720 │ ◉ b 721 ├─╯ 722 │ ◉ a 723 ├─╯ 724 725 "###); 726 727 let (stdout, stderr) = 728 test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "a", "-d", "b", "-d", "c"]); 729 insta::assert_snapshot!(stdout, @""); 730 insta::assert_snapshot!(stderr, @r###" 731 Rebased 1 commits onto destination 732 "###); 733 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 734 ◉ a 735 ├─╮ 736 │ @ c 737 ◉ │ b 738 ├─╯ 739 740 "###); 741 742 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "b|c"]); 743 insta::assert_snapshot!(stderr, @r###" 744 Error: Revset "b|c" resolved to more than one revision 745 Hint: The revset "b|c" resolved to these revisions: 746 royxmykx fe2e8e8b c | c 747 zsuskuln d370aee1 b | b 748 Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:b|c'). 749 "###); 750 751 // try with 'all:' and succeed 752 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "a", "-d", "all:b|c"]); 753 insta::assert_snapshot!(stdout, @""); 754 insta::assert_snapshot!(stderr, @r###" 755 Rebased 1 commits onto destination 756 "###); 757 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 758 ◉ a 759 ├─╮ 760 │ ◉ b 761 @ │ c 762 ├─╯ 763 764 "###); 765 766 // undo and do it again, but with 'ui.always-allow-large-revsets' 767 let (_, _) = test_env.jj_cmd_ok(&repo_path, &["undo"]); 768 let (_, _) = test_env.jj_cmd_ok( 769 &repo_path, 770 &[ 771 "rebase", 772 "--config-toml=ui.always-allow-large-revsets=true", 773 "-r=a", 774 "-d=b|c", 775 ], 776 ); 777 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 778 ◉ a 779 ├─╮ 780 │ ◉ b 781 @ │ c 782 ├─╯ 783 784 "###); 785 786 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "b", "-d", "b"]); 787 insta::assert_snapshot!(stderr, @r###" 788 Error: More than one revset resolved to revision d370aee184ba 789 "###); 790 791 // Same error with 'all:' if there is overlap. 792 let stderr = test_env.jj_cmd_failure( 793 &repo_path, 794 &["rebase", "-r", "a", "-d", "all:b|c", "-d", "b"], 795 ); 796 insta::assert_snapshot!(stderr, @r###" 797 Error: More than one revset resolved to revision d370aee184ba 798 "###); 799 800 let stderr = test_env.jj_cmd_failure( 801 &repo_path, 802 &["rebase", "-r", "a", "-d", "b", "-d", "root()"], 803 ); 804 insta::assert_snapshot!(stderr, @r###" 805 Error: The Git backend does not support creating merge commits with the root commit as one of the parents. 806 "###); 807} 808 809#[test] 810fn test_rebase_with_descendants() { 811 let test_env = TestEnvironment::default(); 812 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 813 let repo_path = test_env.env_root().join("repo"); 814 815 create_commit(&test_env, &repo_path, "a", &[]); 816 create_commit(&test_env, &repo_path, "b", &[]); 817 create_commit(&test_env, &repo_path, "c", &["a", "b"]); 818 create_commit(&test_env, &repo_path, "d", &["c"]); 819 // Test the setup 820 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 821 @ d 822 ◉ c 823 ├─╮ 824 │ ◉ b 825 ◉ │ a 826 ├─╯ 827 828 "###); 829 830 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "b", "-d", "a"]); 831 insta::assert_snapshot!(stdout, @""); 832 insta::assert_snapshot!(stderr, @r###" 833 Rebased 3 commits 834 Working copy now at: vruxwmqv 705832bd d | d 835 Parent commit : royxmykx 57c7246a c | c 836 "###); 837 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 838 @ d 839 ◉ c 840 ├─╮ 841 │ ◉ b 842 ├─╯ 843 ◉ a 844 845 "###); 846 847 // Rebase several subtrees at once. 848 test_env.jj_cmd_ok(&repo_path, &["undo"]); 849 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s=c", "-s=d", "-d=a"]); 850 insta::assert_snapshot!(stdout, @""); 851 insta::assert_snapshot!(stderr, @r###" 852 Rebased 2 commits 853 Working copy now at: vruxwmqv 92c2bc9a d | d 854 Parent commit : rlvkpnrz 2443ea76 a | a 855 Added 0 files, modified 0 files, removed 2 files 856 "###); 857 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 858 @ d 859 │ ◉ c 860 ├─╯ 861 ◉ a 862 │ ◉ b 863 ├─╯ 864 865 "###); 866 867 test_env.jj_cmd_ok(&repo_path, &["undo"]); 868 // Reminder of the setup 869 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 870 @ d 871 ◉ c 872 ├─╮ 873 │ ◉ b 874 ◉ │ a 875 ├─╯ 876 877 "###); 878 879 // `d` was a descendant of `b`, and both are moved to be direct descendants of 880 // `a`. `c` remains a descendant of `b`. 881 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s=b", "-s=d", "-d=a"]); 882 insta::assert_snapshot!(stdout, @""); 883 insta::assert_snapshot!(stderr, @r###" 884 Rebased 3 commits 885 Working copy now at: vruxwmqv f1e71cb7 d | d 886 Parent commit : rlvkpnrz 2443ea76 a | a 887 Added 0 files, modified 0 files, removed 2 files 888 "###); 889 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 890 ◉ c 891 ├─╮ 892 │ ◉ b 893 ├─╯ 894 │ @ d 895 ├─╯ 896 ◉ a 897 898 "###); 899 900 // Same test as above, but with multiple commits per argument 901 test_env.jj_cmd_ok(&repo_path, &["undo"]); 902 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-s=b|d", "-d=a"]); 903 insta::assert_snapshot!(stderr, @r###" 904 Error: Revset "b|d" resolved to more than one revision 905 Hint: The revset "b|d" resolved to these revisions: 906 vruxwmqv df54a9fd d | d 907 zsuskuln d370aee1 b | b 908 Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:b|d'). 909 "###); 910 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s=all:b|d", "-d=a"]); 911 insta::assert_snapshot!(stdout, @""); 912 insta::assert_snapshot!(stderr, @r###" 913 Rebased 3 commits 914 Working copy now at: vruxwmqv d17539f7 d | d 915 Parent commit : rlvkpnrz 2443ea76 a | a 916 Added 0 files, modified 0 files, removed 2 files 917 "###); 918 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 919 ◉ c 920 ├─╮ 921 │ ◉ b 922 ├─╯ 923 │ @ d 924 ├─╯ 925 ◉ a 926 927 "###); 928} 929 930#[test] 931fn test_rebase_error_revision_does_not_exist() { 932 let test_env = TestEnvironment::default(); 933 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 934 let repo_path = test_env.env_root().join("repo"); 935 936 test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "one"]); 937 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b-one"]); 938 test_env.jj_cmd_ok(&repo_path, &["new", "-r", "@-", "-m", "two"]); 939 940 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b", "b-one", "-d", "this"]); 941 insta::assert_snapshot!(stderr, @r###" 942 Error: Revision "this" doesn't exist 943 "###); 944 945 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b", "this", "-d", "b-one"]); 946 insta::assert_snapshot!(stderr, @r###" 947 Error: Revision "this" doesn't exist 948 "###); 949} 950 951fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { 952 test_env.jj_cmd_success(repo_path, &["log", "-T", "branches"]) 953} 954 955// This behavior illustrates https://github.com/martinvonz/jj/issues/2600 956#[test] 957fn test_rebase_with_child_and_descendant_bug_2600() { 958 let test_env = TestEnvironment::default(); 959 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 960 let repo_path = test_env.env_root().join("repo"); 961 962 create_commit(&test_env, &repo_path, "notroot", &[]); 963 create_commit(&test_env, &repo_path, "base", &["notroot"]); 964 create_commit(&test_env, &repo_path, "a", &["base"]); 965 create_commit(&test_env, &repo_path, "b", &["base", "a"]); 966 create_commit(&test_env, &repo_path, "c", &["b"]); 967 let setup_opid = test_env.current_operation_id(&repo_path); 968 969 // Test the setup 970 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 971 @ c 972 ◉ b 973 ├─╮ 974 │ ◉ a 975 ├─╯ 976 ◉ base 977 ◉ notroot 978 979 "###); 980 981 // ===================== rebase -s tests ================= 982 let (stdout, stderr) = 983 test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "base", "-d", "notroot"]); 984 insta::assert_snapshot!(stdout, @""); 985 // This should be a no-op 986 insta::assert_snapshot!(stderr, @r###" 987 Skipped rebase of 1 commits that were already in place 988 "###); 989 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 990 @ c 991 ◉ b 992 ├─╮ 993 │ ◉ a 994 ├─╯ 995 ◉ base 996 ◉ notroot 997 998 "###); 999 1000 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1001 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "a", "-d", "base"]); 1002 insta::assert_snapshot!(stdout, @""); 1003 // This should be a no-op 1004 insta::assert_snapshot!(stderr, @r###" 1005 Skipped rebase of 1 commits that were already in place 1006 "###); 1007 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1008 @ c 1009 ◉ b 1010 ├─╮ 1011 │ ◉ a 1012 ├─╯ 1013 ◉ base 1014 ◉ notroot 10151016 "###); 1017 1018 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1019 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "a", "-d", "root()"]); 1020 insta::assert_snapshot!(stdout, @""); 1021 insta::assert_snapshot!(stderr, @r###" 1022 Rebased 3 commits 1023 Working copy now at: znkkpsqq cf8ecff5 c | c 1024 Parent commit : vruxwmqv 24e1a270 b | b 1025 "###); 1026 // Commit "a" should be rebased onto the root commit. Commit "b" should have 1027 // "base" and "a" as parents as before. 1028 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1029 @ c 1030 ◉ b 1031 ├─╮ 1032 │ ◉ a 1033 ◉ │ base 1034 ◉ │ notroot 1035 ├─╯ 10361037 "###); 1038 1039 // ===================== rebase -b tests ================= 1040 // ====== Reminder of the setup ========= 1041 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1042 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1043 @ c 1044 ◉ b 1045 ├─╮ 1046 │ ◉ a 1047 ├─╯ 1048 ◉ base 1049 ◉ notroot 10501051 "###); 1052 1053 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "c", "-d", "base"]); 1054 insta::assert_snapshot!(stdout, @""); 1055 // The commits in roots(base..c), i.e. commit "a" should be rebased onto "base", 1056 // which is a no-op 1057 insta::assert_snapshot!(stderr, @r###" 1058 Skipped rebase of 1 commits that were already in place 1059 "###); 1060 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1061 @ c 1062 ◉ b 1063 ├─╮ 1064 │ ◉ a 1065 ├─╯ 1066 ◉ base 1067 ◉ notroot 10681069 "###); 1070 1071 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1072 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "c", "-d", "a"]); 1073 insta::assert_snapshot!(stdout, @""); 1074 insta::assert_snapshot!(stderr, @r###" 1075 Rebased 2 commits 1076 Working copy now at: znkkpsqq 76914dcc c | c 1077 Parent commit : vruxwmqv f73f03c7 b | b 1078 "###); 1079 // The commits in roots(a..c), i.e. commit "b" should be rebased onto "a", 1080 // which means "b" loses its "base" parent 1081 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1082 @ c 1083 ◉ b 1084 ◉ a 1085 ◉ base 1086 ◉ notroot 10871088 "###); 1089 1090 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1091 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "a", "-d", "root()"]); 1092 insta::assert_snapshot!(stdout, @""); 1093 // This should be a no-op 1094 insta::assert_snapshot!(stderr, @r###" 1095 Skipped rebase of 1 commits that were already in place 1096 "###); 1097 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1098 @ c 1099 ◉ b 1100 ├─╮ 1101 │ ◉ a 1102 ├─╯ 1103 ◉ base 1104 ◉ notroot 11051106 "###); 1107 1108 // ===================== rebase -r tests ================= 1109 // ====== Reminder of the setup ========= 1110 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1111 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1112 @ c 1113 ◉ b 1114 ├─╮ 1115 │ ◉ a 1116 ├─╯ 1117 ◉ base 1118 ◉ notroot 11191120 "###); 1121 1122 let (stdout, stderr) = 1123 test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "root()"]); 1124 insta::assert_snapshot!(stdout, @""); 1125 insta::assert_snapshot!(stderr, @r###" 1126 Rebased 1 commits onto destination 1127 Rebased 3 descendant commits 1128 Working copy now at: znkkpsqq 45371aaf c | c 1129 Parent commit : vruxwmqv c0a76bf4 b | b 1130 Added 0 files, modified 0 files, removed 1 files 1131 "###); 1132 // The user would expect unsimplified ancestry here. 1133 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1134 @ c 1135 ◉ b 1136 ├─╮ 1137 │ ◉ a 1138 ├─╯ 1139 ◉ notroot 1140 │ ◉ base 1141 ├─╯ 11421143 "###); 1144 1145 // This tests the algorithm for rebasing onto descendants. The result should 1146 // have unsimplified ancestry. 1147 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1148 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "b"]); 1149 insta::assert_snapshot!(stdout, @""); 1150 insta::assert_snapshot!(stderr, @r###" 1151 Rebased 1 commits onto destination 1152 Rebased 3 descendant commits 1153 Working copy now at: znkkpsqq e28fa972 c | c 1154 Parent commit : vruxwmqv 8d0eeb6a b | b 1155 Added 0 files, modified 0 files, removed 1 files 1156 "###); 1157 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1158 @ c 1159 │ ◉ base 1160 ├─╯ 1161 ◉ b 1162 ├─╮ 1163 │ ◉ a 1164 ├─╯ 1165 ◉ notroot 11661167 "###); 1168 1169 // This tests the algorithm for rebasing onto descendants. The result should 1170 // have unsimplified ancestry. 1171 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1172 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "a"]); 1173 insta::assert_snapshot!(stdout, @""); 1174 insta::assert_snapshot!(stderr, @r###" 1175 Rebased 1 commits onto destination 1176 Rebased 3 descendant commits 1177 Working copy now at: znkkpsqq a9da974c c | c 1178 Parent commit : vruxwmqv 0072139c b | b 1179 Added 0 files, modified 0 files, removed 1 files 1180 "###); 1181 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1182 @ c 1183 ◉ b 1184 ├─╮ 1185 │ │ ◉ base 1186 │ ├─╯ 1187 │ ◉ a 1188 ├─╯ 1189 ◉ notroot 11901191 "###); 1192 1193 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1194 // ====== Reminder of the setup ========= 1195 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1196 @ c 1197 ◉ b 1198 ├─╮ 1199 │ ◉ a 1200 ├─╯ 1201 ◉ base 1202 ◉ notroot 12031204 "###); 1205 1206 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "a", "-d", "root()"]); 1207 insta::assert_snapshot!(stdout, @""); 1208 insta::assert_snapshot!(stderr, @r###" 1209 Rebased 1 commits onto destination 1210 Rebased 2 descendant commits 1211 Working copy now at: znkkpsqq 7210b05e c | c 1212 Parent commit : vruxwmqv da3f7511 b | b 1213 Added 0 files, modified 0 files, removed 1 files 1214 "###); 1215 // In this case, it is unclear whether the user would always prefer unsimplified 1216 // ancestry (whether `b` should also be a direct child of the root commit). 1217 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1218 @ c 1219 ◉ b 1220 ◉ base 1221 ◉ notroot 1222 │ ◉ a 1223 ├─╯ 12241225 "###); 1226 1227 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1228 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-d", "root()"]); 1229 insta::assert_snapshot!(stdout, @""); 1230 insta::assert_snapshot!(stderr, @r###" 1231 Rebased 1 commits onto destination 1232 Rebased 1 descendant commits 1233 Working copy now at: znkkpsqq f280545e c | c 1234 Parent commit : zsuskuln 0a7fb8f6 base | base 1235 Parent commit : royxmykx 86a06598 a | a 1236 Added 0 files, modified 0 files, removed 1 files 1237 "###); 1238 // The user would expect unsimplified ancestry here. 1239 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1240 @ c 1241 ├─╮ 1242 │ ◉ a 1243 ├─╯ 1244 ◉ base 1245 ◉ notroot 1246 │ ◉ b 1247 ├─╯ 12481249 "###); 1250 1251 // This tests the algorithm for rebasing onto descendants. The result should 1252 // have unsimplified ancestry. 1253 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1254 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-d", "c"]); 1255 insta::assert_snapshot!(stdout, @""); 1256 insta::assert_snapshot!(stderr, @r###" 1257 Rebased 1 commits onto destination 1258 Rebased 1 descendant commits 1259 Working copy now at: znkkpsqq c0a7cd80 c | c 1260 Parent commit : zsuskuln 0a7fb8f6 base | base 1261 Parent commit : royxmykx 86a06598 a | a 1262 Added 0 files, modified 0 files, removed 1 files 1263 "###); 1264 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1265 ◉ b 1266 @ c 1267 ├─╮ 1268 │ ◉ a 1269 ├─╯ 1270 ◉ base 1271 ◉ notroot 12721273 "###); 1274 1275 // In this test, the commit with weird ancestry is not rebased (neither directly 1276 // nor indirectly). 1277 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1278 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "a"]); 1279 insta::assert_snapshot!(stdout, @""); 1280 insta::assert_snapshot!(stderr, @r###" 1281 Rebased 1 commits onto destination 1282 Working copy now at: znkkpsqq 7a3bc050 c | c 1283 Parent commit : royxmykx 86a06598 a | a 1284 Added 0 files, modified 0 files, removed 1 files 1285 "###); 1286 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 1287 @ c 1288 │ ◉ b 1289 ╭─┤ 1290 ◉ │ a 1291 ├─╯ 1292 ◉ base 1293 ◉ notroot 12941295 "###); 1296} 1297 1298#[test] 1299fn test_rebase_revisions_after() { 1300 let test_env = TestEnvironment::default(); 1301 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 1302 let repo_path = test_env.env_root().join("repo"); 1303 1304 create_commit(&test_env, &repo_path, "a", &[]); 1305 create_commit(&test_env, &repo_path, "b1", &["a"]); 1306 create_commit(&test_env, &repo_path, "b2", &["b1"]); 1307 create_commit(&test_env, &repo_path, "b3", &["a"]); 1308 create_commit(&test_env, &repo_path, "b4", &["b3"]); 1309 create_commit(&test_env, &repo_path, "c", &["b2", "b4"]); 1310 create_commit(&test_env, &repo_path, "d", &["c"]); 1311 create_commit(&test_env, &repo_path, "e", &["c"]); 1312 create_commit(&test_env, &repo_path, "f", &["e"]); 1313 // Test the setup 1314 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1315 @ f xznxytkn e4a00798 1316 ◉ e nkmrtpmo 858693f7 1317 │ ◉ d lylxulpl 7d0512e5 1318 ├─╯ 1319 ◉ c kmkuslsw cd86b3e4 1320 ├─╮ 1321 │ ◉ b4 znkkpsqq a52a83a4 1322 │ ◉ b3 vruxwmqv 523e6a8b 1323 ◉ │ b2 royxmykx 2b8e1148 1324 ◉ │ b1 zsuskuln 072d5ae1 1325 ├─╯ 1326 ◉ a rlvkpnrz 2443ea76 1327 ◉ zzzzzzzz 00000000 1328 "###); 1329 let setup_opid = test_env.current_operation_id(&repo_path); 1330 1331 // Rebasing a commit after its parents should be a no-op. 1332 let (stdout, stderr) = test_env.jj_cmd_ok( 1333 &repo_path, 1334 &["rebase", "-r", "c", "--after", "b2", "--after", "b4"], 1335 ); 1336 insta::assert_snapshot!(stdout, @""); 1337 insta::assert_snapshot!(stderr, @r###" 1338 Skipped rebase of 4 commits that were already in place 1339 Nothing changed. 1340 "###); 1341 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1342 @ f xznxytkn e4a00798 1343 ◉ e nkmrtpmo 858693f7 1344 │ ◉ d lylxulpl 7d0512e5 1345 ├─╯ 1346 ◉ c kmkuslsw cd86b3e4 1347 ├─╮ 1348 │ ◉ b4 znkkpsqq a52a83a4 1349 │ ◉ b3 vruxwmqv 523e6a8b 1350 ◉ │ b2 royxmykx 2b8e1148 1351 ◉ │ b1 zsuskuln 072d5ae1 1352 ├─╯ 1353 ◉ a rlvkpnrz 2443ea76 1354 ◉ zzzzzzzz 00000000 1355 "###); 1356 1357 // Rebasing a commit after itself should be a no-op. 1358 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "--after", "c"]); 1359 insta::assert_snapshot!(stdout, @""); 1360 insta::assert_snapshot!(stderr, @r###" 1361 Skipped rebase of 4 commits that were already in place 1362 Nothing changed. 1363 "###); 1364 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1365 @ f xznxytkn e4a00798 1366 ◉ e nkmrtpmo 858693f7 1367 │ ◉ d lylxulpl 7d0512e5 1368 ├─╯ 1369 ◉ c kmkuslsw cd86b3e4 1370 ├─╮ 1371 │ ◉ b4 znkkpsqq a52a83a4 1372 │ ◉ b3 vruxwmqv 523e6a8b 1373 ◉ │ b2 royxmykx 2b8e1148 1374 ◉ │ b1 zsuskuln 072d5ae1 1375 ├─╯ 1376 ◉ a rlvkpnrz 2443ea76 1377 ◉ zzzzzzzz 00000000 1378 "###); 1379 1380 // Rebase a commit after another commit. "c" has parents "b2" and "b4", so its 1381 // children "d" and "e" should be rebased onto "b2" and "b4" respectively. 1382 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "--after", "e"]); 1383 insta::assert_snapshot!(stdout, @""); 1384 insta::assert_snapshot!(stderr, @r###" 1385 Rebased 1 commits onto destination 1386 Rebased 3 descendant commits 1387 Working copy now at: xznxytkn e0e873c8 f | f 1388 Parent commit : kmkuslsw 754793f3 c | c 1389 "###); 1390 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1391 @ f xznxytkn e0e873c8 1392 ◉ c kmkuslsw 754793f3 1393 ◉ e nkmrtpmo e0d7fb63 1394 ├─╮ 1395 │ │ ◉ d lylxulpl 5e9cb58d 1396 ╭─┬─╯ 1397 │ ◉ b4 znkkpsqq a52a83a4 1398 │ ◉ b3 vruxwmqv 523e6a8b 1399 ◉ │ b2 royxmykx 2b8e1148 1400 ◉ │ b1 zsuskuln 072d5ae1 1401 ├─╯ 1402 ◉ a rlvkpnrz 2443ea76 1403 ◉ zzzzzzzz 00000000 1404 "###); 1405 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1406 1407 // Rebase a commit after a leaf commit. 1408 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "e", "--after", "f"]); 1409 insta::assert_snapshot!(stdout, @""); 1410 insta::assert_snapshot!(stderr, @r###" 1411 Rebased 1 commits onto destination 1412 Rebased 1 descendant commits 1413 Working copy now at: xznxytkn 9804b742 f | f 1414 Parent commit : kmkuslsw cd86b3e4 c | c 1415 Added 0 files, modified 0 files, removed 1 files 1416 "###); 1417 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1418 ◉ e nkmrtpmo 76ac6464 1419 @ f xznxytkn 9804b742 1420 │ ◉ d lylxulpl 7d0512e5 1421 ├─╯ 1422 ◉ c kmkuslsw cd86b3e4 1423 ├─╮ 1424 │ ◉ b4 znkkpsqq a52a83a4 1425 │ ◉ b3 vruxwmqv 523e6a8b 1426 ◉ │ b2 royxmykx 2b8e1148 1427 ◉ │ b1 zsuskuln 072d5ae1 1428 ├─╯ 1429 ◉ a rlvkpnrz 2443ea76 1430 ◉ zzzzzzzz 00000000 1431 "###); 1432 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1433 1434 // Rebase a commit after a commit in a branch of a merge commit. 1435 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--after", "b1"]); 1436 insta::assert_snapshot!(stdout, @""); 1437 insta::assert_snapshot!(stderr, @r###" 1438 Rebased 1 commits onto destination 1439 Rebased 4 descendant commits 1440 Working copy now at: xznxytkn 80c27408 f | f 1441 Parent commit : zsuskuln 072d5ae1 b1 | b1 1442 Added 0 files, modified 0 files, removed 5 files 1443 "###); 1444 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1445 ◉ e nkmrtpmo cee7a197 1446 │ ◉ d lylxulpl 1eb960ec 1447 ├─╯ 1448 ◉ c kmkuslsw 305a7803 1449 ├─╮ 1450 │ ◉ b4 znkkpsqq a52a83a4 1451 │ ◉ b3 vruxwmqv 523e6a8b 1452 ◉ │ b2 royxmykx 526481b4 1453 @ │ f xznxytkn 80c27408 1454 ◉ │ b1 zsuskuln 072d5ae1 1455 ├─╯ 1456 ◉ a rlvkpnrz 2443ea76 1457 ◉ zzzzzzzz 00000000 1458 "###); 1459 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1460 1461 // Rebase a commit after the last commit in a branch of a merge commit. 1462 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--after", "b2"]); 1463 insta::assert_snapshot!(stdout, @""); 1464 insta::assert_snapshot!(stderr, @r###" 1465 Rebased 1 commits onto destination 1466 Rebased 3 descendant commits 1467 Working copy now at: xznxytkn ebbc24b1 f | f 1468 Parent commit : royxmykx 2b8e1148 b2 | b2 1469 Added 0 files, modified 0 files, removed 4 files 1470 "###); 1471 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1472 ◉ e nkmrtpmo 3162ac52 1473 │ ◉ d lylxulpl 6f7f3b2a 1474 ├─╯ 1475 ◉ c kmkuslsw d33f69f1 1476 ├─╮ 1477 │ @ f xznxytkn ebbc24b1 1478 │ ◉ b2 royxmykx 2b8e1148 1479 │ ◉ b1 zsuskuln 072d5ae1 1480 ◉ │ b4 znkkpsqq a52a83a4 1481 ◉ │ b3 vruxwmqv 523e6a8b 1482 ├─╯ 1483 ◉ a rlvkpnrz 2443ea76 1484 ◉ zzzzzzzz 00000000 1485 "###); 1486 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1487 1488 // Rebase a commit after a commit with multiple children. 1489 // "c" has two children "d" and "e", so the rebased commit "f" will inherit the 1490 // two children. 1491 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--after", "c"]); 1492 insta::assert_snapshot!(stdout, @""); 1493 insta::assert_snapshot!(stderr, @r###" 1494 Rebased 1 commits onto destination 1495 Rebased 2 descendant commits 1496 Working copy now at: xznxytkn 8f8c91d3 f | f 1497 Parent commit : kmkuslsw cd86b3e4 c | c 1498 Added 0 files, modified 0 files, removed 1 files 1499 "###); 1500 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1501 ◉ e nkmrtpmo 03ade273 1502 │ ◉ d lylxulpl 8bccbeda 1503 ├─╯ 1504 @ f xznxytkn 8f8c91d3 1505 ◉ c kmkuslsw cd86b3e4 1506 ├─╮ 1507 │ ◉ b4 znkkpsqq a52a83a4 1508 │ ◉ b3 vruxwmqv 523e6a8b 1509 ◉ │ b2 royxmykx 2b8e1148 1510 ◉ │ b1 zsuskuln 072d5ae1 1511 ├─╯ 1512 ◉ a rlvkpnrz 2443ea76 1513 ◉ zzzzzzzz 00000000 1514 "###); 1515 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1516 1517 // Rebase a commit after multiple commits. 1518 let (stdout, stderr) = test_env.jj_cmd_ok( 1519 &repo_path, 1520 &["rebase", "-r", "f", "--after", "e", "--after", "d"], 1521 ); 1522 insta::assert_snapshot!(stdout, @""); 1523 insta::assert_snapshot!(stderr, @r###" 1524 Rebased 1 commits onto destination 1525 Working copy now at: xznxytkn 7784e5a0 f | f 1526 Parent commit : nkmrtpmo 858693f7 e | e 1527 Parent commit : lylxulpl 7d0512e5 d | d 1528 Added 1 files, modified 0 files, removed 0 files 1529 "###); 1530 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1531 @ f xznxytkn 7784e5a0 1532 ├─╮ 1533 │ ◉ d lylxulpl 7d0512e5 1534 ◉ │ e nkmrtpmo 858693f7 1535 ├─╯ 1536 ◉ c kmkuslsw cd86b3e4 1537 ├─╮ 1538 │ ◉ b4 znkkpsqq a52a83a4 1539 │ ◉ b3 vruxwmqv 523e6a8b 1540 ◉ │ b2 royxmykx 2b8e1148 1541 ◉ │ b1 zsuskuln 072d5ae1 1542 ├─╯ 1543 ◉ a rlvkpnrz 2443ea76 1544 ◉ zzzzzzzz 00000000 1545 "###); 1546 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1547 1548 // Rebase two unrelated commits. 1549 let (stdout, stderr) = test_env.jj_cmd_ok( 1550 &repo_path, 1551 &["rebase", "-r", "d", "-r", "e", "--after", "a"], 1552 ); 1553 insta::assert_snapshot!(stdout, @""); 1554 insta::assert_snapshot!(stderr, @r###" 1555 Rebased 2 commits onto destination 1556 Rebased 6 descendant commits 1557 Working copy now at: xznxytkn 0b53613e f | f 1558 Parent commit : kmkuslsw 193687bb c | c 1559 Added 1 files, modified 0 files, removed 0 files 1560 "###); 1561 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1562 @ f xznxytkn 0b53613e 1563 ◉ c kmkuslsw 193687bb 1564 ├─╮ 1565 │ ◉ b4 znkkpsqq e8d0f57b 1566 │ ◉ b3 vruxwmqv cb48344c 1567 │ ├─╮ 1568 ◉ │ │ b2 royxmykx 535f779d 1569 ◉ │ │ b1 zsuskuln 693186c0 1570 ╰─┬─╮ 1571 │ ◉ e nkmrtpmo 2bb4e0b6 1572 ◉ │ d lylxulpl 0b921a1c 1573 ├─╯ 1574 ◉ a rlvkpnrz 2443ea76 1575 ◉ zzzzzzzz 00000000 1576 "###); 1577 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1578 1579 // Rebase a subgraph with merge commit and two parents, which should preserve 1580 // the merge. 1581 let (stdout, stderr) = test_env.jj_cmd_ok( 1582 &repo_path, 1583 &["rebase", "-r", "b2", "-r", "b4", "-r", "c", "--after", "f"], 1584 ); 1585 insta::assert_snapshot!(stdout, @""); 1586 insta::assert_snapshot!(stderr, @r###" 1587 Rebased 3 commits onto destination 1588 Rebased 3 descendant commits 1589 Working copy now at: xznxytkn eaf1d6b8 f | f 1590 Parent commit : nkmrtpmo 0d7e4ce9 e | e 1591 Added 0 files, modified 0 files, removed 3 files 1592 "###); 1593 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1594 ◉ d lylxulpl 16060da9 1595 ├─╮ 1596 │ │ ◉ c kmkuslsw ef5ead27 1597 │ │ ├─╮ 1598 │ │ │ ◉ b4 znkkpsqq 9c884b94 1599 │ │ ◉ │ b2 royxmykx bdfea21d 1600 │ │ ├─╯ 1601 │ │ @ f xznxytkn eaf1d6b8 1602 │ │ ◉ e nkmrtpmo 0d7e4ce9 1603 ╭─┬─╯ 1604 │ ◉ b3 vruxwmqv 523e6a8b 1605 ◉ │ b1 zsuskuln 072d5ae1 1606 ├─╯ 1607 ◉ a rlvkpnrz 2443ea76 1608 ◉ zzzzzzzz 00000000 1609 "###); 1610 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1611 1612 // Rebase a subgraph with four commits after one of the commits itself. 1613 let (stdout, stderr) = 1614 test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b1::d", "--after", "c"]); 1615 insta::assert_snapshot!(stdout, @""); 1616 insta::assert_snapshot!(stderr, @r###" 1617 Rebased 4 commits onto destination 1618 Rebased 2 descendant commits 1619 Working copy now at: xznxytkn 084e0629 f | f 1620 Parent commit : nkmrtpmo 563d78c6 e | e 1621 Added 1 files, modified 0 files, removed 0 files 1622 "###); 1623 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1624 @ f xznxytkn 084e0629 1625 ◉ e nkmrtpmo 563d78c6 1626 ◉ d lylxulpl e67ba5c9 1627 ◉ c kmkuslsw 049aa109 1628 ◉ b2 royxmykx 7af3d6cd 1629 ◉ b1 zsuskuln cd84b343 1630 ├─╮ 1631 │ ◉ b4 znkkpsqq a52a83a4 1632 │ ◉ b3 vruxwmqv 523e6a8b 1633 ├─╯ 1634 ◉ a rlvkpnrz 2443ea76 1635 ◉ zzzzzzzz 00000000 1636 "###); 1637 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1638 1639 // Rebase a subgraph with disconnected commits. Since "b2" is an ancestor of 1640 // "e", "b2" should be a parent of "e" after the rebase. 1641 let (stdout, stderr) = test_env.jj_cmd_ok( 1642 &repo_path, 1643 &["rebase", "-r", "e", "-r", "b2", "--after", "d"], 1644 ); 1645 insta::assert_snapshot!(stdout, @""); 1646 insta::assert_snapshot!(stderr, @r###" 1647 Rebased 2 commits onto destination 1648 Rebased 3 descendant commits 1649 Working copy now at: xznxytkn 4fb2bb60 f | f 1650 Parent commit : kmkuslsw cebde86a c | c 1651 Added 0 files, modified 0 files, removed 2 files 1652 "###); 1653 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1654 @ f xznxytkn 4fb2bb60 1655 │ ◉ e nkmrtpmo 1ea93588 1656 │ ◉ b2 royxmykx 064e3bcb 1657 │ ◉ d lylxulpl b46a9d31 1658 ├─╯ 1659 ◉ c kmkuslsw cebde86a 1660 ├─╮ 1661 │ ◉ b4 znkkpsqq a52a83a4 1662 │ ◉ b3 vruxwmqv 523e6a8b 1663 ◉ │ b1 zsuskuln 072d5ae1 1664 ├─╯ 1665 ◉ a rlvkpnrz 2443ea76 1666 ◉ zzzzzzzz 00000000 1667 "###); 1668 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1669 1670 // Should error if a loop will be created. 1671 let stderr = test_env.jj_cmd_failure( 1672 &repo_path, 1673 &["rebase", "-r", "e", "--after", "a", "--after", "b2"], 1674 ); 1675 insta::assert_snapshot!(stderr, @r###" 1676 Error: Refusing to create a loop: commit 2b8e1148290f would be both an ancestor and a descendant of the rebased commits 1677 "###); 1678} 1679 1680#[test] 1681fn test_rebase_revisions_before() { 1682 let test_env = TestEnvironment::default(); 1683 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 1684 let repo_path = test_env.env_root().join("repo"); 1685 1686 create_commit(&test_env, &repo_path, "a", &[]); 1687 create_commit(&test_env, &repo_path, "b1", &["a"]); 1688 create_commit(&test_env, &repo_path, "b2", &["b1"]); 1689 create_commit(&test_env, &repo_path, "b3", &["a"]); 1690 create_commit(&test_env, &repo_path, "b4", &["b3"]); 1691 create_commit(&test_env, &repo_path, "c", &["b2", "b4"]); 1692 create_commit(&test_env, &repo_path, "d", &["c"]); 1693 create_commit(&test_env, &repo_path, "e", &["c"]); 1694 create_commit(&test_env, &repo_path, "f", &["e"]); 1695 // Test the setup 1696 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1697 @ f xznxytkn e4a00798 1698 ◉ e nkmrtpmo 858693f7 1699 │ ◉ d lylxulpl 7d0512e5 1700 ├─╯ 1701 ◉ c kmkuslsw cd86b3e4 1702 ├─╮ 1703 │ ◉ b4 znkkpsqq a52a83a4 1704 │ ◉ b3 vruxwmqv 523e6a8b 1705 ◉ │ b2 royxmykx 2b8e1148 1706 ◉ │ b1 zsuskuln 072d5ae1 1707 ├─╯ 1708 ◉ a rlvkpnrz 2443ea76 1709 ◉ zzzzzzzz 00000000 1710 "###); 1711 let setup_opid = test_env.current_operation_id(&repo_path); 1712 1713 // Rebasing a commit before its children should be a no-op. 1714 let (stdout, stderr) = test_env.jj_cmd_ok( 1715 &repo_path, 1716 &["rebase", "-r", "c", "--before", "d", "--before", "e"], 1717 ); 1718 insta::assert_snapshot!(stdout, @""); 1719 insta::assert_snapshot!(stderr, @r###" 1720 Skipped rebase of 4 commits that were already in place 1721 Nothing changed. 1722 "###); 1723 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1724 @ f xznxytkn e4a00798 1725 ◉ e nkmrtpmo 858693f7 1726 │ ◉ d lylxulpl 7d0512e5 1727 ├─╯ 1728 ◉ c kmkuslsw cd86b3e4 1729 ├─╮ 1730 │ ◉ b4 znkkpsqq a52a83a4 1731 │ ◉ b3 vruxwmqv 523e6a8b 1732 ◉ │ b2 royxmykx 2b8e1148 1733 ◉ │ b1 zsuskuln 072d5ae1 1734 ├─╯ 1735 ◉ a rlvkpnrz 2443ea76 1736 ◉ zzzzzzzz 00000000 1737 "###); 1738 1739 // Rebasing a commit before itself should be a no-op. 1740 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "--before", "c"]); 1741 insta::assert_snapshot!(stdout, @""); 1742 insta::assert_snapshot!(stderr, @r###" 1743 Skipped rebase of 4 commits that were already in place 1744 Nothing changed. 1745 "###); 1746 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1747 @ f xznxytkn e4a00798 1748 ◉ e nkmrtpmo 858693f7 1749 │ ◉ d lylxulpl 7d0512e5 1750 ├─╯ 1751 ◉ c kmkuslsw cd86b3e4 1752 ├─╮ 1753 │ ◉ b4 znkkpsqq a52a83a4 1754 │ ◉ b3 vruxwmqv 523e6a8b 1755 ◉ │ b2 royxmykx 2b8e1148 1756 ◉ │ b1 zsuskuln 072d5ae1 1757 ├─╯ 1758 ◉ a rlvkpnrz 2443ea76 1759 ◉ zzzzzzzz 00000000 1760 "###); 1761 1762 // Rebasing a commit before the root commit should error. 1763 let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "c", "--before", "root()"]); 1764 insta::assert_snapshot!(stderr, @r###" 1765 Error: The root commit 000000000000 is immutable 1766 "###); 1767 1768 // Rebase a commit before another commit. "c" has parents "b2" and "b4", so its 1769 // children "d" and "e" should be rebased onto "b2" and "b4" respectively. 1770 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "--before", "a"]); 1771 insta::assert_snapshot!(stdout, @""); 1772 insta::assert_snapshot!(stderr, @r###" 1773 Rebased 1 commits onto destination 1774 Rebased 8 descendant commits 1775 Working copy now at: xznxytkn 24335685 f | f 1776 Parent commit : nkmrtpmo e9a28d4b e | e 1777 "###); 1778 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1779 @ f xznxytkn 24335685 1780 ◉ e nkmrtpmo e9a28d4b 1781 ├─╮ 1782 │ │ ◉ d lylxulpl 6609e9c6 1783 ╭─┬─╯ 1784 │ ◉ b4 znkkpsqq 4b39b18c 1785 │ ◉ b3 vruxwmqv 39f79dcc 1786 ◉ │ b2 royxmykx ffcf6038 1787 ◉ │ b1 zsuskuln 85e90af6 1788 ├─╯ 1789 ◉ a rlvkpnrz 318ea816 1790 ◉ c kmkuslsw 5f99791e 1791 ◉ zzzzzzzz 00000000 1792 "###); 1793 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1794 1795 // Rebase a commit before its parent. 1796 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--before", "e"]); 1797 insta::assert_snapshot!(stdout, @""); 1798 insta::assert_snapshot!(stderr, @r###" 1799 Rebased 1 commits onto destination 1800 Rebased 1 descendant commits 1801 Working copy now at: xznxytkn 8e3b728a f | f 1802 Parent commit : kmkuslsw cd86b3e4 c | c 1803 Added 0 files, modified 0 files, removed 1 files 1804 "###); 1805 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1806 ◉ e nkmrtpmo 41706bd9 1807 @ f xznxytkn 8e3b728a 1808 │ ◉ d lylxulpl 7d0512e5 1809 ├─╯ 1810 ◉ c kmkuslsw cd86b3e4 1811 ├─╮ 1812 │ ◉ b4 znkkpsqq a52a83a4 1813 │ ◉ b3 vruxwmqv 523e6a8b 1814 ◉ │ b2 royxmykx 2b8e1148 1815 ◉ │ b1 zsuskuln 072d5ae1 1816 ├─╯ 1817 ◉ a rlvkpnrz 2443ea76 1818 ◉ zzzzzzzz 00000000 1819 "###); 1820 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1821 1822 // Rebase a commit before a commit in a branch of a merge commit. 1823 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--before", "b2"]); 1824 insta::assert_snapshot!(stdout, @""); 1825 insta::assert_snapshot!(stderr, @r###" 1826 Rebased 1 commits onto destination 1827 Rebased 4 descendant commits 1828 Working copy now at: xznxytkn 2b4f48f8 f | f 1829 Parent commit : zsuskuln 072d5ae1 b1 | b1 1830 Added 0 files, modified 0 files, removed 5 files 1831 "###); 1832 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1833 ◉ e nkmrtpmo 7cad61fd 1834 │ ◉ d lylxulpl 526b6ab6 1835 ├─╯ 1836 ◉ c kmkuslsw 445f6927 1837 ├─╮ 1838 │ ◉ b4 znkkpsqq a52a83a4 1839 │ ◉ b3 vruxwmqv 523e6a8b 1840 ◉ │ b2 royxmykx 972bfeb7 1841 @ │ f xznxytkn 2b4f48f8 1842 ◉ │ b1 zsuskuln 072d5ae1 1843 ├─╯ 1844 ◉ a rlvkpnrz 2443ea76 1845 ◉ zzzzzzzz 00000000 1846 "###); 1847 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1848 1849 // Rebase a commit before the first commit in a branch of a merge commit. 1850 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--before", "b1"]); 1851 insta::assert_snapshot!(stdout, @""); 1852 insta::assert_snapshot!(stderr, @r###" 1853 Rebased 1 commits onto destination 1854 Rebased 5 descendant commits 1855 Working copy now at: xznxytkn 488ebb95 f | f 1856 Parent commit : rlvkpnrz 2443ea76 a | a 1857 Added 0 files, modified 0 files, removed 6 files 1858 "###); 1859 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1860 ◉ e nkmrtpmo 9d5fa6a2 1861 │ ◉ d lylxulpl ca323694 1862 ├─╯ 1863 ◉ c kmkuslsw 07426e1a 1864 ├─╮ 1865 │ ◉ b4 znkkpsqq a52a83a4 1866 │ ◉ b3 vruxwmqv 523e6a8b 1867 ◉ │ b2 royxmykx 55376058 1868 ◉ │ b1 zsuskuln cd5b1d04 1869 @ │ f xznxytkn 488ebb95 1870 ├─╯ 1871 ◉ a rlvkpnrz 2443ea76 1872 ◉ zzzzzzzz 00000000 1873 "###); 1874 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1875 1876 // Rebase a commit before a merge commit. "c" has two parents "b2" and "b4", so 1877 // the rebased commit "f" will have the two commits "b2" and "b4" as its 1878 // parents. 1879 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "f", "--before", "c"]); 1880 insta::assert_snapshot!(stdout, @""); 1881 insta::assert_snapshot!(stderr, @r###" 1882 Rebased 1 commits onto destination 1883 Rebased 3 descendant commits 1884 Working copy now at: xznxytkn aae1bc10 f | f 1885 Parent commit : royxmykx 2b8e1148 b2 | b2 1886 Parent commit : znkkpsqq a52a83a4 b4 | b4 1887 Added 0 files, modified 0 files, removed 2 files 1888 "###); 1889 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1890 ◉ e nkmrtpmo 0ea67093 1891 │ ◉ d lylxulpl c079568d 1892 ├─╯ 1893 ◉ c kmkuslsw 6371742b 1894 @ f xznxytkn aae1bc10 1895 ├─╮ 1896 │ ◉ b4 znkkpsqq a52a83a4 1897 │ ◉ b3 vruxwmqv 523e6a8b 1898 ◉ │ b2 royxmykx 2b8e1148 1899 ◉ │ b1 zsuskuln 072d5ae1 1900 ├─╯ 1901 ◉ a rlvkpnrz 2443ea76 1902 ◉ zzzzzzzz 00000000 1903 "###); 1904 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1905 1906 // Rebase a commit before multiple commits. 1907 let (stdout, stderr) = test_env.jj_cmd_ok( 1908 &repo_path, 1909 &["rebase", "-r", "b1", "--before", "d", "--before", "e"], 1910 ); 1911 insta::assert_snapshot!(stdout, @""); 1912 insta::assert_snapshot!(stderr, @r###" 1913 Rebased 1 commits onto destination 1914 Rebased 5 descendant commits 1915 Working copy now at: xznxytkn 8268ec4d f | f 1916 Parent commit : nkmrtpmo fd26fbd4 e | e 1917 "###); 1918 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1919 @ f xznxytkn 8268ec4d 1920 ◉ e nkmrtpmo fd26fbd4 1921 │ ◉ d lylxulpl 21da64b4 1922 ├─╯ 1923 ◉ b1 zsuskuln 83e9b8ac 1924 ◉ c kmkuslsw a89354fc 1925 ├─╮ 1926 │ ◉ b4 znkkpsqq a52a83a4 1927 │ ◉ b3 vruxwmqv 523e6a8b 1928 ◉ │ b2 royxmykx b7f03180 1929 ├─╯ 1930 ◉ a rlvkpnrz 2443ea76 1931 ◉ zzzzzzzz 00000000 1932 "###); 1933 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1934 1935 // Rebase a commit before two commits in separate branches to create a merge 1936 // commit. 1937 let (stdout, stderr) = test_env.jj_cmd_ok( 1938 &repo_path, 1939 &["rebase", "-r", "f", "--before", "b2", "--before", "b4"], 1940 ); 1941 insta::assert_snapshot!(stdout, @""); 1942 insta::assert_snapshot!(stderr, @r###" 1943 Rebased 1 commits onto destination 1944 Rebased 5 descendant commits 1945 Working copy now at: xznxytkn 7ba8014f f | f 1946 Parent commit : zsuskuln 072d5ae1 b1 | b1 1947 Parent commit : vruxwmqv 523e6a8b b3 | b3 1948 Added 0 files, modified 0 files, removed 4 files 1949 "###); 1950 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1951 ◉ e nkmrtpmo 9436134a 1952 │ ◉ d lylxulpl 534be1ee 1953 ├─╯ 1954 ◉ c kmkuslsw bc3ed9f8 1955 ├─╮ 1956 │ ◉ b4 znkkpsqq 3e59611b 1957 ◉ │ b2 royxmykx 148d7e50 1958 ├─╯ 1959 @ f xznxytkn 7ba8014f 1960 ├─╮ 1961 │ ◉ b3 vruxwmqv 523e6a8b 1962 ◉ │ b1 zsuskuln 072d5ae1 1963 ├─╯ 1964 ◉ a rlvkpnrz 2443ea76 1965 ◉ zzzzzzzz 00000000 1966 "###); 1967 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 1968 1969 // Rebase two unrelated commits "b2" and "b4" before a single commit "a". This 1970 // creates a merge commit "a" with the two parents "b2" and "b4". 1971 let (stdout, stderr) = test_env.jj_cmd_ok( 1972 &repo_path, 1973 &["rebase", "-r", "b2", "-r", "b4", "--before", "a"], 1974 ); 1975 insta::assert_snapshot!(stdout, @""); 1976 insta::assert_snapshot!(stderr, @r###" 1977 Rebased 2 commits onto destination 1978 Rebased 7 descendant commits 1979 Working copy now at: xznxytkn fabd8dd7 f | f 1980 Parent commit : nkmrtpmo b5933877 e | e 1981 "###); 1982 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 1983 @ f xznxytkn fabd8dd7 1984 ◉ e nkmrtpmo b5933877 1985 │ ◉ d lylxulpl 6b91dd66 1986 ├─╯ 1987 ◉ c kmkuslsw d873acf7 1988 ├─╮ 1989 │ ◉ b3 vruxwmqv 1fd332d8 1990 ◉ │ b1 zsuskuln 8e39430f 1991 ├─╯ 1992 ◉ a rlvkpnrz 414580f5 1993 ├─╮ 1994 │ ◉ b4 znkkpsqq ae3d5bdb 1995 ◉ │ b2 royxmykx a225236e 1996 ├─╯ 1997 ◉ zzzzzzzz 00000000 1998 "###); 1999 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2000 2001 // Rebase a subgraph with a merge commit and two parents. 2002 let (stdout, stderr) = test_env.jj_cmd_ok( 2003 &repo_path, 2004 &["rebase", "-r", "b2", "-r", "b4", "-r", "c", "--before", "e"], 2005 ); 2006 insta::assert_snapshot!(stdout, @""); 2007 insta::assert_snapshot!(stderr, @r###" 2008 Rebased 3 commits onto destination 2009 Rebased 3 descendant commits 2010 Working copy now at: xznxytkn cbe2be58 f | f 2011 Parent commit : nkmrtpmo e31053d1 e | e 2012 "###); 2013 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2014 @ f xznxytkn cbe2be58 2015 ◉ e nkmrtpmo e31053d1 2016 ◉ c kmkuslsw 23155860 2017 ├─╮ 2018 │ ◉ b4 znkkpsqq e50520ad 2019 │ ├─╮ 2020 ◉ │ │ b2 royxmykx 54f03b06 2021 ╰─┬─╮ 2022 ◉ │ │ d lylxulpl 0c74206e 2023 ╰─┬─╮ 2024 │ ◉ b3 vruxwmqv 523e6a8b 2025 ◉ │ b1 zsuskuln 072d5ae1 2026 ├─╯ 2027 ◉ a rlvkpnrz 2443ea76 2028 ◉ zzzzzzzz 00000000 2029 "###); 2030 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2031 2032 // Rebase a subgraph with disconnected commits. Since "b1" is an ancestor of 2033 // "e", "b1" should be a parent of "e" after the rebase. 2034 let (stdout, stderr) = test_env.jj_cmd_ok( 2035 &repo_path, 2036 &["rebase", "-r", "b1", "-r", "e", "--before", "a"], 2037 ); 2038 insta::assert_snapshot!(stdout, @""); 2039 insta::assert_snapshot!(stderr, @r###" 2040 Rebased 2 commits onto destination 2041 Rebased 7 descendant commits 2042 Working copy now at: xznxytkn 1c48b514 f | f 2043 Parent commit : kmkuslsw c0fd979a c | c 2044 "###); 2045 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2046 @ f xznxytkn 1c48b514 2047 │ ◉ d lylxulpl 4dbbc808 2048 ├─╯ 2049 ◉ c kmkuslsw c0fd979a 2050 ├─╮ 2051 │ ◉ b4 znkkpsqq 4d5c61f4 2052 │ ◉ b3 vruxwmqv d5699c24 2053 ◉ │ b2 royxmykx e23ab998 2054 ├─╯ 2055 ◉ a rlvkpnrz 076f0094 2056 ◉ e nkmrtpmo 20d1f131 2057 ◉ b1 zsuskuln 11db739a 2058 ◉ zzzzzzzz 00000000 2059 "###); 2060 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2061 2062 // Should error if a loop will be created. 2063 let stderr = test_env.jj_cmd_failure( 2064 &repo_path, 2065 &["rebase", "-r", "e", "--before", "b2", "--before", "c"], 2066 ); 2067 insta::assert_snapshot!(stderr, @r###" 2068 Error: Refusing to create a loop: commit 2b8e1148290f would be both an ancestor and a descendant of the rebased commits 2069 "###); 2070} 2071 2072#[test] 2073fn test_rebase_revisions_after_before() { 2074 let test_env = TestEnvironment::default(); 2075 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 2076 let repo_path = test_env.env_root().join("repo"); 2077 2078 create_commit(&test_env, &repo_path, "a", &[]); 2079 create_commit(&test_env, &repo_path, "b1", &["a"]); 2080 create_commit(&test_env, &repo_path, "b2", &["a"]); 2081 create_commit(&test_env, &repo_path, "c", &["b1", "b2"]); 2082 create_commit(&test_env, &repo_path, "d", &["c"]); 2083 create_commit(&test_env, &repo_path, "e", &["c"]); 2084 create_commit(&test_env, &repo_path, "f", &["e"]); 2085 // Test the setup 2086 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2087 @ f lylxulpl 88f778c5 2088 ◉ e kmkuslsw 48dd9e3f 2089 │ ◉ d znkkpsqq 92438fc9 2090 ├─╯ 2091 ◉ c vruxwmqv c41e416e 2092 ├─╮ 2093 │ ◉ b2 royxmykx 903ab0d6 2094 ◉ │ b1 zsuskuln 072d5ae1 2095 ├─╯ 2096 ◉ a rlvkpnrz 2443ea76 2097 ◉ zzzzzzzz 00000000 2098 "###); 2099 let setup_opid = test_env.current_operation_id(&repo_path); 2100 2101 // Rebase a commit after another commit and before that commit's child to 2102 // insert directly between the two commits. 2103 let (stdout, stderr) = test_env.jj_cmd_ok( 2104 &repo_path, 2105 &["rebase", "-r", "d", "--after", "e", "--before", "f"], 2106 ); 2107 insta::assert_snapshot!(stdout, @""); 2108 insta::assert_snapshot!(stderr, @r###" 2109 Rebased 1 commits onto destination 2110 Rebased 1 descendant commits 2111 Working copy now at: lylxulpl fe3d8c30 f | f 2112 Parent commit : znkkpsqq cca70ee1 d | d 2113 Added 1 files, modified 0 files, removed 0 files 2114 "###); 2115 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2116 @ f lylxulpl fe3d8c30 2117 ◉ d znkkpsqq cca70ee1 2118 ◉ e kmkuslsw 48dd9e3f 2119 ◉ c vruxwmqv c41e416e 2120 ├─╮ 2121 │ ◉ b2 royxmykx 903ab0d6 2122 ◉ │ b1 zsuskuln 072d5ae1 2123 ├─╯ 2124 ◉ a rlvkpnrz 2443ea76 2125 ◉ zzzzzzzz 00000000 2126 "###); 2127 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2128 2129 // Rebase a commit after another commit and before that commit's descendant to 2130 // create a new merge commit. 2131 let (stdout, stderr) = test_env.jj_cmd_ok( 2132 &repo_path, 2133 &["rebase", "-r", "d", "--after", "a", "--before", "f"], 2134 ); 2135 insta::assert_snapshot!(stdout, @""); 2136 insta::assert_snapshot!(stderr, @r###" 2137 Rebased 1 commits onto destination 2138 Rebased 1 descendant commits 2139 Working copy now at: lylxulpl 22f0323c f | f 2140 Parent commit : kmkuslsw 48dd9e3f e | e 2141 Parent commit : znkkpsqq 61388bb6 d | d 2142 Added 1 files, modified 0 files, removed 0 files 2143 "###); 2144 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2145 @ f lylxulpl 22f0323c 2146 ├─╮ 2147 │ ◉ d znkkpsqq 61388bb6 2148 ◉ │ e kmkuslsw 48dd9e3f 2149 ◉ │ c vruxwmqv c41e416e 2150 ├───╮ 2151 │ │ ◉ b2 royxmykx 903ab0d6 2152 │ ├─╯ 2153 ◉ │ b1 zsuskuln 072d5ae1 2154 ├─╯ 2155 ◉ a rlvkpnrz 2443ea76 2156 ◉ zzzzzzzz 00000000 2157 "###); 2158 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2159 2160 // "c" has parents "b1" and "b2", so when it is rebased, its children "d" and 2161 // "e" should have "b1" and "b2" as parents as well. "c" is then inserted in 2162 // between "d" and "e", making "e" a merge commit with 3 parents "b1", "b2", 2163 // and "c". 2164 let (stdout, stderr) = test_env.jj_cmd_ok( 2165 &repo_path, 2166 &["rebase", "-r", "c", "--after", "d", "--before", "e"], 2167 ); 2168 insta::assert_snapshot!(stdout, @""); 2169 insta::assert_snapshot!(stderr, @r###" 2170 Rebased 1 commits onto destination 2171 Rebased 3 descendant commits 2172 Working copy now at: lylxulpl e37682c5 f | f 2173 Parent commit : kmkuslsw 9bbc9e53 e | e 2174 Added 1 files, modified 0 files, removed 0 files 2175 "###); 2176 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2177 @ f lylxulpl e37682c5 2178 ◉ e kmkuslsw 9bbc9e53 2179 ├─┬─╮ 2180 │ │ ◉ c vruxwmqv e11c7c95 2181 │ │ ◉ d znkkpsqq 37869bd5 2182 ╭─┬─╯ 2183 │ ◉ b2 royxmykx 903ab0d6 2184 ◉ │ b1 zsuskuln 072d5ae1 2185 ├─╯ 2186 ◉ a rlvkpnrz 2443ea76 2187 ◉ zzzzzzzz 00000000 2188 "###); 2189 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2190 2191 // Rebase multiple commits and preserve their ancestry. Apart from the heads of 2192 // the target commits ("d" and "e"), "f" also has commits "b1" and "b2" as 2193 // parents since its parents "d" and "e" were in the target set and were 2194 // replaced by their closest ancestors outside the target set. 2195 let (stdout, stderr) = test_env.jj_cmd_ok( 2196 &repo_path, 2197 &[ 2198 "rebase", "-r", "c", "-r", "d", "-r", "e", "--after", "a", "--before", "f", 2199 ], 2200 ); 2201 insta::assert_snapshot!(stdout, @""); 2202 insta::assert_snapshot!(stderr, @r###" 2203 Rebased 3 commits onto destination 2204 Rebased 1 descendant commits 2205 Working copy now at: lylxulpl 868f6c61 f | f 2206 Parent commit : zsuskuln 072d5ae1 b1 | b1 2207 Parent commit : royxmykx 903ab0d6 b2 | b2 2208 Parent commit : znkkpsqq ae6181e6 d | d 2209 Parent commit : kmkuslsw a55a6779 e | e 2210 Added 1 files, modified 0 files, removed 0 files 2211 "###); 2212 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2213 @ f lylxulpl 868f6c61 2214 ├─┬─┬─╮ 2215 │ │ │ ◉ e kmkuslsw a55a6779 2216 │ │ ◉ │ d znkkpsqq ae6181e6 2217 │ │ ├─╯ 2218 │ │ ◉ c vruxwmqv 22540859 2219 │ ◉ │ b2 royxmykx 903ab0d6 2220 │ ├─╯ 2221 ◉ │ b1 zsuskuln 072d5ae1 2222 ├─╯ 2223 ◉ a rlvkpnrz 2443ea76 2224 ◉ zzzzzzzz 00000000 2225 "###); 2226 test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); 2227 2228 // Should error if a loop will be created. 2229 let stderr = test_env.jj_cmd_failure( 2230 &repo_path, 2231 &["rebase", "-r", "e", "--after", "c", "--before", "a"], 2232 ); 2233 insta::assert_snapshot!(stderr, @r###" 2234 Error: Refusing to create a loop: commit c41e416ee4cf would be both an ancestor and a descendant of the rebased commits 2235 "###); 2236} 2237 2238#[test] 2239fn test_rebase_skip_empty() { 2240 let test_env = TestEnvironment::default(); 2241 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 2242 let repo_path = test_env.env_root().join("repo"); 2243 2244 create_commit(&test_env, &repo_path, "a", &[]); 2245 create_commit(&test_env, &repo_path, "b", &["a"]); 2246 test_env.jj_cmd_ok(&repo_path, &["new", "a", "-m", "will become empty"]); 2247 test_env.jj_cmd_ok(&repo_path, &["restore", "--from=b"]); 2248 test_env.jj_cmd_ok(&repo_path, &["new", "-m", "already empty"]); 2249 test_env.jj_cmd_ok(&repo_path, &["new", "-m", "also already empty"]); 2250 2251 // Test the setup 2252 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["log", "-T", "description"]), @r###" 2253 @ also already empty 2254 ◉ already empty 2255 ◉ will become empty 2256 │ ◉ b 2257 ├─╯ 2258 ◉ a 22592260 "###); 2261 2262 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-d=b", "--skip-empty"]); 2263 insta::assert_snapshot!(stdout, @""); 2264 insta::assert_snapshot!(stderr, @r###" 2265 Rebased 3 commits 2266 Working copy now at: yostqsxw 6b74c840 (empty) also already empty 2267 Parent commit : vruxwmqv 48a31526 (empty) already empty 2268 "###); 2269 2270 // The parent commit became empty and was dropped, but the already empty commits 2271 // were kept 2272 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["log", "-T", "description"]), @r###" 2273 @ also already empty 2274 ◉ already empty 2275 ◉ b 2276 ◉ a 22772278 "###); 2279} 2280 2281#[test] 2282fn test_rebase_skip_if_on_destination() { 2283 let test_env = TestEnvironment::default(); 2284 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 2285 let repo_path = test_env.env_root().join("repo"); 2286 2287 create_commit(&test_env, &repo_path, "a", &[]); 2288 create_commit(&test_env, &repo_path, "b1", &["a"]); 2289 create_commit(&test_env, &repo_path, "b2", &["a"]); 2290 create_commit(&test_env, &repo_path, "c", &["b1", "b2"]); 2291 create_commit(&test_env, &repo_path, "d", &["c"]); 2292 create_commit(&test_env, &repo_path, "e", &["c"]); 2293 create_commit(&test_env, &repo_path, "f", &["e"]); 2294 // Test the setup 2295 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2296 @ f lylxulpl 88f778c5 2297 ◉ e kmkuslsw 48dd9e3f 2298 │ ◉ d znkkpsqq 92438fc9 2299 ├─╯ 2300 ◉ c vruxwmqv c41e416e 2301 ├─╮ 2302 │ ◉ b2 royxmykx 903ab0d6 2303 ◉ │ b1 zsuskuln 072d5ae1 2304 ├─╯ 2305 ◉ a rlvkpnrz 2443ea76 2306 ◉ zzzzzzzz 00000000 2307 "###); 2308 2309 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "d", "-d", "a"]); 2310 insta::assert_snapshot!(stdout, @""); 2311 // Skip rebase with -b 2312 insta::assert_snapshot!(stderr, @r###" 2313 Skipped rebase of 2 commits that were already in place 2314 "###); 2315 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2316 @ f lylxulpl 88f778c5 2317 ◉ e kmkuslsw 48dd9e3f 2318 │ ◉ d znkkpsqq 92438fc9 2319 ├─╯ 2320 ◉ c vruxwmqv c41e416e 2321 ├─╮ 2322 │ ◉ b2 royxmykx 903ab0d6 2323 ◉ │ b1 zsuskuln 072d5ae1 2324 ├─╯ 2325 ◉ a rlvkpnrz 2443ea76 2326 ◉ zzzzzzzz 00000000 2327 "###); 2328 2329 let (stdout, stderr) = 2330 test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "c", "-d", "b1", "-d", "b2"]); 2331 insta::assert_snapshot!(stdout, @""); 2332 // Skip rebase with -s 2333 insta::assert_snapshot!(stderr, @r###" 2334 Skipped rebase of 1 commits that were already in place 2335 "###); 2336 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2337 @ f lylxulpl 88f778c5 2338 ◉ e kmkuslsw 48dd9e3f 2339 │ ◉ d znkkpsqq 92438fc9 2340 ├─╯ 2341 ◉ c vruxwmqv c41e416e 2342 ├─╮ 2343 │ ◉ b2 royxmykx 903ab0d6 2344 ◉ │ b1 zsuskuln 072d5ae1 2345 ├─╯ 2346 ◉ a rlvkpnrz 2443ea76 2347 ◉ zzzzzzzz 00000000 2348 "###); 2349 2350 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "d", "-d", "c"]); 2351 insta::assert_snapshot!(stdout, @""); 2352 // Skip rebase with -r since commit has no children 2353 insta::assert_snapshot!(stderr, @r###" 2354 Skipped rebase of 1 commits that were already in place 2355 Nothing changed. 2356 "###); 2357 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2358 @ f lylxulpl 88f778c5 2359 ◉ e kmkuslsw 48dd9e3f 2360 │ ◉ d znkkpsqq 92438fc9 2361 ├─╯ 2362 ◉ c vruxwmqv c41e416e 2363 ├─╮ 2364 │ ◉ b2 royxmykx 903ab0d6 2365 ◉ │ b1 zsuskuln 072d5ae1 2366 ├─╯ 2367 ◉ a rlvkpnrz 2443ea76 2368 ◉ zzzzzzzz 00000000 2369 "###); 2370 2371 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "e", "-d", "c"]); 2372 insta::assert_snapshot!(stdout, @""); 2373 // Skip rebase of commit, but rebases children onto destination with -r 2374 insta::assert_snapshot!(stderr, @r###" 2375 Skipped rebase of 1 commits that were already in place 2376 Rebased 1 descendant commits 2377 Working copy now at: lylxulpl 77cb229f f | f 2378 Parent commit : vruxwmqv c41e416e c | c 2379 Added 0 files, modified 0 files, removed 1 files 2380 "###); 2381 insta::assert_snapshot!(get_long_log_output(&test_env, &repo_path), @r###" 2382 @ f lylxulpl 77cb229f 2383 │ ◉ e kmkuslsw 48dd9e3f 2384 ├─╯ 2385 │ ◉ d znkkpsqq 92438fc9 2386 ├─╯ 2387 ◉ c vruxwmqv c41e416e 2388 ├─╮ 2389 │ ◉ b2 royxmykx 903ab0d6 2390 ◉ │ b1 zsuskuln 072d5ae1 2391 ├─╯ 2392 ◉ a rlvkpnrz 2443ea76 2393 ◉ zzzzzzzz 00000000 2394 "###); 2395} 2396 2397fn get_long_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { 2398 let template = r#"description.first_line() ++ " " ++ change_id.shortest(8) ++ " " ++ commit_id.shortest(8)"#; 2399 test_env.jj_cmd_success(repo_path, &["log", "-T", template]) 2400}