ok/jj
1
0
Fork 0
forked from mirrors/jj

repo: introduce MutableRepo::reparent_descendants()

This commit is contained in:
Samuel Tardieu 2024-09-17 19:09:13 +02:00
parent 736163c8d3
commit 90280ad2fd
2 changed files with 94 additions and 0 deletions

View file

@ -1334,6 +1334,27 @@ impl MutableRepo {
Ok(num_rebased)
}
/// Reparent descendants of the rewritten commits.
///
/// The descendants of the commits registered in `self.parent_mappings` will
/// be recursively reparented onto the new version of their parents.
/// The content of those descendants will remain untouched.
/// Returns the number of reparented descendants.
pub fn reparent_descendants(&mut self, settings: &UserSettings) -> BackendResult<usize> {
let roots = self.parent_mapping.keys().cloned().collect_vec();
let mut num_reparented = 0;
self.transform_descendants(settings, roots, |rewriter| {
if rewriter.parents_changed() {
let builder = rewriter.reparent(settings)?;
builder.write()?;
num_reparented += 1;
}
Ok(())
})?;
self.parent_mapping.clear();
Ok(num_reparented)
}
pub fn rebase_descendants_return_map(
&mut self,
settings: &UserSettings,

View file

@ -21,6 +21,7 @@ use jj_lib::repo::Repo;
use maplit::hashset;
use testutils::assert_rebased_onto;
use testutils::create_random_commit;
use testutils::create_random_tree;
use testutils::write_random_commit;
use testutils::CommitGraphBuilder;
use testutils::TestRepo;
@ -676,3 +677,75 @@ fn test_remove_wc_commit_previous_discardable() {
mut_repo.rebase_descendants(&settings).unwrap();
assert!(!mut_repo.view().heads().contains(old_wc_commit.id()));
}
#[test]
fn test_reparent_descendants() {
// Test that MutableRepo::reparent_descendants() reparents descendants of
// rewritten commits without altering their content.
let settings = testutils::user_settings();
let test_repo = TestRepo::init();
let repo = &test_repo.repo;
let mut tx = repo.start_transaction(&settings);
let mut graph_builder = CommitGraphBuilder::new(&settings, tx.repo_mut());
let commit_a = graph_builder.initial_commit();
let commit_b = graph_builder.initial_commit();
let commit_child_a_b = graph_builder.commit_with_parents(&[&commit_a, &commit_b]);
let commit_grandchild_a_b = graph_builder.commit_with_parents(&[&commit_child_a_b]);
let commit_child_a = graph_builder.commit_with_parents(&[&commit_a]);
let commit_child_b = graph_builder.commit_with_parents(&[&commit_b]);
let mut_repo = tx.repo_mut();
for (bookmark, commit) in [
("b", &commit_b),
("child_a_b", &commit_child_a_b),
("grandchild_a_b", &commit_grandchild_a_b),
("child_a", &commit_child_a),
("child_b", &commit_child_b),
] {
mut_repo.set_local_bookmark_target(bookmark, RefTarget::normal(commit.id().clone()));
}
let repo = tx.commit("test");
// Rewrite "commit_a".
let mut tx = repo.start_transaction(&settings);
let mut_repo = tx.repo_mut();
mut_repo
.rewrite_commit(&settings, &commit_a)
.set_tree_id(create_random_tree(&repo))
.write()
.unwrap();
let reparented = mut_repo.reparent_descendants(&settings).unwrap();
// "child_a_b", "grandchild_a_b" and "child_a" (3 commits) must have been
// reparented.
assert_eq!(reparented, 3);
let repo = tx.commit("test");
for (bookmark, commit) in [
("b", &commit_b),
("child_a_b", &commit_child_a_b),
("grandchild_a_b", &commit_grandchild_a_b),
("child_a", &commit_child_a),
("child_b", &commit_child_b),
] {
let rewritten_id = repo
.view()
.get_local_bookmark(bookmark)
.as_normal()
.unwrap()
.clone();
if matches!(bookmark, "b" | "child_b") {
// "b" and "child_b" have been kept untouched.
assert_eq!(commit.id(), &rewritten_id);
} else {
// All commits except "b", and "child_b" have been reparented while keeping
// their content.
assert_ne!(commit.id(), &rewritten_id);
let rewritten_commit = repo.store().get_commit(&rewritten_id).unwrap();
assert_eq!(commit.tree_id(), rewritten_commit.tree_id());
let (parent_ids, rewritten_parent_ids) =
(commit.parent_ids(), rewritten_commit.parent_ids());
assert_eq!(parent_ids.len(), rewritten_parent_ids.len());
assert_ne!(parent_ids, rewritten_parent_ids);
}
}
}