diff --git a/cli/src/commands/rebase.rs b/cli/src/commands/rebase.rs index 8b6ffc68cd..58547e58cc 100644 --- a/cli/src/commands/rebase.rs +++ b/cli/src/commands/rebase.rs @@ -20,7 +20,6 @@ use std::sync::Arc; use clap::ArgGroup; use indexmap::IndexSet; use itertools::Itertools; -use jj_lib::backend::CommitId; use jj_lib::commit::{Commit, CommitIteratorExt}; use jj_lib::object_id::ObjectId; use jj_lib::repo::{ReadonlyRepo, Repo}; @@ -356,96 +355,45 @@ fn rebase_revision( new_parents: &[Commit], rev_arg: &RevisionArg, ) -> Result<(), CommandError> { - let old_commit = workspace_command.resolve_single_rev(rev_arg)?; - workspace_command.check_rewritable([old_commit.id()])?; - if new_parents.contains(&old_commit) { + let to_rebase_commit = workspace_command.resolve_single_rev(rev_arg)?; + workspace_command.check_rewritable([to_rebase_commit.id()])?; + if new_parents.contains(&to_rebase_commit) { return Err(user_error(format!( "Cannot rebase {} onto itself", - short_commit_hash(old_commit.id()), + short_commit_hash(to_rebase_commit.id()), ))); } - let children_expression = RevsetExpression::commit(old_commit.id().clone()).children(); - let child_commits: Vec<_> = children_expression - .evaluate_programmatic(workspace_command.repo().as_ref()) - .unwrap() - .iter() - .commits(workspace_command.repo().store()) - .try_collect()?; - // Currently, immutable commits are defined so that a child of a rewriteable - // commit is always rewriteable. - debug_assert!(workspace_command - .check_rewritable(child_commits.iter().ids()) - .is_ok()); - - // First, rebase the children of `old_commit`. let mut tx = workspace_command.start_transaction(); let mut rebased_commit_ids = HashMap::new(); - for child_commit in child_commits { - let new_child_parent_ids: Vec = child_commit - .parents() - .iter() - .flat_map(|c| { - if c == &old_commit { - old_commit.parent_ids().to_vec() - } else { - [c.id().clone()].to_vec() - } - }) - .collect(); - - // Some of the new parents may be ancestors of others as in - // `test_rebase_single_revision`. - let new_child_parents_expression = RevsetExpression::commits(new_child_parent_ids.clone()) - .minus( - &RevsetExpression::commits(new_child_parent_ids.clone()) - .parents() - .ancestors(), - ); - let new_child_parents = new_child_parents_expression - .evaluate_programmatic(tx.base_repo().as_ref()) - .unwrap() - .iter() - .collect_vec(); - rebased_commit_ids.insert( - child_commit.id().clone(), - rebase_commit(settings, tx.mut_repo(), child_commit, new_child_parents)? - .id() - .clone(), - ); - } - // Now, rebase the descendants of the children. + // First, rebase the descendants of `to_rebase_commit`. // TODO(ilyagr): Consider making it possible for these descendants to become // emptied, like --skip_empty. This would require writing careful tests. - rebased_commit_ids.extend(tx.mut_repo().rebase_descendants_return_map(settings)?); + tx.mut_repo().transform_descendants( + settings, + vec![to_rebase_commit.id().clone()], + |mut rewriter| { + let old_commit = rewriter.old_commit(); + let old_commit_id = old_commit.id().clone(); + + // Replace references to `to_rebase_commit` with its parents. + rewriter.replace_parent(to_rebase_commit.id(), to_rebase_commit.parent_ids()); + if rewriter.parents_changed() { + let builder = rewriter.rebase(settings)?; + let commit = builder.write()?; + rebased_commit_ids.insert(old_commit_id, commit.id().clone()); + } + Ok(()) + }, + )?; + let num_rebased_descendants = rebased_commit_ids.len(); // We now update `new_parents` to account for the rebase of all of - // `old_commit`'s descendants. Even if some of the original `new_parents` - // were descendants of `old_commit`, this will no longer be the case after + // `to_rebase_commit`'s descendants. Even if some of the original `new_parents` + // were descendants of `to_rebase_commit`, this will no longer be the case after // the update. - // - // To make the update simpler, we assume that each commit was rewritten only - // once; we don't have a situation where both `(A,B)` and `(B,C)` are in - // `rebased_commit_ids`. - // - // TODO(BUG #2650): There is something wrong with this assumption, the next TODO - // seems to be a little optimistic. See the panicked test in - // `test_rebase_with_child_and_descendant_bug_2600`. - // - // TODO(ilyagr): This assumption relies on the fact that, after - // `rebase_descendants`, a descendant of `old_commit` cannot also be a - // direct child of `old_commit`. This fact will likely change, see - // https://github.com/martinvonz/jj/issues/2600. So, the code needs to be - // updated before that happens. This would also affect - // `test_rebase_with_child_and_descendant_bug_2600`. - // - // The issue is that if a child and a descendant of `old_commit` were the - // same commit (call it `Q`), it would be rebased first by `rebase_commit` - // above, and then the result would be rebased again by - // `rebase_descendants_return_map`. Then, if we were trying to rebase - // `old_commit` onto `Q`, new_parents would only account for one of these. let new_parents = new_parents .iter() .map(|new_parent| { @@ -456,20 +404,20 @@ fn rebase_revision( }) .collect(); - let tx_description = format!("rebase commit {}", old_commit.id().hex()); - // Finally, it's safe to rebase `old_commit`. We can skip rebasing if it is - // already a child of `new_parents`. Otherwise, at this point, it should no - // longer have any children; they have all been rebased and the originals + let tx_description = format!("rebase commit {}", to_rebase_commit.id().hex()); + // Finally, it's safe to rebase `to_rebase_commit`. We can skip rebasing if it + // is already a child of `new_parents`. Otherwise, at this point, it should + // no longer have any children; they have all been rebased and the originals // have been abandoned. - let skipped_commit_rebase = if old_commit.parent_ids() == new_parents { + let skipped_commit_rebase = if to_rebase_commit.parent_ids() == new_parents { if let Some(mut formatter) = ui.status_formatter() { write!(formatter, "Skipping rebase of commit ")?; - tx.write_commit_summary(formatter.as_mut(), &old_commit)?; + tx.write_commit_summary(formatter.as_mut(), &to_rebase_commit)?; writeln!(formatter)?; } true } else { - rebase_commit(settings, tx.mut_repo(), old_commit, new_parents)?; + rebase_commit(settings, tx.mut_repo(), to_rebase_commit, new_parents)?; debug_assert_eq!(tx.mut_repo().rebase_descendants(settings)?, 0); false }; diff --git a/cli/tests/common/mod.rs b/cli/tests/common/mod.rs index 880046ee61..72f4eb5a51 100644 --- a/cli/tests/common/mod.rs +++ b/cli/tests/common/mod.rs @@ -227,6 +227,7 @@ impl TestEnvironment { /// Run a `jj` command, check that it failed with code 101, and return its /// stderr #[must_use] + #[allow(dead_code)] pub fn jj_cmd_panic(&self, current_dir: &Path, args: &[&str]) -> String { let assert = self.jj_cmd(current_dir, args).assert().code(101).stdout(""); self.normalize_output(&get_stderr_string(&assert)) diff --git a/cli/tests/test_rebase_command.rs b/cli/tests/test_rebase_command.rs index 0dd41d2919..f137983db5 100644 --- a/cli/tests/test_rebase_command.rs +++ b/cli/tests/test_rebase_command.rs @@ -266,63 +266,64 @@ fn test_rebase_single_revision() { 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", &["a", "b"]); - create_commit(&test_env, &repo_path, "d", &["c"]); + 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###" - @ d - ◉ c + @ e + ◉ d ├─╮ - │ ◉ b - ◉ │ a + │ ◉ c + ◉ │ b ├─╯ + ◉ a ◉ "###); - // Descendants of the rebased commit "b" should be rebased onto parents. First - // we test with a non-merge commit. Normally, the descendant "c" would still - // have 2 parents afterwards: the parent of "b" -- the root commit -- and - // "a". However, since the root commit is an ancestor of "a", we don't - // actually want both to be parents of the same commit. So, only "a" becomes - // a parent. - let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-d", "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###" Also rebased 2 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv 7e15b97a d | d - Parent commit : royxmykx 934236c8 c | c + 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###" - ◉ b - │ @ d - │ ◉ c + ◉ c + │ @ e + │ ◉ d + ╭─┤ + ◉ │ b ├─╯ ◉ a ◉ "###); test_env.jj_cmd_ok(&repo_path, &["undo"]); - // Now, let's try moving the merge commit. After, both parents of "c" ("a" and - // "b") should become parents of "d". - let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "root()"]); + // 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###" Also rebased 1 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv bf87078f d | d - Parent commit : zsuskuln d370aee1 b | b - Parent commit : rlvkpnrz 2443ea76 a | a + 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###" - ◉ c - │ @ d + ◉ d + │ @ e │ ├─╮ - │ │ ◉ a + │ │ ◉ c ├───╯ │ ◉ b ├─╯ + ◉ a ◉ "###); } @@ -354,17 +355,17 @@ fn test_rebase_single_revision_merge_parent() { insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Also rebased 1 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv c62d0789 d | d - Parent commit : zsuskuln d370aee1 b | b + 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###" ◉ c │ @ d ╭─┤ - ◉ │ a │ ◉ b + ◉ │ a ├─╯ ◉ "###); @@ -694,7 +695,8 @@ fn test_rebase_with_child_and_descendant_bug_2600() { test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); let repo_path = test_env.env_root().join("repo"); - create_commit(&test_env, &repo_path, "base", &[]); + create_commit(&test_env, &repo_path, "notroot", &[]); + create_commit(&test_env, &repo_path, "base", &["notroot"]); create_commit(&test_env, &repo_path, "a", &["base"]); create_commit(&test_env, &repo_path, "b", &["base", "a"]); create_commit(&test_env, &repo_path, "c", &["b"]); @@ -708,16 +710,17 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); // ===================== rebase -s tests ================= let (stdout, stderr) = - test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "base", "-d", "root()"]); + test_env.jj_cmd_ok(&repo_path, &["rebase", "-s", "base", "-d", "notroot"]); insta::assert_snapshot!(stdout, @""); // This should be a no-op insta::assert_snapshot!(stderr, @r###" - Skipping rebase of commit rlvkpnrz 0c61db1b base | base + Skipping rebase of commit zsuskuln 0a7fb8f6 base | base "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ c @@ -726,6 +729,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -734,7 +738,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); // This should be a no-op insta::assert_snapshot!(stderr, @r###" - Skipping rebase of commit zsuskuln 2c5b7858 a | a + Skipping rebase of commit royxmykx 86a06598 a | a "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ c @@ -743,6 +747,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -751,8 +756,8 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 3 commits - Working copy now at: vruxwmqv 2b10f149 c | c - Parent commit : royxmykx 3b233bd8 b | b + Working copy now at: znkkpsqq cf8ecff5 c | c + Parent commit : vruxwmqv 24e1a270 b | b "###); // Commit "a" should be rebased onto the root commit. Commit "b" should have // "base" and "a" as parents as before. @@ -762,6 +767,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { ├─╮ │ ◉ a ◉ │ base + ◉ │ notroot ├─╯ ◉ "###); @@ -776,6 +782,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -784,7 +791,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { // The commits in roots(base..c), i.e. commit "a" should be rebased onto "base", // which is a no-op insta::assert_snapshot!(stderr, @r###" - Skipping rebase of commit zsuskuln 2c5b7858 a | a + Skipping rebase of commit royxmykx 86a06598 a | a "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ c @@ -793,6 +800,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -801,8 +809,8 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Rebased 2 commits - Working copy now at: vruxwmqv 2fc4ef73 c | c - Parent commit : royxmykx 9912ef4b b | b + Working copy now at: znkkpsqq 76914dcc c | c + Parent commit : vruxwmqv f73f03c7 b | b "###); // The commits in roots(a..c), i.e. commit "b" should be rebased onto "a", // which means "b" loses its "base" parent @@ -811,6 +819,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { ◉ b ◉ a ◉ base + ◉ notroot ◉ "###); @@ -819,7 +828,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); // This should be a no-op insta::assert_snapshot!(stderr, @r###" - Skipping rebase of commit rlvkpnrz 0c61db1b base | base + Skipping rebase of commit rlvkpnrz 39f28e63 notroot | notroot "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @ c @@ -828,6 +837,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -841,6 +851,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -848,134 +859,66 @@ fn test_rebase_with_child_and_descendant_bug_2600() { test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "root()"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" - Skipping rebase of commit rlvkpnrz 0c61db1b base | base - Rebased 4 descendant commits onto parent of commit - Working copy now at: vruxwmqv 57aaa944 c | c - Parent commit : royxmykx c8495a71 b | b + Also rebased 3 descendant commits onto parent of rebased commit + Working copy now at: znkkpsqq 45371aaf c | c + Parent commit : vruxwmqv c0a76bf4 b | b Added 0 files, modified 0 files, removed 1 files "###); // The user would expect unsimplified ancestry here. - // ◉ base - // │ @ c - // │ ◉ b - // │ ├─╮ - // │ │ ◉ a - // │ ├─╯ - // ├─╯ - // ◉ insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" - @ c - ◉ b - ◉ a - │ ◉ base + ◉ base + │ @ c + │ ◉ b + │ ├─╮ + │ │ ◉ a + │ ├─╯ + │ ◉ notroot ├─╯ ◉ "###); - // TODO(#2650) !!!!! The panic here is a BUG !!! - // This tests the algorithm for rebasing onto descendants. The result should be - // simplified if and only if it's simplified in the above case. + // This tests the algorithm for rebasing onto descendants. The result should + // have unsimplified ancestry. test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); - let stderr = test_env.jj_cmd_panic(&repo_path, &["rebase", "-r", "base", "-d", "b"]); - assert!(stderr.contains("graph has cycle")); - // // At time of writing: - // insta::assert_snapshot!(stderr, @r###" - // thread 'main' panicked at lib/src/dag_walk.rs:113:13: - // graph has cycle - // stack backtrace: - // 0: rust_begin_unwind - // at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/std/src/panicking.rs: - // 645:5 1: core::panicking::panic_fmt - // at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/core/src/panicking. - // rs:72:14 2: jj_lib::dag_walk::topo_order_forward_ok - // at - // /usr/local/google/home/ilyagr/dev/jj/lib/src/dag_walk.rs:113:13 - // 3: jj_lib::dag_walk::topo_order_reverse_ok - // at - // /usr/local/google/home/ilyagr/dev/jj/lib/src/dag_walk.rs:160:22 - // 4: jj_lib::dag_walk::topo_order_reverse - // at - // /usr/local/google/home/ilyagr/dev/jj/lib/src/dag_walk.rs:142:5 - // 5: jj_lib::rewrite::DescendantRebaser::new - // at - // /usr/local/google/home/ilyagr/dev/jj/lib/src/rewrite.rs:306:24 - // 6: jj_lib::repo::MutableRepo::create_descendant_rebaser - // at /usr/local/google/home/ilyagr/dev/jj/lib/src/repo.rs:844:9 - // 7: jj_lib::repo::MutableRepo::rebase_descendants_return_rebaser - // at /usr/local/google/home/ilyagr/dev/jj/lib/src/repo.rs:861:27 - // 8: jj_lib::repo::MutableRepo::rebase_descendants_with_options - // at /usr/local/google/home/ilyagr/dev/jj/lib/src/repo.rs:872:12 - // 9: jj_lib::repo::MutableRepo::rebase_descendants - // at /usr/local/google/home/ilyagr/dev/jj/lib/src/repo.rs:878:9 - // 10: jj_cli::commands::rebase::rebase_revision - // at - // /usr/local/google/home/ilyagr/dev/jj/cli/src/commands/rebase.rs:420:22 - // 11: jj_cli::commands::rebase::cmd_rebase - // at - // /usr/local/google/home/ilyagr/dev/jj/cli/src/commands/rebase.rs:197:9 - // 12: jj_cli::commands::run_command - // at - // /usr/local/google/home/ilyagr/dev/jj/cli/src/commands/mod.rs:187:39 13: - // core::ops::function::FnOnce::call_once at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/core/src/ops/ - // function.rs:250:5 14: core::ops::function::FnOnce::call_once{{vtable. - // shim}} at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/core/src/ops/ - // function.rs:250:5 15: as - // core::ops::function::FnOnce>::call_once at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/alloc/src/boxed.rs: - // 2007:9 16: jj_cli::cli_util::CliRunner::run_internal - // at - // /usr/local/google/home/ilyagr/dev/jj/cli/src/cli_util.rs:2867:9 - // 17: jj_cli::cli_util::CliRunner::run - // at - // /usr/local/google/home/ilyagr/dev/jj/cli/src/cli_util.rs:2884:22 - // 18: jj::main - // at /usr/local/google/home/ilyagr/dev/jj/cli/src/main.rs:18:5 - // 19: core::ops::function::FnOnce::call_once - // at - // /rustc/6cf088810f66fff15d05bf7135c5f5888b7c93b4/library/core/src/ops/ - // function.rs:250:5 note: Some details are omitted, run with - // `RUST_BACKTRACE=full` for a verbose backtrace. "###); - // - // Unsimlified ancestry would look like - // @ c - // │ ◉ base - // ├─╯ - // ◉ b - // ├─╮ - // │ ◉ a - // ├─╯ - // ◉ + let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "b"]); + insta::assert_snapshot!(stdout, @""); + insta::assert_snapshot!(stderr, @r###" + Also rebased 3 descendant commits onto parent of rebased commit + Working copy now at: znkkpsqq e28fa972 c | c + Parent commit : vruxwmqv 8d0eeb6a b | b + Added 0 files, modified 0 files, removed 1 files + "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" - @ c + ◉ base + │ @ c + ├─╯ ◉ b ├─╮ │ ◉ a ├─╯ - ◉ base + ◉ notroot ◉ "###); - // This tests the algorithm for rebasing onto descendants. The result should be - // simplified if and only if it's simplified in the above case. + // This tests the algorithm for rebasing onto descendants. The result should + // have unsimplified ancestry. test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "base", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" - Also rebased 4 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv 0b91d0eb c | c - Parent commit : royxmykx fb944989 b | b + Also rebased 3 descendant commits onto parent of rebased commit + Working copy now at: znkkpsqq a9da974c c | c + Parent commit : vruxwmqv 0072139c b | b Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ◉ base │ @ c │ ◉ b + ╭─┤ + ◉ │ a ├─╯ - ◉ a + ◉ notroot ◉ "###); @@ -988,6 +931,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ ◉ a ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -995,8 +939,8 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Also rebased 2 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv f366e099 c | c - Parent commit : royxmykx bfc7c538 b | b + Working copy now at: znkkpsqq 7210b05e c | c + Parent commit : vruxwmqv da3f7511 b | b Added 0 files, modified 0 files, removed 1 files "###); // In this case, it is unclear whether the user would always prefer unsimplified @@ -1006,6 +950,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { │ @ c │ ◉ b │ ◉ base + │ ◉ notroot ├─╯ ◉ "###); @@ -1015,44 +960,44 @@ fn test_rebase_with_child_and_descendant_bug_2600() { insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Also rebased 1 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv 4d1fd267 c | c - Parent commit : zsuskuln 2c5b7858 a | a + Working copy now at: znkkpsqq f280545e c | c + Parent commit : zsuskuln 0a7fb8f6 base | base + Parent commit : royxmykx 86a06598 a | a Added 0 files, modified 0 files, removed 1 files "###); // The user would expect unsimplified ancestry here. - // ◉ b - // │ @ c - // │ ├─╮ - // │ │ ◉ a - // │ ├─╯ - // │ ◉ base - // ├─╯ - // ◉ insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ◉ b - │ @ c - │ ◉ a + │ @ c + │ ├─╮ + │ │ ◉ a + │ ├─╯ │ ◉ base + │ ◉ notroot ├─╯ ◉ "###); - // This tests the algorithm for rebasing onto descendants. The result should be - // simplified if and only if it's simplified in the above case. + // This tests the algorithm for rebasing onto descendants. The result should + // have unsimplified ancestry. test_env.jj_cmd_ok(&repo_path, &["op", "restore", &setup_opid]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "b", "-d", "c"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" Also rebased 1 descendant commits onto parent of rebased commit - Working copy now at: vruxwmqv 0bacac66 c | c - Parent commit : zsuskuln 2c5b7858 a | a + Working copy now at: znkkpsqq c0a7cd80 c | c + Parent commit : zsuskuln 0a7fb8f6 base | base + Parent commit : royxmykx 86a06598 a | a Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ◉ b - @ c - ◉ a + @ c + ├─╮ + │ ◉ a + ├─╯ ◉ base + ◉ notroot ◉ "###); @@ -1062,8 +1007,8 @@ fn test_rebase_with_child_and_descendant_bug_2600() { let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "c", "-d", "a"]); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r###" - Working copy now at: vruxwmqv e64d4b0d c | c - Parent commit : zsuskuln 2c5b7858 a | a + Working copy now at: znkkpsqq 7a3bc050 c | c + Parent commit : royxmykx 86a06598 a | a Added 0 files, modified 0 files, removed 1 files "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" @@ -1073,6 +1018,7 @@ fn test_rebase_with_child_and_descendant_bug_2600() { ◉ │ a ├─╯ ◉ base + ◉ notroot ◉ "###); }