// Copyright 2022 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::path::Path; use crate::common::TestEnvironment; fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) { if parents.is_empty() { test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]); } else { let mut args = vec!["new", "-m", name]; args.extend(parents); test_env.jj_cmd_ok(repo_path, &args); } std::fs::write(repo_path.join(name), format!("{name}\n")).unwrap(); test_env.jj_cmd_ok(repo_path, &["bookmark", "create", name]);} #[test]fn test_rebase_invalid() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); // Missing destination let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase"]); insta::assert_snapshot!(stderr, @r###" error: the following required arguments were not provided: <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> Usage: jj rebase <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -r and -s let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-r", "a", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" error: the argument '--revisions <REVISIONS>' cannot be used with '--source <SOURCE>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -b and -s let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-b", "a", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" error: the argument '--branch <BRANCH>' cannot be used with '--source <SOURCE>' Usage: jj rebase --branch <BRANCH> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -d and --after let stderr = test_env.jj_cmd_cli_error( &repo_path, &["rebase", "-r", "a", "-d", "b", "--after", "b"], ); insta::assert_snapshot!(stderr, @r###" error: the argument '--destination <DESTINATION>' cannot be used with '--insert-after <INSERT_AFTER>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -d and --before let stderr = test_env.jj_cmd_cli_error( &repo_path, &["rebase", "-r", "a", "-d", "b", "--before", "b"], ); insta::assert_snapshot!(stderr, @r###" error: the argument '--destination <DESTINATION>' cannot be used with '--insert-before <INSERT_BEFORE>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Rebase onto self with -r let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "a"]); insta::assert_snapshot!(stderr, @r###" Error: Cannot rebase 2443ea76b0b1 onto itself "###); // Rebase root with -r let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "root()", "-d", "a"]); insta::assert_snapshot!(stderr, @r###" Error: The root commit 000000000000 is immutable "###); // Rebase onto descendant with -s let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" Error: Cannot rebase 2443ea76b0b1 onto descendant 1394f625cbbd "###);} #[test]fn test_rebase_bookmark() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["b"]); create_commit(&test_env, &repo_path, "e", &["a"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a │ ○ d: b │ │ ○ c: b │ ├─╯ │ ○ b: a ├─╯ ○ a ◆ "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "c", "-d", "e"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @"Rebased 3 commits onto destination"); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ○ d: b │ ○ c: b ├─╯ ○ b: e @ e: a ○ a ◆ "###); // Test rebasing multiple bookmarks at once test_env.jj_cmd_ok(&repo_path, &["undo"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=e", "-b=d", "-d=b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Skipped rebase of 1 commits that were already in place Rebased 1 commits onto destination Working copy now at: znkkpsqq 9ca2a154 e | e Parent commit : zsuskuln 1394f625 b | b Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b │ ○ d: b ├─╯ │ ○ c: b ├─╯ ○ b: a ○ a ◆ "###); // Same test but with more than one revision per argument test_env.jj_cmd_ok(&repo_path, &["undo"]); let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b=e|d", "-d=b"]); insta::assert_snapshot!(stderr, @r###" Error: Revset "e|d" resolved to more than one revision Hint: The revset "e|d" resolved to these revisions: znkkpsqq e52756c8 e | e vruxwmqv 514fa6b2 d | d Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:e|d'). "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=all:e|d", "-d=b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Skipped rebase of 1 commits that were already in place Rebased 1 commits onto destination Working copy now at: znkkpsqq 817e3fb0 e | e Parent commit : zsuskuln 1394f625 b | b Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b │ ○ d: b ├─╯ │ ○ c: b ├─╯ ○ b: a ○ a ◆ "###);} #[test]fn test_rebase_bookmark_with_merge() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &[]); create_commit(&test_env, &repo_path, "d", &["c"]); create_commit(&test_env, &repo_path, "e", &["a", "d"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c │ │ ○ b: a ├───╯ ○ │ a ├─╯ ◆ "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "d", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Rebased 3 commits onto destination Working copy now at: znkkpsqq 5f8a3db2 e | e Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : vruxwmqv 1677f795 d | d Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c: b │ ○ b: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Rebased 3 commits onto destination Working copy now at: znkkpsqq a331ac11 e | e Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : vruxwmqv 3d0f3644 d | d Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c: b │ ○ b: a ├─╯ ○ a ◆ "###);} #[test]fn test_rebase_single_revision() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["a"]); create_commit(&test_env, &repo_path, "d", &["b", "c"]); create_commit(&test_env, &repo_path, "e", &["d"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: d ○ d: b c ├─╮ │ ○ c: a ○ │ b: a ├─╯ ○ a ◆ "###); // Descendants of the rebased commit "c" should be rebased onto parents. First // we test with a non-merge commit. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 2 descendant commits Working copy now at: znkkpsqq 2668ffbe e | e Parent commit : vruxwmqv 7b370c85 d | d Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: d ○ d: b a ├─╮ │ │ ○ c: b ├───╯ ○ │ b: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Now, let's try moving the merge commit. After, both parents of "d" ("b" and // "c") should become parents of "e". let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "d", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 1 descendant commits Working copy now at: znkkpsqq ed210c15 e | e Parent commit : zsuskuln 1394f625 b | b Parent commit : royxmykx c0cb3a0b c | c Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b c ├─╮ │ ○ c: a ○ │ b: a ├─╯ │ ○ d: a ├─╯ ○ a ◆ "###);} #[test]fn test_rebase_single_revision_merge_parent() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &[]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["a", "c"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ d: a c ├─╮ │ ○ c: b │ ○ b ○ │ a ├─╯ ◆ "###); // Descendants of the rebased commit should be rebased onto parents, and if // the descendant is a merge commit, it shouldn't forget its other parents. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 1 descendant commits Working copy now at: vruxwmqv a37531e8 d | d Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : zsuskuln d370aee1 b | b Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ d: a b ├─╮ │ ○ b │ │ ○ c: a ├───╯ ○ │ a ├─╯ ◆ "###);} #[test]fn test_rebase_multiple_revisions() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["a"]); create_commit(&test_env, &repo_path, "e", &["d"]); create_commit(&test_env, &repo_path, "f", &["c", "e"]); create_commit(&test_env, &repo_path, "g", &["f"]); create_commit(&test_env, &repo_path, "h", &["g"]); create_commit(&test_env, &repo_path, "i", &["f"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: c e ├─╮ │ ○ e: d │ ○ d: a ○ │ c: b ○ │ b: a ├─╯ ○ a ◆ "###); // Test with two non-related non-merge commits. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-r", "e", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 2 commits onto destination Rebased 4 descendant commits Working copy now at: xznxytkn 016685dc i | i Parent commit : kmkuslsw e04d3932 f | f Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: b d ├─╮ │ ○ d: a ○ │ b: a ├─╯ │ ○ e: a ├─╯ │ ○ c: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Test with two related non-merge commits. Since "b" is a parent of "c", when // rebasing commits "b" and "c", their ancestry relationship should be // preserved. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-r", "c", "-d", "e"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 2 commits onto destination Rebased 4 descendant commits Working copy now at: xznxytkn 94538385 i | i Parent commit : kmkuslsw dae8d293 f | f Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: a e ├─╮ │ │ ○ c: b │ │ ○ b: e │ ├─╯ │ ○ e: d │ ○ d: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Test with a subgraph containing a merge commit. Since the merge commit "f" // was extracted, its descendants which are not part of the subgraph will // inherit its descendants which are not in the subtree ("c" and "d"). // "f" will retain its parent "c" since "c" is outside the target set, and not // a descendant of any new children. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "e::g", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 3 commits onto destination Rebased 2 descendant commits Working copy now at: xznxytkn 1868ded4 i | i Parent commit : royxmykx 7e4fbf4f c | c Parent commit : vruxwmqv 4cc44fbf d | d Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: c d ├─╮Lines 1–500 of 2795. Load more
// Copyright 2022 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::path::Path; use crate::common::TestEnvironment; fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) { if parents.is_empty() { test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]); } else { let mut args = vec!["new", "-m", name]; args.extend(parents); test_env.jj_cmd_ok(repo_path, &args); } std::fs::write(repo_path.join(name), format!("{name}\n")).unwrap(); test_env.jj_cmd_ok(repo_path, &["bookmark", "create", name]); } #[test] fn test_rebase_invalid() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); // Missing destination let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase"]); insta::assert_snapshot!(stderr, @r###" error: the following required arguments were not provided: <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> Usage: jj rebase <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -r and -s let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-r", "a", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" error: the argument '--revisions <REVISIONS>' cannot be used with '--source <SOURCE>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -b and -s let stderr = test_env.jj_cmd_cli_error(&repo_path, &["rebase", "-b", "a", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" error: the argument '--branch <BRANCH>' cannot be used with '--source <SOURCE>' Usage: jj rebase --branch <BRANCH> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -d and --after let stderr = test_env.jj_cmd_cli_error( &repo_path, &["rebase", "-r", "a", "-d", "b", "--after", "b"], ); insta::assert_snapshot!(stderr, @r###" error: the argument '--destination <DESTINATION>' cannot be used with '--insert-after <INSERT_AFTER>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Both -d and --before let stderr = test_env.jj_cmd_cli_error( &repo_path, &["rebase", "-r", "a", "-d", "b", "--before", "b"], ); insta::assert_snapshot!(stderr, @r###" error: the argument '--destination <DESTINATION>' cannot be used with '--insert-before <INSERT_BEFORE>' Usage: jj rebase --revisions <REVISIONS> <--destination <DESTINATION>|--insert-after <INSERT_AFTER>|--insert-before <INSERT_BEFORE>> For more information, try '--help'. "###); // Rebase onto self with -r let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "a"]); insta::assert_snapshot!(stderr, @r###" Error: Cannot rebase 2443ea76b0b1 onto itself "###); // Rebase root with -r let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "root()", "-d", "a"]); insta::assert_snapshot!(stderr, @r###" Error: The root commit 000000000000 is immutable "###); // Rebase onto descendant with -s let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-s", "a", "-d", "b"]); insta::assert_snapshot!(stderr, @r###" Error: Cannot rebase 2443ea76b0b1 onto descendant 1394f625cbbd "###); } #[test] fn test_rebase_bookmark() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["b"]); create_commit(&test_env, &repo_path, "e", &["a"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a │ ○ d: b │ │ ○ c: b │ ├─╯ │ ○ b: a ├─╯ ○ a ◆ "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "c", "-d", "e"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @"Rebased 3 commits onto destination"); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ○ d: b │ ○ c: b ├─╯ ○ b: e @ e: a ○ a ◆ "###); // Test rebasing multiple bookmarks at once test_env.jj_cmd_ok(&repo_path, &["undo"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=e", "-b=d", "-d=b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Skipped rebase of 1 commits that were already in place Rebased 1 commits onto destination Working copy now at: znkkpsqq 9ca2a154 e | e Parent commit : zsuskuln 1394f625 b | b Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b │ ○ d: b ├─╯ │ ○ c: b ├─╯ ○ b: a ○ a ◆ "###); // Same test but with more than one revision per argument test_env.jj_cmd_ok(&repo_path, &["undo"]); let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b=e|d", "-d=b"]); insta::assert_snapshot!(stderr, @r###" Error: Revset "e|d" resolved to more than one revision Hint: The revset "e|d" resolved to these revisions: znkkpsqq e52756c8 e | e vruxwmqv 514fa6b2 d | d Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:e|d'). "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b=all:e|d", "-d=b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Skipped rebase of 1 commits that were already in place Rebased 1 commits onto destination Working copy now at: znkkpsqq 817e3fb0 e | e Parent commit : zsuskuln 1394f625 b | b Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b │ ○ d: b ├─╯ │ ○ c: b ├─╯ ○ b: a ○ a ◆ "###); } #[test] fn test_rebase_bookmark_with_merge() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &[]); create_commit(&test_env, &repo_path, "d", &["c"]); create_commit(&test_env, &repo_path, "e", &["a", "d"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c │ │ ○ b: a ├───╯ ○ │ a ├─╯ ◆ "###); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-b", "d", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Rebased 3 commits onto destination Working copy now at: znkkpsqq 5f8a3db2 e | e Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : vruxwmqv 1677f795 d | d Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c: b │ ○ b: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" Rebased 3 commits onto destination Working copy now at: znkkpsqq a331ac11 e | e Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : vruxwmqv 3d0f3644 d | d Added 1 files, modified 0 files, removed 0 files "#); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: a d ├─╮ │ ○ d: c │ ○ c: b │ ○ b: a ├─╯ ○ a ◆ "###); } #[test] fn test_rebase_single_revision() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["a"]); create_commit(&test_env, &repo_path, "d", &["b", "c"]); create_commit(&test_env, &repo_path, "e", &["d"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: d ○ d: b c ├─╮ │ ○ c: a ○ │ b: a ├─╯ ○ a ◆ "###); // Descendants of the rebased commit "c" should be rebased onto parents. First // we test with a non-merge commit. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "b"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 2 descendant commits Working copy now at: znkkpsqq 2668ffbe e | e Parent commit : vruxwmqv 7b370c85 d | d Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: d ○ d: b a ├─╮ │ │ ○ c: b ├───╯ ○ │ b: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Now, let's try moving the merge commit. After, both parents of "d" ("b" and // "c") should become parents of "e". let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "d", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 1 descendant commits Working copy now at: znkkpsqq ed210c15 e | e Parent commit : zsuskuln 1394f625 b | b Parent commit : royxmykx c0cb3a0b c | c Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ e: b c ├─╮ │ ○ c: a ○ │ b: a ├─╯ │ ○ d: a ├─╯ ○ a ◆ "###); } #[test] fn test_rebase_single_revision_merge_parent() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &[]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["a", "c"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ d: a c ├─╮ │ ○ c: b │ ○ b ○ │ a ├─╯ ◆ "###); // Descendants of the rebased commit should be rebased onto parents, and if // the descendant is a merge commit, it shouldn't forget its other parents. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 1 commits onto destination Rebased 1 descendant commits Working copy now at: vruxwmqv a37531e8 d | d Parent commit : rlvkpnrz 2443ea76 a | a Parent commit : zsuskuln d370aee1 b | b Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ d: a b ├─╮ │ ○ b │ │ ○ c: a ├───╯ ○ │ a ├─╯ ◆ "###); } #[test] fn test_rebase_multiple_revisions() { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); create_commit(&test_env, &repo_path, "a", &[]); create_commit(&test_env, &repo_path, "b", &["a"]); create_commit(&test_env, &repo_path, "c", &["b"]); create_commit(&test_env, &repo_path, "d", &["a"]); create_commit(&test_env, &repo_path, "e", &["d"]); create_commit(&test_env, &repo_path, "f", &["c", "e"]); create_commit(&test_env, &repo_path, "g", &["f"]); create_commit(&test_env, &repo_path, "h", &["g"]); create_commit(&test_env, &repo_path, "i", &["f"]); // Test the setup insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: c e ├─╮ │ ○ e: d │ ○ d: a ○ │ c: b ○ │ b: a ├─╯ ○ a ◆ "###); // Test with two non-related non-merge commits. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-r", "e", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 2 commits onto destination Rebased 4 descendant commits Working copy now at: xznxytkn 016685dc i | i Parent commit : kmkuslsw e04d3932 f | f Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: b d ├─╮ │ ○ d: a ○ │ b: a ├─╯ │ ○ e: a ├─╯ │ ○ c: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Test with two related non-merge commits. Since "b" is a parent of "c", when // rebasing commits "b" and "c", their ancestry relationship should be // preserved. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-r", "c", "-d", "e"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 2 commits onto destination Rebased 4 descendant commits Working copy now at: xznxytkn 94538385 i | i Parent commit : kmkuslsw dae8d293 f | f Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: f │ ○ h: g │ ○ g: f ├─╯ ○ f: a e ├─╮ │ │ ○ c: b │ │ ○ b: e │ ├─╯ │ ○ e: d │ ○ d: a ├─╯ ○ a ◆ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); // Test with a subgraph containing a merge commit. Since the merge commit "f" // was extracted, its descendants which are not part of the subgraph will // inherit its descendants which are not in the subtree ("c" and "d"). // "f" will retain its parent "c" since "c" is outside the target set, and not // a descendant of any new children. let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "e::g", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 3 commits onto destination Rebased 2 descendant commits Working copy now at: xznxytkn 1868ded4 i | i Parent commit : royxmykx 7e4fbf4f c | c Parent commit : vruxwmqv 4cc44fbf d | d Added 0 files, modified 0 files, removed 2 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ i: c d ├─╮