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

evolution: don't create merge commits with one parent ancestor of another

This commit is contained in:
Martin von Zweigbergk 2021-06-30 12:16:42 -07:00
parent 443528159e
commit 1a4d9d5644
2 changed files with 42 additions and 6 deletions

View file

@ -572,7 +572,7 @@ impl<'settings> OrphanResolver<'settings> {
self.remaining_orphans.pop().map(|orphan_pos| {
let store = mut_repo.store();
let orphan_entry = mut_repo.index().entry_by_pos(orphan_pos);
let mut new_parents = vec![];
let mut new_parent_ids = vec![];
let mut ambiguous_new_parents = false;
let evolution = mut_repo.evolution();
for old_parent in orphan_entry.parents() {
@ -582,16 +582,17 @@ impl<'settings> OrphanResolver<'settings> {
ambiguous_new_parents = true;
break;
}
new_parents.push(
store
.get_commit(new_parent_candidates.iter().next().unwrap())
.unwrap(),
);
new_parent_ids.push(new_parent_candidates.into_iter().next().unwrap());
}
let orphan = store.get_commit(&orphan_entry.commit_id()).unwrap();
if ambiguous_new_parents {
OrphanResolution::AmbiguousTarget { orphan }
} else {
let mut new_parents = vec![];
// Don't create commit where one parent is an ancestor of another.
for new_parent_id in mut_repo.index().heads(&new_parent_ids) {
new_parents.push(store.get_commit(&new_parent_id).unwrap());
}
let new_commit = rebase_commit(self.user_settings, mut_repo, &orphan, &new_parents);
OrphanResolution::Resolved { orphan, new_commit }
}

View file

@ -552,6 +552,41 @@ fn test_evolve_orphan(use_git: bool) {
tx.discard();
}
#[test_case(false ; "local store")]
// #[test_case(true ; "git store")]
/// When evolving a merge commit, the new commit should not have a parent that
/// is an ancestor of another parent.
fn test_evolve_orphan_merge_ancestor_of_other_parent(use_git: bool) {
let settings = testutils::user_settings();
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
let root_commit = repo.store().root_commit();
let mut tx = repo.start_transaction("test");
let mut_repo = tx.mut_repo();
let initial = child_commit(&settings, &repo, &root_commit).write_to_repo(mut_repo);
let child1 = child_commit(&settings, &repo, &initial).write_to_repo(mut_repo);
let child2 = child_commit(&settings, &repo, &initial).write_to_repo(mut_repo);
let merge = testutils::create_random_commit(&settings, &repo)
.set_parents(vec![child1.id().clone(), child2.id().clone()])
.write_to_repo(mut_repo);
let rewritten_child2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &child2)
.set_parents(vec![child1.id().clone()])
.set_description("rewritten child2".to_string())
.write_to_repo(mut_repo);
let mut resolver = OrphanResolver::new(&settings, mut_repo);
let resolution = resolver.resolve_next(mut_repo);
assert_matches!(resolution, Some(OrphanResolution::Resolved { .. }));
assert_eq!(resolver.resolve_next(mut_repo), None);
if let Some(OrphanResolution::Resolved { orphan, new_commit }) = resolution {
assert_eq!(orphan, merge);
assert_eq!(new_commit.parents(), vec![rewritten_child2]);
}
tx.discard();
}
#[test_case(false ; "local store")]
#[test_case(true ; "git store")]
fn test_evolve_pruned_orphan(use_git: bool) {