Skip to content

Commit

Permalink
repo: introduce MutableRepo::reparent_descendants()
Browse files Browse the repository at this point in the history
  • Loading branch information
samueltardieu committed Sep 23, 2024
1 parent dc7bdc0 commit 5f33579
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
21 changes: 21 additions & 0 deletions lib/src/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
73 changes: 73 additions & 0 deletions lib/tests/test_mut_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,3 +676,76 @@ 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" by removing its content.
let mut tx = repo.start_transaction(&settings);
let mut_repo = tx.repo_mut();
let empty_commit_tree_id = mut_repo.store().empty_merged_tree_id().clone();
mut_repo
.rewrite_commit(&settings, &commit_a)
.set_tree_id(empty_commit_tree_id)
.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);
}
}
}

0 comments on commit 5f33579

Please sign in to comment.