forked from mirrors/jj
jj new --insert-after
This commit is contained in:
parent
4119aa44a9
commit
605a39b84f
3 changed files with 154 additions and 1 deletions
|
@ -133,6 +133,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
* `jj new --insert-before` inserts the new commit between the target commit and
|
||||
its parents.
|
||||
|
||||
* `jj new --insert-after` inserts the new commit between the target commit and
|
||||
its children.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* When sharing the working copy with a Git repo, we used to forget to export
|
||||
|
|
|
@ -446,6 +446,7 @@ struct EditArgs {
|
|||
/// For more information, see
|
||||
/// https://github.com/martinvonz/jj/blob/main/docs/working-copy.md.
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
#[command(group(ArgGroup::new("order").args(&["insert_after", "insert_before"])))]
|
||||
struct NewArgs {
|
||||
/// Parent(s) of the new change
|
||||
#[arg(default_value = "@")]
|
||||
|
@ -459,6 +460,9 @@ struct NewArgs {
|
|||
/// Allow revsets expanding to multiple commits in a single argument
|
||||
#[arg(long, short = 'L')]
|
||||
allow_large_revsets: bool,
|
||||
/// Insert the new change between the target commit(s) and their children
|
||||
#[arg(long, short = 'A', visible_alias = "after")]
|
||||
insert_after: bool,
|
||||
/// Insert the new change between the target commit(s) and their parents
|
||||
#[arg(long, short = 'B', visible_alias = "before")]
|
||||
insert_before: bool,
|
||||
|
@ -2097,9 +2101,45 @@ fn cmd_new(ui: &mut Ui, command: &CommandHelper, args: &NewArgs) -> Result<(), C
|
|||
let merged_tree = merge_commit_trees(tx.base_repo().as_repo_ref(), &target_commits);
|
||||
new_commit = tx
|
||||
.mut_repo()
|
||||
.new_commit(command.settings(), target_ids, merged_tree.id().clone())
|
||||
.new_commit(
|
||||
command.settings(),
|
||||
target_ids.clone(),
|
||||
merged_tree.id().clone(),
|
||||
)
|
||||
.set_description(&args.message)
|
||||
.write()?;
|
||||
if args.insert_after {
|
||||
// Each child of the targets will be rebased: its set of parents will be updated
|
||||
// so that the targets are replaced by the new commit.
|
||||
let old_parents = RevsetExpression::commits(target_ids);
|
||||
// Exclude children that are ancestors of the new commit
|
||||
let to_rebase = old_parents.children().minus(&old_parents.ancestors());
|
||||
let commits_to_rebase: Vec<Commit> = tx
|
||||
.base_workspace_helper()
|
||||
.evaluate_revset(&to_rebase)?
|
||||
.iter()
|
||||
.commits(tx.base_repo().store())
|
||||
.try_collect()?;
|
||||
num_rebased = commits_to_rebase.len();
|
||||
for child_commit in commits_to_rebase {
|
||||
let commit_parents =
|
||||
RevsetExpression::commits(child_commit.parent_ids().to_owned());
|
||||
let new_parents = commit_parents.minus(&old_parents);
|
||||
let mut new_parent_commits: Vec<Commit> = tx
|
||||
.base_workspace_helper()
|
||||
.evaluate_revset(&new_parents)?
|
||||
.iter()
|
||||
.commits(tx.base_repo().store())
|
||||
.try_collect()?;
|
||||
new_parent_commits.push(new_commit.clone());
|
||||
rebase_commit(
|
||||
command.settings(),
|
||||
tx.mut_repo(),
|
||||
&child_commit,
|
||||
&new_parent_commits,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
num_rebased += tx.mut_repo().rebase_descendants(command.settings())?;
|
||||
if num_rebased > 0 {
|
||||
|
|
|
@ -106,6 +106,116 @@ fn test_new_merge() {
|
|||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_insert_after() {
|
||||
let test_env = TestEnvironment::default();
|
||||
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||
let repo_path = test_env.env_root().join("repo");
|
||||
setup_before_insertion(&test_env, &repo_path);
|
||||
insta::assert_snapshot!(get_short_log_output(&test_env, &repo_path), @r###"
|
||||
@ F
|
||||
|\
|
||||
o | E
|
||||
| o D
|
||||
|/
|
||||
| o C
|
||||
| o B
|
||||
| o A
|
||||
|/
|
||||
o root
|
||||
"###);
|
||||
|
||||
let stdout =
|
||||
test_env.jj_cmd_success(&repo_path, &["new", "--insert-after", "-m", "G", "B", "D"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
Rebased 2 descendant commits
|
||||
Working copy now at: ca7c6481a8dd G
|
||||
"###);
|
||||
insta::assert_snapshot!(get_short_log_output(&test_env, &repo_path), @r###"
|
||||
o C
|
||||
| o F
|
||||
| |\
|
||||
|/ /
|
||||
@ | G
|
||||
|\ \
|
||||
| | o E
|
||||
o | | D
|
||||
| |/
|
||||
|/|
|
||||
| o B
|
||||
| o A
|
||||
|/
|
||||
o root
|
||||
"###);
|
||||
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["new", "--insert-after", "-m", "H", "D"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
Rebased 3 descendant commits
|
||||
Working copy now at: fcf8281b4135 H
|
||||
"###);
|
||||
insta::assert_snapshot!(get_short_log_output(&test_env, &repo_path), @r###"
|
||||
o C
|
||||
| o F
|
||||
| |\
|
||||
|/ /
|
||||
o | G
|
||||
|\ \
|
||||
@ | | H
|
||||
| | o E
|
||||
o | | D
|
||||
| |/
|
||||
|/|
|
||||
| o B
|
||||
| o A
|
||||
|/
|
||||
o root
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_insert_after_children() {
|
||||
let test_env = TestEnvironment::default();
|
||||
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||
let repo_path = test_env.env_root().join("repo");
|
||||
setup_before_insertion(&test_env, &repo_path);
|
||||
insta::assert_snapshot!(get_short_log_output(&test_env, &repo_path), @r###"
|
||||
@ F
|
||||
|\
|
||||
o | E
|
||||
| o D
|
||||
|/
|
||||
| o C
|
||||
| o B
|
||||
| o A
|
||||
|/
|
||||
o root
|
||||
"###);
|
||||
|
||||
// Check that inserting G after A and C doesn't try to rebase B (which is
|
||||
// initially a child of A) onto G as that would create a cycle since B is
|
||||
// a parent of C which is a parent G.
|
||||
let stdout =
|
||||
test_env.jj_cmd_success(&repo_path, &["new", "--insert-after", "-m", "G", "A", "C"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
Working copy now at: b48d4d73a39c G
|
||||
"###);
|
||||
insta::assert_snapshot!(get_short_log_output(&test_env, &repo_path), @r###"
|
||||
@ G
|
||||
|\
|
||||
| | o F
|
||||
| | |\
|
||||
| | o | E
|
||||
| | | o D
|
||||
| | |/
|
||||
o | | C
|
||||
o | | B
|
||||
|/ /
|
||||
o | A
|
||||
|/
|
||||
o root
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_insert_before() {
|
||||
let test_env = TestEnvironment::default();
|
||||
|
|
Loading…
Reference in a new issue