mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-27 06:27:43 +00:00
rewrite: make merge_commit_trees() use index for finding common ancestors
The index is now always kept up to date and it has functionality for finding common ancestors, so let's use it! This should make merging commits a little faster if their common ancestor is far away (which is rare). It's probably much more important that the index-based algorithm is more correct. Also, it returns multiple common ancestors in the criss-cross case, which lets us do a recursive merge like git does. I'm leaving the recursive merge for later, though.
This commit is contained in:
parent
bb94516175
commit
2a531832d6
4 changed files with 23 additions and 19 deletions
|
@ -619,16 +619,16 @@ fn evolve_two_divergent_commits(
|
|||
let rebased_tree2 = if commit2.parents() == new_parents {
|
||||
commit2.tree()
|
||||
} else {
|
||||
let old_base_tree = merge_commit_trees(store, &commit2.parents());
|
||||
let new_base_tree = merge_commit_trees(store, &new_parents);
|
||||
let old_base_tree = merge_commit_trees(tx.as_repo_ref(), &commit2.parents());
|
||||
let new_base_tree = merge_commit_trees(tx.as_repo_ref(), &new_parents);
|
||||
let tree_id = merge_trees(&new_base_tree, &old_base_tree, &commit2.tree()).unwrap();
|
||||
store.get_tree(&DirRepoPath::root(), &tree_id).unwrap()
|
||||
};
|
||||
let rebased_predecessor_tree = if common_predecessor.parents() == new_parents {
|
||||
common_predecessor.tree()
|
||||
} else {
|
||||
let old_base_tree = merge_commit_trees(store, &common_predecessor.parents());
|
||||
let new_base_tree = merge_commit_trees(store, &new_parents);
|
||||
let old_base_tree = merge_commit_trees(tx.as_repo_ref(), &common_predecessor.parents());
|
||||
let new_base_tree = merge_commit_trees(tx.as_repo_ref(), &new_parents);
|
||||
let tree_id =
|
||||
merge_trees(&new_base_tree, &old_base_tree, &common_predecessor.tree()).unwrap();
|
||||
store.get_tree(&DirRepoPath::root(), &tree_id).unwrap()
|
||||
|
|
|
@ -104,10 +104,10 @@ impl<'a> IndexRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn common_ancestors(&self, ids1: &[CommitId], ids2: &[CommitId]) -> Vec<CommitId> {
|
||||
pub fn common_ancestors(&self, set1: &[CommitId], set2: &[CommitId]) -> Vec<CommitId> {
|
||||
match self {
|
||||
IndexRef::Readonly(index) => index.common_ancestors(ids1, ids2),
|
||||
IndexRef::Mutable(index) => index.common_ancestors(ids1, ids2),
|
||||
IndexRef::Readonly(index) => index.common_ancestors(set1, set2),
|
||||
IndexRef::Mutable(index) => index.common_ancestors(set1, set2),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,23 +14,27 @@
|
|||
|
||||
use crate::commit::Commit;
|
||||
use crate::commit_builder::CommitBuilder;
|
||||
use crate::dag_walk::common_ancestor;
|
||||
use crate::repo::RepoRef;
|
||||
use crate::repo_path::DirRepoPath;
|
||||
use crate::settings::UserSettings;
|
||||
use crate::store_wrapper::StoreWrapper;
|
||||
use crate::transaction::Transaction;
|
||||
use crate::tree::Tree;
|
||||
use crate::trees::merge_trees;
|
||||
|
||||
pub fn merge_commit_trees(store: &StoreWrapper, commits: &[Commit]) -> Tree {
|
||||
pub fn merge_commit_trees(repo: RepoRef, commits: &[Commit]) -> Tree {
|
||||
let store = repo.store();
|
||||
if commits.is_empty() {
|
||||
store
|
||||
.get_tree(&DirRepoPath::root(), store.empty_tree_id())
|
||||
.unwrap()
|
||||
} else {
|
||||
let index = repo.index();
|
||||
let mut new_tree = commits[0].tree();
|
||||
let commit_ids: Vec<_> = commits.iter().map(|commit| commit.id().clone()).collect();
|
||||
for (i, other_commit) in commits.iter().enumerate().skip(1) {
|
||||
let ancestor = common_ancestor(&commits[0..i], vec![other_commit]);
|
||||
let ancestors = index.common_ancestors(&commit_ids[0..i], &[commit_ids[i].clone()]);
|
||||
// TODO: Do recursive merge here instead of using just the first ancestor.
|
||||
let ancestor = store.get_commit(&ancestors[0]).unwrap();
|
||||
let new_tree_id =
|
||||
merge_trees(&new_tree, &ancestor.tree(), &other_commit.tree()).unwrap();
|
||||
new_tree = store.get_tree(&DirRepoPath::root(), &new_tree_id).unwrap();
|
||||
|
@ -46,8 +50,8 @@ pub fn rebase_commit(
|
|||
new_parents: &[Commit],
|
||||
) -> Commit {
|
||||
let store = tx.store();
|
||||
let old_base_tree = merge_commit_trees(store, &old_commit.parents());
|
||||
let new_base_tree = merge_commit_trees(store, &new_parents);
|
||||
let old_base_tree = merge_commit_trees(tx.as_repo_ref(), &old_commit.parents());
|
||||
let new_base_tree = merge_commit_trees(tx.as_repo_ref(), &new_parents);
|
||||
// TODO: pass in labels for the merge parts
|
||||
let new_tree_id = merge_trees(&new_base_tree, &old_base_tree, &old_commit.tree()).unwrap();
|
||||
let new_parent_ids = new_parents
|
||||
|
@ -67,8 +71,8 @@ pub fn back_out_commit(
|
|||
new_parents: &[Commit],
|
||||
) -> Commit {
|
||||
let store = tx.store();
|
||||
let old_base_tree = merge_commit_trees(store, &old_commit.parents());
|
||||
let new_base_tree = merge_commit_trees(store, &new_parents);
|
||||
let old_base_tree = merge_commit_trees(tx.as_repo_ref(), &old_commit.parents());
|
||||
let new_base_tree = merge_commit_trees(tx.as_repo_ref(), &new_parents);
|
||||
// TODO: pass in labels for the merge parts
|
||||
let new_tree_id = merge_trees(&new_base_tree, &old_commit.tree(), &old_base_tree).unwrap();
|
||||
let new_parent_ids = new_parents
|
||||
|
|
|
@ -769,7 +769,7 @@ fn cmd_diff(
|
|||
sub_matches.value_of("revision").unwrap_or("@"),
|
||||
)?;
|
||||
let parents = commit.parents();
|
||||
from_tree = merge_commit_trees(repo.store(), &parents);
|
||||
from_tree = merge_commit_trees(repo.as_repo_ref(), &parents);
|
||||
to_tree = commit.tree()
|
||||
}
|
||||
if sub_matches.is_present("summary") {
|
||||
|
@ -1484,7 +1484,7 @@ fn cmd_edit(
|
|||
let owned_wc = repo.working_copy().clone();
|
||||
let mut_repo = Arc::get_mut(&mut repo).unwrap();
|
||||
let commit = resolve_revision_arg(ui, mut_repo, sub_matches)?;
|
||||
let base_tree = merge_commit_trees(repo.store(), &commit.parents());
|
||||
let base_tree = merge_commit_trees(repo.as_repo_ref(), &commit.parents());
|
||||
let tree_id = crate::diff_edit::edit_diff(&base_tree, &commit.tree())?;
|
||||
if &tree_id == commit.tree().id() {
|
||||
ui.write("Nothing changed.\n");
|
||||
|
@ -1516,7 +1516,7 @@ fn cmd_split(
|
|||
let owned_wc = repo.working_copy().clone();
|
||||
let mut_repo = Arc::get_mut(&mut repo).unwrap();
|
||||
let commit = resolve_revision_arg(ui, mut_repo, sub_matches)?;
|
||||
let base_tree = merge_commit_trees(repo.store(), &commit.parents());
|
||||
let base_tree = merge_commit_trees(repo.as_repo_ref(), &commit.parents());
|
||||
let tree_id = crate::diff_edit::edit_diff(&base_tree, &commit.tree())?;
|
||||
if &tree_id == commit.tree().id() {
|
||||
ui.write("Nothing changed.\n");
|
||||
|
@ -1579,7 +1579,7 @@ fn cmd_merge(
|
|||
} else {
|
||||
description = edit_description(&repo, "");
|
||||
}
|
||||
let merged_tree = merge_commit_trees(repo.store(), &commits);
|
||||
let merged_tree = merge_commit_trees(repo.as_repo_ref(), &commits);
|
||||
let mut tx = repo.start_transaction("merge commits");
|
||||
CommitBuilder::for_new_commit(ui.settings(), repo.store(), merged_tree.id().clone())
|
||||
.set_parents(parent_ids)
|
||||
|
|
Loading…
Reference in a new issue