Skip to content

Commit

Permalink
restore: add --restore-descendants flag
Browse files Browse the repository at this point in the history
  • Loading branch information
samueltardieu committed Sep 24, 2024
1 parent e8deb08 commit 667fe49
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 7 deletions.
8 changes: 3 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
* `jj commit` and `jj describe` now accept `--author` option allowing to quickly change
author of given commit.

* `jj diffedit` now accepts a `--restore-descendants` flag. When used,
descendants of the edited commit will keep their original content.

* `jj abandon` now accepts a `--restore-descendants` flag. When used,
descendants of the abandoned commits will keep their original content.
* `jj diffedit`, `jj abandon`, and `jj restore` now accept a `--restore-descendants`
flag. When used, descendants of the edited or deleted commits will keep their original
content.

### Fixed bugs

Expand Down
17 changes: 15 additions & 2 deletions cli/src/commands/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ pub(crate) struct RestoreArgs {
/// the user might not even realize something went wrong.
#[arg(long, short, hide = true)]
revision: Option<RevisionArg>,
/// Preserve the content (not the diff) when rebasing descendants
#[arg(long)]
restore_descendants: bool,
}

#[instrument(skip_all)]
Expand Down Expand Up @@ -116,13 +119,23 @@ pub(crate) fn cmd_restore(
.write()?;
// rebase_descendants early; otherwise `new_commit` would always have
// a conflicted change id at this point.
let num_rebased = tx.repo_mut().rebase_descendants(command.settings())?;
let (num_rebased, extra_msg) = if args.restore_descendants {
(
tx.repo_mut().reparent_descendants(command.settings())?,
" (while preserving their content)",
)
} else {
(tx.repo_mut().rebase_descendants(command.settings())?, "")
};
if let Some(mut formatter) = ui.status_formatter() {
write!(formatter, "Created ")?;
tx.write_commit_summary(formatter.as_mut(), &new_commit)?;
writeln!(formatter)?;
if num_rebased > 0 {
writeln!(formatter, "Rebased {num_rebased} descendant commits")?;
writeln!(
formatter,
"Rebased {num_rebased} descendant commits{extra_msg}"
)?;
}
}
tx.finish(ui, format!("restore into commit {}", to_commit.id().hex()))?;
Expand Down
1 change: 1 addition & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,7 @@ See `jj diffedit` if you'd like to restore portions of files rather than entire
This undoes the changes that can be seen with `jj diff -r REVISION`. If `REVISION` only has a single parent, this option is equivalent to `jj restore --to REVISION --from REVISION-`.
The default behavior of `jj restore` is equivalent to `jj restore --changes-in @`.
* `--restore-descendants` — Preserve the content (not the diff) when rebasing descendants
Expand Down
81 changes: 81 additions & 0 deletions cli/tests/test_restore_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,87 @@ fn test_restore_conflicted_merge() {
"###);
}

#[test]
fn test_restore_restore_descendants() {
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, "base", &[], &[("file", "base\n")]);
create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]);
create_commit(
&test_env,
&repo_path,
"b",
&["base"],
&[("file", "b\n"), ("file2", "b\n")],
);
create_commit(
&test_env,
&repo_path,
"ab",
&["a", "b"],
&[("file", "ab\n")],
);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r#"
@ ab
├─╮
│ ○ b
○ │ a
├─╯
○ base
"#);
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap(), @r#"
ab
"#);

// Commit "b" was not supposed to modify "file", restore it from its parent
// while preserving its child commit content.
let (stdout, stderr) = test_env.jj_cmd_ok(
&repo_path,
&["restore", "-c", "b", "file", "--restore-descendants"],
);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r#"
Created royxmykx 3fd5aa05 b | b
Rebased 1 descendant commits (while preserving their content)
Working copy now at: vruxwmqv bf5491a0 ab | ab
Parent commit : zsuskuln aa493daf a | a
Parent commit : royxmykx 3fd5aa05 b | b
"#);

// Check that "a", "b", and "ab" have their expected content by diffing them.
// "ab" must have kept its content.
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--from=a", "--to=ab", "--git"]), @r#"
diff --git a/file b/file
index 7898192261..81bf396956 100644
--- a/file
+++ b/file
@@ -1,1 +1,1 @@
-a
+ab
diff --git a/file2 b/file2
new file mode 100644
index 0000000000..6178079822
--- /dev/null
+++ b/file2
@@ -1,0 +1,1 @@
+b
"#);
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--from=b", "--to=ab", "--git"]), @r#"
diff --git a/file b/file
index df967b96a5..81bf396956 100644
--- a/file
+++ b/file
@@ -1,1 +1,1 @@
-base
+ab
"#);
}

fn create_commit(
test_env: &TestEnvironment,
repo_path: &Path,
Expand Down

0 comments on commit 667fe49

Please sign in to comment.