rewrite: propagate backend errors in DescendantRebase::rebase_next()

This commit is contained in:
Martin von Zweigbergk 2022-04-27 22:30:03 -07:00 committed by Martin von Zweigbergk
parent 96b3e05bc5
commit 543a95c653
14 changed files with 201 additions and 159 deletions

View File

@ -195,7 +195,10 @@ impl ReadonlyRepo {
}) })
} }
pub fn load_at_head(user_settings: &UserSettings, repo_path: PathBuf) -> Arc<ReadonlyRepo> { pub fn load_at_head(
user_settings: &UserSettings,
repo_path: PathBuf,
) -> Result<Arc<ReadonlyRepo>, BackendError> {
RepoLoader::init(user_settings, repo_path) RepoLoader::init(user_settings, repo_path)
.load_at_head() .load_at_head()
.resolve(user_settings) .resolve(user_settings)
@ -282,7 +285,10 @@ impl ReadonlyRepo {
Transaction::new(mut_repo, description) Transaction::new(mut_repo, description)
} }
pub fn reload_at_head(&self, user_settings: &UserSettings) -> Arc<ReadonlyRepo> { pub fn reload_at_head(
&self,
user_settings: &UserSettings,
) -> Result<Arc<ReadonlyRepo>, BackendError> {
self.loader().load_at_head().resolve(user_settings) self.loader().load_at_head().resolve(user_settings)
} }
@ -297,9 +303,9 @@ pub enum RepoAtHead {
} }
impl RepoAtHead { impl RepoAtHead {
pub fn resolve(self, user_settings: &UserSettings) -> Arc<ReadonlyRepo> { pub fn resolve(self, user_settings: &UserSettings) -> Result<Arc<ReadonlyRepo>, BackendError> {
match self { match self {
RepoAtHead::Single(repo) => repo, RepoAtHead::Single(repo) => Ok(repo),
RepoAtHead::Unresolved(unresolved) => unresolved.resolve(user_settings), RepoAtHead::Unresolved(unresolved) => unresolved.resolve(user_settings),
} }
} }
@ -312,16 +318,16 @@ pub struct UnresolvedHeadRepo {
} }
impl UnresolvedHeadRepo { impl UnresolvedHeadRepo {
pub fn resolve(self, user_settings: &UserSettings) -> Arc<ReadonlyRepo> { pub fn resolve(self, user_settings: &UserSettings) -> Result<Arc<ReadonlyRepo>, BackendError> {
let base_repo = self.repo_loader.load_at(&self.op_heads[0]); let base_repo = self.repo_loader.load_at(&self.op_heads[0]);
let mut tx = base_repo.start_transaction("resolve concurrent operations"); let mut tx = base_repo.start_transaction("resolve concurrent operations");
for other_op_head in self.op_heads.into_iter().skip(1) { for other_op_head in self.op_heads.into_iter().skip(1) {
tx.merge_operation(other_op_head); tx.merge_operation(other_op_head);
tx.mut_repo().rebase_descendants(user_settings); tx.mut_repo().rebase_descendants(user_settings)?;
} }
let merged_repo = tx.write().leave_unpublished(); let merged_repo = tx.write().leave_unpublished();
self.locked_op_heads.finish(merged_repo.operation()); self.locked_op_heads.finish(merged_repo.operation());
merged_repo Ok(merged_repo)
} }
} }
@ -554,14 +560,14 @@ impl MutableRepo {
) )
} }
pub fn rebase_descendants(&mut self, settings: &UserSettings) -> usize { pub fn rebase_descendants(&mut self, settings: &UserSettings) -> Result<usize, BackendError> {
if !self.has_rewrites() { if !self.has_rewrites() {
// Optimization // Optimization
return 0; return Ok(0);
} }
let mut rebaser = self.create_descendant_rebaser(settings); let mut rebaser = self.create_descendant_rebaser(settings);
rebaser.rebase_all(); rebaser.rebase_all()?;
rebaser.rebased().len() Ok(rebaser.rebased().len())
} }
pub fn set_checkout(&mut self, workspace_id: WorkspaceId, commit_id: CommitId) { pub fn set_checkout(&mut self, workspace_id: WorkspaceId, commit_id: CommitId) {

View File

@ -14,9 +14,9 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use itertools::Itertools; use itertools::{process_results, Itertools};
use crate::backend::CommitId; use crate::backend::{BackendError, CommitId};
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::CommitBuilder; use crate::commit_builder::CommitBuilder;
use crate::dag_walk; use crate::dag_walk;
@ -290,8 +290,12 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
) )
} }
fn update_references(&mut self, old_commit_id: CommitId, new_commit_ids: Vec<CommitId>) { fn update_references(
self.update_checkouts(&old_commit_id, &new_commit_ids); &mut self,
old_commit_id: CommitId,
new_commit_ids: Vec<CommitId>,
) -> Result<(), BackendError> {
self.update_checkouts(&old_commit_id, &new_commit_ids)?;
if let Some(branch_names) = self.branches.get(&old_commit_id).cloned() { if let Some(branch_names) = self.branches.get(&old_commit_id).cloned() {
let mut branch_updates = vec![]; let mut branch_updates = vec![];
@ -324,9 +328,14 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
if !self.new_commits.contains(&old_commit_id) || self.rebased.contains_key(&old_commit_id) { if !self.new_commits.contains(&old_commit_id) || self.rebased.contains_key(&old_commit_id) {
self.heads_to_remove.push(old_commit_id); self.heads_to_remove.push(old_commit_id);
} }
Ok(())
} }
fn update_checkouts(&mut self, old_commit_id: &CommitId, new_commit_ids: &[CommitId]) { fn update_checkouts(
&mut self,
old_commit_id: &CommitId,
new_commit_ids: &[CommitId],
) -> Result<(), BackendError> {
let mut workspaces_to_update = vec![]; let mut workspaces_to_update = vec![];
for (workspace_id, checkout_id) in self.mut_repo.view().checkouts() { for (workspace_id, checkout_id) in self.mut_repo.view().checkouts() {
if checkout_id == old_commit_id { if checkout_id == old_commit_id {
@ -335,7 +344,7 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
} }
if workspaces_to_update.is_empty() { if workspaces_to_update.is_empty() {
return; return Ok(());
} }
// If several workspaces had the same old commit checked out, we want them all // If several workspaces had the same old commit checked out, we want them all
@ -344,7 +353,7 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
// otherwise create a separate new commit for each workspace. // otherwise create a separate new commit for each workspace.
// We arbitrarily pick a new checkout among the candidates. // We arbitrarily pick a new checkout among the candidates.
let new_commit_id = new_commit_ids[0].clone(); let new_commit_id = new_commit_ids[0].clone();
let new_commit = self.mut_repo.store().get_commit(&new_commit_id).unwrap(); let new_commit = self.mut_repo.store().get_commit(&new_commit_id)?;
let new_checkout_commit = let new_checkout_commit =
self.mut_repo self.mut_repo
.check_out(workspaces_to_update[0].clone(), self.settings, &new_commit); .check_out(workspaces_to_update[0].clone(), self.settings, &new_commit);
@ -352,34 +361,35 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
self.mut_repo self.mut_repo
.check_out(workspace_id, self.settings, &new_checkout_commit); .check_out(workspace_id, self.settings, &new_checkout_commit);
} }
Ok(())
} }
// TODO: Perhaps change the interface since it's not just about rebasing // TODO: Perhaps change the interface since it's not just about rebasing
// commits. // commits.
pub fn rebase_next(&mut self) -> Option<RebasedDescendant> { pub fn rebase_next(&mut self) -> Result<Option<RebasedDescendant>, BackendError> {
while let Some(old_commit_id) = self.to_visit.pop() { while let Some(old_commit_id) = self.to_visit.pop() {
if let Some(new_parent_ids) = self.new_parents.get(&old_commit_id).cloned() { if let Some(new_parent_ids) = self.new_parents.get(&old_commit_id).cloned() {
// This is a commit that had already been rebased before `self` was created // This is a commit that had already been rebased before `self` was created
// (i.e. it's part of the input for this rebase). We don't need // (i.e. it's part of the input for this rebase). We don't need
// to rebase it, but we still want to update branches pointing // to rebase it, but we still want to update branches pointing
// to the old commit. // to the old commit.
self.update_references(old_commit_id, new_parent_ids); self.update_references(old_commit_id, new_parent_ids)?;
continue; continue;
} }
if let Some(divergent_ids) = self.divergent.get(&old_commit_id).cloned() { if let Some(divergent_ids) = self.divergent.get(&old_commit_id).cloned() {
// Leave divergent commits in place. Don't update `new_parents` since we don't // Leave divergent commits in place. Don't update `new_parents` since we don't
// want to rebase descendants either. // want to rebase descendants either.
self.update_references(old_commit_id, divergent_ids); self.update_references(old_commit_id, divergent_ids)?;
continue; continue;
} }
let old_commit = self.mut_repo.store().get_commit(&old_commit_id).unwrap(); let old_commit = self.mut_repo.store().get_commit(&old_commit_id)?;
let old_parent_ids = old_commit.parent_ids(); let old_parent_ids = old_commit.parent_ids();
let new_parent_ids = self.new_parents(&old_parent_ids); let new_parent_ids = self.new_parents(&old_parent_ids);
if self.to_skip.contains(&old_commit_id) { if self.to_skip.contains(&old_commit_id) {
// Update the `new_parents` map so descendants are rebased correctly. // Update the `new_parents` map so descendants are rebased correctly.
self.new_parents self.new_parents
.insert(old_commit_id.clone(), new_parent_ids.clone()); .insert(old_commit_id.clone(), new_parent_ids.clone());
self.update_references(old_commit_id, new_parent_ids); self.update_references(old_commit_id, new_parent_ids)?;
continue; continue;
} else if new_parent_ids == old_parent_ids { } else if new_parent_ids == old_parent_ids {
// The commit is already in place. // The commit is already in place.
@ -394,19 +404,21 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
.iter() .iter()
.cloned() .cloned()
.collect(); .collect();
let new_parents = new_parent_ids let new_parents = process_results(
.iter() new_parent_ids
.filter(|new_parent| head_set.contains(new_parent)) .iter()
.map(|new_parent_id| self.mut_repo.store().get_commit(new_parent_id).unwrap()) .filter(|new_parent| head_set.contains(new_parent))
.collect_vec(); .map(|new_parent_id| self.mut_repo.store().get_commit(new_parent_id)),
|iter| iter.collect_vec(),
)?;
let new_commit = rebase_commit(self.settings, self.mut_repo, &old_commit, &new_parents); let new_commit = rebase_commit(self.settings, self.mut_repo, &old_commit, &new_parents);
self.rebased self.rebased
.insert(old_commit_id.clone(), new_commit.id().clone()); .insert(old_commit_id.clone(), new_commit.id().clone());
self.update_references(old_commit_id, vec![new_commit.id().clone()]); self.update_references(old_commit_id, vec![new_commit.id().clone()])?;
return Some(RebasedDescendant { return Ok(Some(RebasedDescendant {
old_commit, old_commit,
new_commit, new_commit,
}); }));
} }
// TODO: As the TODO above says, we should probably change the API. Even if we // TODO: As the TODO above says, we should probably change the API. Even if we
// don't, we should at least make this code not do any work if you call // don't, we should at least make this code not do any work if you call
@ -423,11 +435,12 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
self.mut_repo.set_view(view); self.mut_repo.set_view(view);
self.mut_repo.clear_rewritten_commits(); self.mut_repo.clear_rewritten_commits();
self.mut_repo.clear_abandoned_commits(); self.mut_repo.clear_abandoned_commits();
None Ok(None)
} }
pub fn rebase_all(&mut self) { pub fn rebase_all(&mut self) -> Result<(), BackendError> {
while self.rebase_next().is_some() {} while self.rebase_next()?.is_some() {}
Ok(())
} }
} }

View File

@ -112,7 +112,8 @@ fn test_bad_locking_children(use_git: bool) {
let machine1_repo = machine1_workspace let machine1_repo = machine1_workspace
.repo_loader() .repo_loader()
.load_at_head() .load_at_head()
.resolve(&settings); .resolve(&settings)
.unwrap();
let mut machine1_tx = machine1_repo.start_transaction("test"); let mut machine1_tx = machine1_repo.start_transaction("test");
let child1 = testutils::create_random_commit(&settings, &machine1_repo) let child1 = testutils::create_random_commit(&settings, &machine1_repo)
.set_parents(vec![initial.id().clone()]) .set_parents(vec![initial.id().clone()])
@ -126,7 +127,8 @@ fn test_bad_locking_children(use_git: bool) {
let machine2_repo = machine2_workspace let machine2_repo = machine2_workspace
.repo_loader() .repo_loader()
.load_at_head() .load_at_head()
.resolve(&settings); .resolve(&settings)
.unwrap();
let mut machine2_tx = machine2_repo.start_transaction("test"); let mut machine2_tx = machine2_repo.start_transaction("test");
let child2 = testutils::create_random_commit(&settings, &machine2_repo) let child2 = testutils::create_random_commit(&settings, &machine2_repo)
.set_parents(vec![initial.id().clone()]) .set_parents(vec![initial.id().clone()])
@ -141,7 +143,8 @@ fn test_bad_locking_children(use_git: bool) {
let merged_repo = merged_workspace let merged_repo = merged_workspace
.repo_loader() .repo_loader()
.load_at_head() .load_at_head()
.resolve(&settings); .resolve(&settings)
.unwrap();
assert!(merged_repo.view().heads().contains(child1.id())); assert!(merged_repo.view().heads().contains(child1.id()));
assert!(merged_repo.view().heads().contains(child2.id())); assert!(merged_repo.view().heads().contains(child2.id()));
let op_id = merged_repo.op_id().clone(); let op_id = merged_repo.op_id().clone();
@ -180,10 +183,10 @@ fn test_bad_locking_interrupted(use_git: bool) {
copy_directory(&backup_path, &op_heads_dir); copy_directory(&backup_path, &op_heads_dir);
// Reload the repo and check that only the new head is present. // Reload the repo and check that only the new head is present.
let reloaded_repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let reloaded_repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
assert_eq!(reloaded_repo.op_id(), &op_id); assert_eq!(reloaded_repo.op_id(), &op_id);
// Reload once more to make sure that the .jj/op_heads/ directory was updated // Reload once more to make sure that the .jj/op_heads/ directory was updated
// correctly. // correctly.
let reloaded_repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let reloaded_repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
assert_eq!(reloaded_repo.op_id(), &op_id); assert_eq!(reloaded_repo.op_id(), &op_id);
} }

View File

@ -112,7 +112,7 @@ fn test_rewrite(use_git: bool) {
CommitBuilder::for_rewrite_from(&rewrite_settings, &store, &initial_commit) CommitBuilder::for_rewrite_from(&rewrite_settings, &store, &initial_commit)
.set_tree(rewritten_tree.id().clone()) .set_tree(rewritten_tree.id().clone())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
tx.commit(); tx.commit();
assert_eq!(rewritten_commit.parents(), vec![store.root_commit()]); assert_eq!(rewritten_commit.parents(), vec![store.root_commit()]);
assert_eq!( assert_eq!(
@ -173,7 +173,7 @@ fn test_commit_builder_descendants(use_git: bool) {
CommitBuilder::for_new_commit(&settings, &store, store.empty_tree_id().clone()) CommitBuilder::for_new_commit(&settings, &store, store.empty_tree_id().clone())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
// Test with for_open_commit() // Test with for_open_commit()
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
@ -185,15 +185,15 @@ fn test_commit_builder_descendants(use_git: bool) {
) )
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
// Test with for_rewrite_from() // Test with for_rewrite_from()
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
let commit4 = let commit4 =
CommitBuilder::for_rewrite_from(&settings, &store, &commit2).write_to_repo(tx.mut_repo()); CommitBuilder::for_rewrite_from(&settings, &store, &commit2).write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
assert_rebased(rebaser.rebase_next(), &commit3, &[&commit4]); assert_rebased(rebaser.rebase_next().unwrap(), &commit3, &[&commit4]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
// Test with for_rewrite_from() but new change id // Test with for_rewrite_from() but new change id
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
@ -201,5 +201,5 @@ fn test_commit_builder_descendants(use_git: bool) {
.generate_new_change_id() .generate_new_change_id()
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
} }

View File

@ -61,7 +61,7 @@ fn test_commit_parallel(use_git: bool) {
for thread in threads { for thread in threads {
thread.join().ok().unwrap(); thread.join().ok().unwrap();
} }
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
// One commit per thread plus the commit from the initial checkout on top of the // One commit per thread plus the commit from the initial checkout on top of the
// root commit // root commit
assert_eq!(repo.view().heads().len(), num_threads + 1); assert_eq!(repo.view().heads().len(), num_threads + 1);
@ -84,7 +84,7 @@ fn test_commit_parallel_instances(use_git: bool) {
let mut threads = vec![]; let mut threads = vec![];
for _ in 0..num_threads { for _ in 0..num_threads {
let settings = settings.clone(); let settings = settings.clone();
let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
testutils::create_random_commit(&settings, &repo).write_to_repo(tx.mut_repo()); testutils::create_random_commit(&settings, &repo).write_to_repo(tx.mut_repo());
@ -97,7 +97,7 @@ fn test_commit_parallel_instances(use_git: bool) {
} }
// One commit per thread plus the commit from the initial checkout on top of the // One commit per thread plus the commit from the initial checkout on top of the
// root commit // root commit
let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
assert_eq!(repo.view().heads().len(), num_threads + 1); assert_eq!(repo.view().heads().len(), num_threads + 1);
// One addition operation for initializing the repo, one for checking out the // One addition operation for initializing the repo, one for checking out the

View File

@ -74,7 +74,7 @@ fn test_import_refs() {
let git_repo = repo.store().git_repo().unwrap(); let git_repo = repo.store().git_repo().unwrap();
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
let view = repo.view(); let view = repo.view();
@ -160,7 +160,7 @@ fn test_import_refs_reimport() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
// Delete feature1 and rewrite feature2 // Delete feature1 and rewrite feature2
@ -181,7 +181,7 @@ fn test_import_refs_reimport() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
let view = repo.view(); let view = repo.view();
@ -245,7 +245,7 @@ fn test_import_refs_reimport_head_removed() {
let commit = empty_git_commit(&git_repo, "refs/heads/main", &[]); let commit = empty_git_commit(&git_repo, "refs/heads/main", &[]);
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let commit_id = CommitId::from_bytes(commit.id().as_bytes()); let commit_id = CommitId::from_bytes(commit.id().as_bytes());
// Test the setup // Test the setup
assert!(tx.mut_repo().view().heads().contains(&commit_id)); assert!(tx.mut_repo().view().heads().contains(&commit_id));
@ -253,7 +253,7 @@ fn test_import_refs_reimport_head_removed() {
// Remove the head and re-import // Remove the head and re-import
tx.mut_repo().remove_head(&commit_id); tx.mut_repo().remove_head(&commit_id);
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(!tx.mut_repo().view().heads().contains(&commit_id)); assert!(!tx.mut_repo().view().heads().contains(&commit_id));
} }
@ -301,7 +301,9 @@ fn test_import_refs_empty_git_repo() {
let heads_before = test_data.repo.view().heads().clone(); let heads_before = test_data.repo.view().heads().clone();
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap(); git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
let repo = tx.commit(); let repo = tx.commit();
assert_eq!(*repo.view().heads(), heads_before); assert_eq!(*repo.view().heads(), heads_before);
assert_eq!(repo.view().branches().len(), 0); assert_eq!(repo.view().branches().len(), 0);
@ -326,7 +328,9 @@ fn test_import_refs_detached_head() {
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap(); git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
let repo = tx.commit(); let repo = tx.commit();
let expected_heads = hashset! { let expected_heads = hashset! {
@ -349,7 +353,9 @@ fn test_export_refs_initial() {
git_repo.set_head("refs/heads/main").unwrap(); git_repo.set_head("refs/heads/main").unwrap();
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
test_data.repo = tx.commit(); test_data.repo = tx.commit();
// The first export shouldn't do anything // The first export shouldn't do anything
@ -371,7 +377,9 @@ fn test_export_refs_no_op() {
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
test_data.repo = tx.commit(); test_data.repo = tx.commit();
assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(())); assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(()));
@ -398,7 +406,9 @@ fn test_export_refs_branch_changed() {
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
test_data.repo = tx.commit(); test_data.repo = tx.commit();
assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(())); assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(()));
@ -434,7 +444,9 @@ fn test_export_refs_current_branch_changed() {
git_repo.set_head("refs/heads/main").unwrap(); git_repo.set_head("refs/heads/main").unwrap();
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
test_data.repo = tx.commit(); test_data.repo = tx.commit();
assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(())); assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(()));
@ -468,7 +480,9 @@ fn test_export_refs_unborn_git_branch() {
git_repo.set_head("refs/heads/main").unwrap(); git_repo.set_head("refs/heads/main").unwrap();
let mut tx = test_data.repo.start_transaction("test"); let mut tx = test_data.repo.start_transaction("test");
git::import_refs(tx.mut_repo(), &git_repo).unwrap(); git::import_refs(tx.mut_repo(), &git_repo).unwrap();
tx.mut_repo().rebase_descendants(&test_data.settings); tx.mut_repo()
.rebase_descendants(&test_data.settings)
.unwrap();
test_data.repo = tx.commit(); test_data.repo = tx.commit();
assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(())); assert_eq!(git::export_refs(&test_data.repo, &git_repo), Ok(()));

View File

@ -257,7 +257,7 @@ fn test_index_commits_previous_operations(use_git: bool) {
std::fs::remove_dir_all(&index_operations_dir).unwrap(); std::fs::remove_dir_all(&index_operations_dir).unwrap();
std::fs::create_dir(&index_operations_dir).unwrap(); std::fs::create_dir(&index_operations_dir).unwrap();
let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
let index = repo.index(); let index = repo.index();
// There should be the root commit, plus 3 more // There should be the root commit, plus 3 more
assert_eq!(index.num_commits(), 1 + 3); assert_eq!(index.num_commits(), 1 + 3);
@ -302,7 +302,7 @@ fn test_index_commits_incremental(use_git: bool) {
let commit_c = child_commit(&settings, &repo, &commit_b).write_to_repo(tx.mut_repo()); let commit_c = child_commit(&settings, &repo, &commit_b).write_to_repo(tx.mut_repo());
tx.commit(); tx.commit();
let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
let index = repo.index(); let index = repo.index();
// There should be the root commit, plus 3 more // There should be the root commit, plus 3 more
assert_eq!(index.num_commits(), 1 + 3); assert_eq!(index.num_commits(), 1 + 3);
@ -345,7 +345,7 @@ fn test_index_commits_incremental_empty_transaction(use_git: bool) {
repo.start_transaction("test").commit(); repo.start_transaction("test").commit();
let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()); let repo = ReadonlyRepo::load_at_head(&settings, repo.repo_path().clone()).unwrap();
let index = repo.index(); let index = repo.index();
// There should be the root commit, plus 1 more // There should be the root commit, plus 1 more
assert_eq!(index.num_commits(), 1 + 1); assert_eq!(index.num_commits(), 1 + 1);

View File

@ -34,7 +34,7 @@ fn test_load_at_operation(use_git: bool) {
// If we load the repo at head, we should not see the commit since it was // If we load the repo at head, we should not see the commit since it was
// removed // removed
let loader = RepoLoader::init(&settings, repo.repo_path().clone()); let loader = RepoLoader::init(&settings, repo.repo_path().clone());
let head_repo = loader.load_at_head().resolve(&settings); let head_repo = loader.load_at_head().resolve(&settings).unwrap();
assert!(!head_repo.view().heads().contains(commit.id())); assert!(!head_repo.view().heads().contains(commit.id()));
// If we load the repo at the previous operation, we should see the commit since // If we load the repo at the previous operation, we should see the commit since

View File

@ -612,7 +612,7 @@ fn test_simplify_conflict_after_resolving_parent(use_git: bool) {
.set_tree(tree_b3.id().clone()) .set_tree(tree_b3.id().clone())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let commit_c3 = rebase_commit(&settings, tx.mut_repo(), &commit_c2, &[commit_b3]); let commit_c3 = rebase_commit(&settings, tx.mut_repo(), &commit_c2, &[commit_b3]);
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
// The conflict should now be resolved. // The conflict should now be resolved.

View File

@ -97,7 +97,7 @@ fn test_checkout_previous_not_empty(use_git: bool) {
.set_open(true) .set_open(true)
.write_to_repo(mut_repo); .write_to_repo(mut_repo);
mut_repo.check_out(ws_id, &settings, &new_checkout); mut_repo.check_out(ws_id, &settings, &new_checkout);
mut_repo.rebase_descendants(&settings); mut_repo.rebase_descendants(&settings).unwrap();
assert!(mut_repo.view().heads().contains(old_checkout.id())); assert!(mut_repo.view().heads().contains(old_checkout.id()));
} }
@ -129,7 +129,7 @@ fn test_checkout_previous_empty(use_git: bool) {
.set_open(true) .set_open(true)
.write_to_repo(mut_repo); .write_to_repo(mut_repo);
mut_repo.check_out(ws_id, &settings, &new_checkout); mut_repo.check_out(ws_id, &settings, &new_checkout);
mut_repo.rebase_descendants(&settings); mut_repo.rebase_descendants(&settings).unwrap();
assert!(!mut_repo.view().heads().contains(old_checkout.id())); assert!(!mut_repo.view().heads().contains(old_checkout.id()));
} }
@ -168,7 +168,7 @@ fn test_checkout_previous_empty_non_head(use_git: bool) {
.set_open(true) .set_open(true)
.write_to_repo(mut_repo); .write_to_repo(mut_repo);
mut_repo.check_out(ws_id, &settings, &new_checkout); mut_repo.check_out(ws_id, &settings, &new_checkout);
mut_repo.rebase_descendants(&settings); mut_repo.rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
*mut_repo.view().heads(), *mut_repo.view().heads(),
hashset! {old_child.id().clone(), new_checkout.id().clone()} hashset! {old_child.id().clone(), new_checkout.id().clone()}
@ -540,14 +540,15 @@ fn test_rebase_descendants_simple(use_git: bool) {
mut_repo.record_abandoned_commit(commit4.id().clone()); mut_repo.record_abandoned_commit(commit4.id().clone());
let mut rebaser = mut_repo.create_descendant_rebaser(&settings); let mut rebaser = mut_repo.create_descendant_rebaser(&settings);
// Commit 3 got rebased onto commit 2's replacement, i.e. commit 6 // Commit 3 got rebased onto commit 2's replacement, i.e. commit 6
assert_rebased(rebaser.rebase_next(), &commit3, &[&commit6]); assert_rebased(rebaser.rebase_next().unwrap(), &commit3, &[&commit6]);
// Commit 5 got rebased onto commit 4's parent, i.e. commit 1 // Commit 5 got rebased onto commit 4's parent, i.e. commit 1
assert_rebased(rebaser.rebase_next(), &commit5, &[&commit1]); assert_rebased(rebaser.rebase_next().unwrap(), &commit5, &[&commit1]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
// No more descendants to rebase if we try again. // No more descendants to rebase if we try again.
assert!(mut_repo assert!(mut_repo
.create_descendant_rebaser(&settings) .create_descendant_rebaser(&settings)
.rebase_next() .rebase_next()
.unwrap()
.is_none()); .is_none());
} }
@ -577,10 +578,11 @@ fn test_rebase_descendants_conflicting_rewrite(use_git: bool) {
let mut rebaser = mut_repo.create_descendant_rebaser(&settings); let mut rebaser = mut_repo.create_descendant_rebaser(&settings);
// Commit 3 does *not* get rebased because it's unclear if it should go onto // Commit 3 does *not* get rebased because it's unclear if it should go onto
// commit 4 or commit 5 // commit 4 or commit 5
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
// No more descendants to rebase if we try again. // No more descendants to rebase if we try again.
assert!(mut_repo assert!(mut_repo
.create_descendant_rebaser(&settings) .create_descendant_rebaser(&settings)
.rebase_next() .rebase_next()
.unwrap()
.is_none()); .is_none());
} }

View File

@ -68,7 +68,7 @@ fn test_consecutive_operations(use_git: bool) {
assert_ne!(op_id1, op_id0); assert_ne!(op_id1, op_id0);
assert_eq!(list_dir(&op_heads_dir), vec![op_id1.hex()]); assert_eq!(list_dir(&op_heads_dir), vec![op_id1.hex()]);
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let mut tx2 = repo.start_transaction("transaction 2"); let mut tx2 = repo.start_transaction("transaction 2");
testutils::create_random_commit(&settings, &repo).write_to_repo(tx2.mut_repo()); testutils::create_random_commit(&settings, &repo).write_to_repo(tx2.mut_repo());
let op_id2 = tx2.commit().operation().id().clone(); let op_id2 = tx2.commit().operation().id().clone();
@ -78,7 +78,7 @@ fn test_consecutive_operations(use_git: bool) {
// Reloading the repo makes no difference (there are no conflicting operations // Reloading the repo makes no difference (there are no conflicting operations
// to resolve). // to resolve).
let _repo = repo.reload_at_head(&settings); let _repo = repo.reload_at_head(&settings).unwrap();
assert_eq!(list_dir(&op_heads_dir), vec![op_id2.hex()]); assert_eq!(list_dir(&op_heads_dir), vec![op_id2.hex()]);
} }
@ -115,7 +115,7 @@ fn test_concurrent_operations(use_git: bool) {
assert_eq!(actual_heads_on_disk, expected_heads_on_disk); assert_eq!(actual_heads_on_disk, expected_heads_on_disk);
// Reloading the repo causes the operations to be merged // Reloading the repo causes the operations to be merged
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let merged_op_id = repo.op_id().clone(); let merged_op_id = repo.op_id().clone();
assert_ne!(merged_op_id, op_id0); assert_ne!(merged_op_id, op_id0);
assert_ne!(merged_op_id, op_id1); assert_ne!(merged_op_id, op_id1);
@ -154,11 +154,11 @@ fn test_isolation(use_git: bool) {
let rewrite1 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &initial) let rewrite1 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &initial)
.set_description("rewrite1".to_string()) .set_description("rewrite1".to_string())
.write_to_repo(mut_repo1); .write_to_repo(mut_repo1);
mut_repo1.rebase_descendants(&settings); mut_repo1.rebase_descendants(&settings).unwrap();
let rewrite2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &initial) let rewrite2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &initial)
.set_description("rewrite2".to_string()) .set_description("rewrite2".to_string())
.write_to_repo(mut_repo2); .write_to_repo(mut_repo2);
mut_repo2.rebase_descendants(&settings); mut_repo2.rebase_descendants(&settings).unwrap();
// Neither transaction has committed yet, so each transaction sees its own // Neither transaction has committed yet, so each transaction sees its own
// commit. // commit.
@ -175,6 +175,6 @@ fn test_isolation(use_git: bool) {
tx2.commit(); tx2.commit();
assert_heads(repo.as_repo_ref(), vec![initial.id()]); assert_heads(repo.as_repo_ref(), vec![initial.id()]);
// After reload, the base repo sees both rewrites. // After reload, the base repo sees both rewrites.
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
assert_heads(repo.as_repo_ref(), vec![rewrite1.id(), rewrite2.id()]); assert_heads(repo.as_repo_ref(), vec![rewrite1.id(), rewrite2.id()]);
} }

View File

@ -54,10 +54,10 @@ fn test_rebase_descendants_sideways(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_f]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_f]);
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&new_commit_c]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&new_commit_c]);
let new_commit_e = assert_rebased(rebaser.rebase_next(), &commit_e, &[&commit_f]); let new_commit_e = assert_rebased(rebaser.rebase_next().unwrap(), &commit_e, &[&commit_f]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 3); assert_eq!(rebaser.rebased().len(), 3);
assert_eq!( assert_eq!(
@ -111,12 +111,12 @@ fn test_rebase_descendants_forward(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_f]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_f]);
let new_commit_f = assert_rebased(rebaser.rebase_next(), &commit_f, &[&new_commit_d]); let new_commit_f = assert_rebased(rebaser.rebase_next().unwrap(), &commit_f, &[&new_commit_d]);
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&new_commit_f]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&new_commit_f]);
let new_commit_e = assert_rebased(rebaser.rebase_next(), &commit_e, &[&new_commit_d]); let new_commit_e = assert_rebased(rebaser.rebase_next().unwrap(), &commit_e, &[&new_commit_d]);
let new_commit_g = assert_rebased(rebaser.rebase_next(), &commit_g, &[&new_commit_f]); let new_commit_g = assert_rebased(rebaser.rebase_next().unwrap(), &commit_g, &[&new_commit_f]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 5); assert_eq!(rebaser.rebased().len(), 5);
assert_eq!( assert_eq!(
@ -169,8 +169,8 @@ fn test_rebase_descendants_reorder(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_i = assert_rebased(rebaser.rebase_next(), &commit_i, &[&commit_h]); let new_commit_i = assert_rebased(rebaser.rebase_next().unwrap(), &commit_i, &[&commit_h]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -209,8 +209,8 @@ fn test_rebase_descendants_backward(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_b]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_b]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -254,9 +254,9 @@ fn test_rebase_descendants_chain_becomes_branchy(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_f = assert_rebased(rebaser.rebase_next(), &commit_f, &[&commit_e]); let new_commit_f = assert_rebased(rebaser.rebase_next().unwrap(), &commit_f, &[&commit_e]);
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&new_commit_f]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&new_commit_f]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 2); assert_eq!(rebaser.rebased().len(), 2);
assert_eq!( assert_eq!(
@ -301,14 +301,14 @@ fn test_rebase_descendants_internal_merge(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_f]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_f]);
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_f]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_f]);
let new_commit_e = assert_rebased( let new_commit_e = assert_rebased(
rebaser.rebase_next(), rebaser.rebase_next().unwrap(),
&commit_e, &commit_e,
&[&new_commit_c, &new_commit_d], &[&new_commit_c, &new_commit_d],
); );
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 3); assert_eq!(rebaser.rebased().len(), 3);
assert_eq!( assert_eq!(
@ -352,8 +352,12 @@ fn test_rebase_descendants_external_merge(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_e = assert_rebased(rebaser.rebase_next(), &commit_e, &[&commit_f, &commit_d]); let new_commit_e = assert_rebased(
assert!(rebaser.rebase_next().is_none()); rebaser.rebase_next().unwrap(),
&commit_e,
&[&commit_f, &commit_d],
);
assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -393,10 +397,10 @@ fn test_rebase_descendants_abandon(use_git: bool) {
hashmap! {}, hashmap! {},
hashset! {commit_b.id().clone(), commit_e.id().clone()}, hashset! {commit_b.id().clone(), commit_e.id().clone()},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_a]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_a]);
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_a]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_a]);
let new_commit_f = assert_rebased(rebaser.rebase_next(), &commit_f, &[&new_commit_d]); let new_commit_f = assert_rebased(rebaser.rebase_next().unwrap(), &commit_f, &[&new_commit_d]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 3); assert_eq!(rebaser.rebased().len(), 3);
assert_eq!( assert_eq!(
@ -432,7 +436,7 @@ fn test_rebase_descendants_abandon_no_descendants(use_git: bool) {
hashmap! {}, hashmap! {},
hashset! {commit_b.id().clone(), commit_c.id().clone()}, hashset! {commit_b.id().clone(), commit_c.id().clone()},
); );
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 0); assert_eq!(rebaser.rebased().len(), 0);
assert_eq!( assert_eq!(
@ -472,8 +476,8 @@ fn test_rebase_descendants_abandon_and_replace(use_git: bool) {
hashmap! {commit_b.id().clone() => hashset!{commit_e.id().clone()}}, hashmap! {commit_b.id().clone() => hashset!{commit_e.id().clone()}},
hashset! {commit_c.id().clone()}, hashset! {commit_c.id().clone()},
); );
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_e]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_e]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -510,8 +514,8 @@ fn test_rebase_descendants_abandon_degenerate_merge(use_git: bool) {
hashmap! {}, hashmap! {},
hashset! {commit_b.id().clone()}, hashset! {commit_b.id().clone()},
); );
let new_commit_d = assert_rebased(rebaser.rebase_next(), &commit_d, &[&commit_c]); let new_commit_d = assert_rebased(rebaser.rebase_next().unwrap(), &commit_d, &[&commit_c]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -553,11 +557,11 @@ fn test_rebase_descendants_abandon_widen_merge(use_git: bool) {
hashset! {commit_e.id().clone()}, hashset! {commit_e.id().clone()},
); );
let new_commit_f = assert_rebased( let new_commit_f = assert_rebased(
rebaser.rebase_next(), rebaser.rebase_next().unwrap(),
&commit_f, &commit_f,
&[&commit_b, &commit_c, &commit_d], &[&commit_b, &commit_c, &commit_d],
); );
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -599,9 +603,9 @@ fn test_rebase_descendants_multiple_sideways(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_f]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_f]);
let new_commit_e = assert_rebased(rebaser.rebase_next(), &commit_e, &[&commit_f]); let new_commit_e = assert_rebased(rebaser.rebase_next().unwrap(), &commit_e, &[&commit_f]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 2); assert_eq!(rebaser.rebased().len(), 2);
assert_eq!( assert_eq!(
@ -644,9 +648,9 @@ fn test_rebase_descendants_multiple_swap(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_d]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_d]);
let new_commit_e = assert_rebased(rebaser.rebase_next(), &commit_e, &[&commit_b]); let new_commit_e = assert_rebased(rebaser.rebase_next().unwrap(), &commit_e, &[&commit_b]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 2); assert_eq!(rebaser.rebased().len(), 2);
assert_eq!( assert_eq!(
@ -685,7 +689,7 @@ fn test_rebase_descendants_multiple_no_descendants(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert!(rebaser.rebased().is_empty()); assert!(rebaser.rebased().is_empty());
assert_eq!( assert_eq!(
@ -748,9 +752,9 @@ fn test_rebase_descendants_divergent_rewrite(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
let new_commit_c = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_b2]); let new_commit_c = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_b2]);
let new_commit_g = assert_rebased(rebaser.rebase_next(), &commit_g, &[&commit_f2]); let new_commit_g = assert_rebased(rebaser.rebase_next().unwrap(), &commit_g, &[&commit_f2]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 2); assert_eq!(rebaser.rebased().len(), 2);
assert_eq!( assert_eq!(
@ -793,8 +797,8 @@ fn test_rebase_descendants_repeated(use_git: bool) {
.set_description("b2".to_string()) .set_description("b2".to_string())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
let commit_c2 = assert_rebased(rebaser.rebase_next(), &commit_c, &[&commit_b2]); let commit_c2 = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c, &[&commit_b2]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -806,7 +810,7 @@ fn test_rebase_descendants_repeated(use_git: bool) {
// We made no more changes, so nothing should be rebased. // We made no more changes, so nothing should be rebased.
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 0); assert_eq!(rebaser.rebased().len(), 0);
// Now mark B3 as rewritten from B2 and rebase descendants again. // Now mark B3 as rewritten from B2 and rebase descendants again.
@ -814,8 +818,8 @@ fn test_rebase_descendants_repeated(use_git: bool) {
.set_description("b3".to_string()) .set_description("b3".to_string())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings); let mut rebaser = tx.mut_repo().create_descendant_rebaser(&settings);
let commit_c3 = assert_rebased(rebaser.rebase_next(), &commit_c2, &[&commit_b3]); let commit_c3 = assert_rebased(rebaser.rebase_next().unwrap(), &commit_c2, &[&commit_b3]);
assert!(rebaser.rebase_next().is_none()); assert!(rebaser.rebase_next().unwrap().is_none());
assert_eq!(rebaser.rebased().len(), 1); assert_eq!(rebaser.rebased().len(), 1);
assert_eq!( assert_eq!(
@ -871,7 +875,7 @@ fn test_rebase_descendants_contents(use_git: bool) {
}, },
hashset! {}, hashset! {},
); );
rebaser.rebase_all(); rebaser.rebase_all().unwrap();
let rebased = rebaser.rebased(); let rebased = rebaser.rebased();
assert_eq!(rebased.len(), 1); assert_eq!(rebased.len(), 1);
let new_commit_c = repo let new_commit_c = repo
@ -916,7 +920,7 @@ fn test_rebase_descendants_basic_branch_update() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Normal(commit_b2.id().clone())) Some(RefTarget::Normal(commit_b2.id().clone()))
@ -958,7 +962,7 @@ fn test_rebase_descendants_branch_move_two_steps() {
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let commit_c2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_c) let commit_c2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_c)
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let heads = tx.mut_repo().view().heads(); let heads = tx.mut_repo().view().heads();
assert_eq!(heads.len(), 1); assert_eq!(heads.len(), 1);
let c3_id = heads.iter().next().unwrap().clone(); let c3_id = heads.iter().next().unwrap().clone();
@ -1003,7 +1007,7 @@ fn test_rebase_descendants_basic_branch_update_with_non_local_branch() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Normal(commit_b2.id().clone())) Some(RefTarget::Normal(commit_b2.id().clone()))
@ -1048,7 +1052,7 @@ fn test_rebase_descendants_update_branch_after_abandon() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
tx.mut_repo().record_abandoned_commit(commit_b.id().clone()); tx.mut_repo().record_abandoned_commit(commit_b.id().clone());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Normal(commit_a.id().clone())) Some(RefTarget::Normal(commit_a.id().clone()))
@ -1093,7 +1097,7 @@ fn test_rebase_descendants_update_branches_after_divergent_rewrite() {
let commit_b4 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_b4 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.set_description("more different".to_string()) .set_description("more different".to_string())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Conflict { Some(RefTarget::Conflict {
@ -1152,7 +1156,7 @@ fn test_rebase_descendants_rewrite_updates_branch_conflict() {
let commit_b3 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_b3 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.set_description("different".to_string()) .set_description("different".to_string())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Conflict { Some(RefTarget::Conflict {
@ -1208,7 +1212,7 @@ fn test_rebase_descendants_rewrite_resolves_branch_conflict() {
let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_b2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.set_parents(vec![commit_c.id().clone()]) .set_parents(vec![commit_c.id().clone()])
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!( assert_eq!(
tx.mut_repo().get_local_branch("main"), tx.mut_repo().get_local_branch("main"),
Some(RefTarget::Normal(commit_b2.id().clone())) Some(RefTarget::Normal(commit_b2.id().clone()))
@ -1246,7 +1250,7 @@ fn test_rebase_descendants_branch_delete_modify_abandon() {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
tx.mut_repo().record_abandoned_commit(commit_b.id().clone()); tx.mut_repo().record_abandoned_commit(commit_b.id().clone());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
assert_eq!(tx.mut_repo().get_local_branch("main"), None); assert_eq!(tx.mut_repo().get_local_branch("main"), None);
} }
@ -1284,7 +1288,7 @@ fn test_rebase_descendants_update_checkout_open(use_git: bool) {
let commit_c = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b) let commit_c = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_b)
.set_description("C".to_string()) .set_description("C".to_string())
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
// Workspaces 1 and 2 had B checked out, so they get updated to C. Workspace 3 // Workspaces 1 and 2 had B checked out, so they get updated to C. Workspace 3
@ -1329,7 +1333,7 @@ fn test_rebase_descendants_update_checkout_closed(use_git: bool) {
.set_description("C".to_string()) .set_description("C".to_string())
.set_open(false) .set_open(false)
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
// Workspaces 1 and 2 had B checked out, so they get updated to the same new // Workspaces 1 and 2 had B checked out, so they get updated to the same new
@ -1381,7 +1385,7 @@ fn test_rebase_descendants_update_checkout_abandoned_merge(use_git: bool) {
let mut tx = repo.start_transaction("test"); let mut tx = repo.start_transaction("test");
tx.mut_repo().record_abandoned_commit(commit_d.id().clone()); tx.mut_repo().record_abandoned_commit(commit_d.id().clone());
tx.mut_repo().rebase_descendants(&settings); tx.mut_repo().rebase_descendants(&settings).unwrap();
let repo = tx.commit(); let repo = tx.commit();
let new_checkout_id = repo.view().get_checkout(&workspace_id).unwrap(); let new_checkout_id = repo.view().get_checkout(&workspace_id).unwrap();

View File

@ -127,7 +127,7 @@ fn test_merge_views_heads() {
tx2.mut_repo().add_public_head(&public_head_add_tx2); tx2.mut_repo().add_public_head(&public_head_add_tx2);
tx2.commit(); tx2.commit();
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let expected_heads = hashset! { let expected_heads = hashset! {
head_unchanged.id().clone(), head_unchanged.id().clone(),
@ -221,7 +221,7 @@ fn test_merge_views_checkout() {
std::thread::sleep(std::time::Duration::from_millis(1)); std::thread::sleep(std::time::Duration::from_millis(1));
tx2.commit(); tx2.commit();
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
// We currently arbitrarily pick the first transaction's checkout (first by // We currently arbitrarily pick the first transaction's checkout (first by
// transaction end time). // transaction end time).
@ -308,7 +308,7 @@ fn test_merge_views_branches() {
); );
tx2.commit(); tx2.commit();
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let expected_main_branch = BranchTarget { let expected_main_branch = BranchTarget {
local_target: Some(RefTarget::Conflict { local_target: Some(RefTarget::Conflict {
removes: vec![main_branch_local_tx0.id().clone()], removes: vec![main_branch_local_tx0.id().clone()],
@ -366,7 +366,7 @@ fn test_merge_views_tags() {
.set_tag("v1.0".to_string(), RefTarget::Normal(v1_tx2.id().clone())); .set_tag("v1.0".to_string(), RefTarget::Normal(v1_tx2.id().clone()));
tx2.commit(); tx2.commit();
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let expected_v1 = RefTarget::Conflict { let expected_v1 = RefTarget::Conflict {
removes: vec![v1_tx0.id().clone()], removes: vec![v1_tx0.id().clone()],
adds: vec![v1_tx1.id().clone(), v1_tx2.id().clone()], adds: vec![v1_tx1.id().clone(), v1_tx2.id().clone()],
@ -428,7 +428,7 @@ fn test_merge_views_git_refs() {
); );
tx2.commit(); tx2.commit();
let repo = repo.reload_at_head(&settings); let repo = repo.reload_at_head(&settings).unwrap();
let expected_main_branch = RefTarget::Conflict { let expected_main_branch = RefTarget::Conflict {
removes: vec![main_branch_tx0.id().clone()], removes: vec![main_branch_tx0.id().clone()],
adds: vec![main_branch_tx1.id().clone(), main_branch_tx2.id().clone()], adds: vec![main_branch_tx1.id().clone(), main_branch_tx2.id().clone()],
@ -450,7 +450,7 @@ fn commit_transactions(settings: &UserSettings, txs: Vec<Transaction>) -> Arc<Re
op_ids.push(tx.commit().op_id().clone()); op_ids.push(tx.commit().op_id().clone());
std::thread::sleep(std::time::Duration::from_millis(1)); std::thread::sleep(std::time::Duration::from_millis(1));
} }
let repo = repo_loader.load_at_head().resolve(settings); let repo = repo_loader.load_at_head().resolve(settings).unwrap();
// Test the setup. The assumption here is that the parent order matches the // Test the setup. The assumption here is that the parent order matches the
// order in which they were merged (which currently matches the transaction // order in which they were merged (which currently matches the transaction
// commit order), so we want to know make sure they appear in a certain // commit order), so we want to know make sure they appear in a certain
@ -482,7 +482,7 @@ fn test_merge_views_child_on_rewritten(child_first: bool) {
let commit_a2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_a) let commit_a2 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_a)
.set_description("A2".to_string()) .set_description("A2".to_string())
.write_to_repo(tx2.mut_repo()); .write_to_repo(tx2.mut_repo());
tx2.mut_repo().rebase_descendants(&settings); tx2.mut_repo().rebase_descendants(&settings).unwrap();
let repo = if child_first { let repo = if child_first {
commit_transactions(&settings, vec![tx1, tx2]) commit_transactions(&settings, vec![tx1, tx2])
@ -529,7 +529,7 @@ fn test_merge_views_child_on_rewritten_divergent(on_rewritten: bool, child_first
let commit_a4 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_a2) let commit_a4 = CommitBuilder::for_rewrite_from(&settings, repo.store(), &commit_a2)
.set_description("A4".to_string()) .set_description("A4".to_string())
.write_to_repo(tx2.mut_repo()); .write_to_repo(tx2.mut_repo());
tx2.mut_repo().rebase_descendants(&settings); tx2.mut_repo().rebase_descendants(&settings).unwrap();
let repo = if child_first { let repo = if child_first {
commit_transactions(&settings, vec![tx1, tx2]) commit_transactions(&settings, vec![tx1, tx2])
@ -579,7 +579,7 @@ fn test_merge_views_child_on_abandoned(child_first: bool) {
let mut tx2 = repo.start_transaction("test"); let mut tx2 = repo.start_transaction("test");
tx2.mut_repo() tx2.mut_repo()
.record_abandoned_commit(commit_b.id().clone()); .record_abandoned_commit(commit_b.id().clone());
tx2.mut_repo().rebase_descendants(&settings); tx2.mut_repo().rebase_descendants(&settings).unwrap();
let repo = if child_first { let repo = if child_first {
commit_transactions(&settings, vec![tx1, tx2]) commit_transactions(&settings, vec![tx1, tx2])

View File

@ -240,7 +240,7 @@ jj init --git-repo=.";
let mut tx = workspace_command.start_transaction("resolve concurrent operations"); let mut tx = workspace_command.start_transaction("resolve concurrent operations");
for other_op_head in op_heads.into_iter().skip(1) { for other_op_head in op_heads.into_iter().skip(1) {
tx.merge_operation(other_op_head); tx.merge_operation(other_op_head);
let num_rebased = tx.mut_repo().rebase_descendants(ui.settings()); let num_rebased = tx.mut_repo().rebase_descendants(ui.settings())?;
if num_rebased > 0 { if num_rebased > 0 {
writeln!( writeln!(
ui, ui,
@ -347,7 +347,7 @@ impl WorkspaceCommandHelper {
// so we just need to reset our working copy state to it without updating // so we just need to reset our working copy state to it without updating
// working copy files. // working copy files.
locked_working_copy.reset(&new_checkout.tree())?; locked_working_copy.reset(&new_checkout.tree())?;
tx.mut_repo().rebase_descendants(&self.settings); tx.mut_repo().rebase_descendants(&self.settings)?;
self.repo = tx.commit(); self.repo = tx.commit();
locked_working_copy.finish(self.repo.op_id().clone()); locked_working_copy.finish(self.repo.op_id().clone());
} else { } else {
@ -654,7 +654,7 @@ impl WorkspaceCommandHelper {
mut_repo.set_checkout(workspace_id, commit.id().clone()); mut_repo.set_checkout(workspace_id, commit.id().clone());
// Rebase descendants // Rebase descendants
let num_rebased = mut_repo.rebase_descendants(&self.settings); let num_rebased = mut_repo.rebase_descendants(&self.settings)?;
if num_rebased > 0 { if num_rebased > 0 {
writeln!( writeln!(
ui, ui,
@ -758,7 +758,7 @@ impl WorkspaceCommandHelper {
writeln!(ui, "Nothing changed.")?; writeln!(ui, "Nothing changed.")?;
return Ok(()); return Ok(());
} }
let num_rebased = mut_repo.rebase_descendants(ui.settings()); let num_rebased = mut_repo.rebase_descendants(ui.settings())?;
if num_rebased > 0 { if num_rebased > 0 {
writeln!(ui, "Rebased {} descendant commits", num_rebased)?; writeln!(ui, "Rebased {} descendant commits", num_rebased)?;
} }
@ -2107,7 +2107,7 @@ fn cmd_untrack(
CommitBuilder::for_rewrite_from(ui.settings(), &store, &current_checkout) CommitBuilder::for_rewrite_from(ui.settings(), &store, &current_checkout)
.set_tree(new_tree_id) .set_tree(new_tree_id)
.write_to_repo(tx.mut_repo()); .write_to_repo(tx.mut_repo());
let num_rebased = tx.mut_repo().rebase_descendants(ui.settings()); let num_rebased = tx.mut_repo().rebase_descendants(ui.settings())?;
if num_rebased > 0 { if num_rebased > 0 {
writeln!(ui, "Rebased {} descendant commits", num_rebased)?; writeln!(ui, "Rebased {} descendant commits", num_rebased)?;
} }
@ -3273,7 +3273,7 @@ fn cmd_abandon(
for commit in to_abandon { for commit in to_abandon {
tx.mut_repo().record_abandoned_commit(commit.id().clone()); tx.mut_repo().record_abandoned_commit(commit.id().clone());
} }
let num_rebased = tx.mut_repo().rebase_descendants(ui.settings()); let num_rebased = tx.mut_repo().rebase_descendants(ui.settings())?;
if num_rebased > 0 { if num_rebased > 0 {
writeln!( writeln!(
ui, ui,
@ -3373,7 +3373,7 @@ from the source will be moved into the destination.
// changes we're moving, so applying them will have no effect and the // changes we're moving, so applying them will have no effect and the
// changes will disappear. // changes will disappear.
let mut rebaser = mut_repo.create_descendant_rebaser(ui.settings()); let mut rebaser = mut_repo.create_descendant_rebaser(ui.settings());
rebaser.rebase_all(); rebaser.rebase_all()?;
let rebased_destination_id = rebaser.rebased().get(destination.id()).unwrap().clone(); let rebased_destination_id = rebaser.rebased().get(destination.id()).unwrap().clone();
destination = mut_repo.store().get_commit(&rebased_destination_id)?; destination = mut_repo.store().get_commit(&rebased_destination_id)?;
} }
@ -3687,7 +3687,7 @@ any changes, then the operation will be aborted.
hashmap! { commit.id().clone() => hashset!{second_commit.id().clone()} }, hashmap! { commit.id().clone() => hashset!{second_commit.id().clone()} },
hashset! {}, hashset! {},
); );
rebaser.rebase_all(); rebaser.rebase_all()?;
let num_rebased = rebaser.rebased().len(); let num_rebased = rebaser.rebased().len();
if num_rebased > 0 { if num_rebased > 0 {
writeln!(ui, "Rebased {} descendant commits", num_rebased)?; writeln!(ui, "Rebased {} descendant commits", num_rebased)?;
@ -3802,7 +3802,7 @@ fn rebase_branch(
rebase_commit(ui.settings(), tx.mut_repo(), &root_commit, new_parents); rebase_commit(ui.settings(), tx.mut_repo(), &root_commit, new_parents);
num_rebased += 1; num_rebased += 1;
} }
num_rebased += tx.mut_repo().rebase_descendants(ui.settings()); num_rebased += tx.mut_repo().rebase_descendants(ui.settings())?;
writeln!(ui, "Rebased {} commits", num_rebased)?; writeln!(ui, "Rebased {} commits", num_rebased)?;
workspace_command.finish_transaction(ui, tx)?; workspace_command.finish_transaction(ui, tx)?;
Ok(()) Ok(())
@ -3822,7 +3822,7 @@ fn rebase_descendants(
old_commit.id().hex() old_commit.id().hex()
)); ));
rebase_commit(ui.settings(), tx.mut_repo(), &old_commit, new_parents); rebase_commit(ui.settings(), tx.mut_repo(), &old_commit, new_parents);
let num_rebased = tx.mut_repo().rebase_descendants(ui.settings()) + 1; let num_rebased = tx.mut_repo().rebase_descendants(ui.settings())? + 1;
writeln!(ui, "Rebased {} commits", num_rebased)?; writeln!(ui, "Rebased {} commits", num_rebased)?;
workspace_command.finish_transaction(ui, tx)?; workspace_command.finish_transaction(ui, tx)?;
Ok(()) Ok(())
@ -3863,7 +3863,7 @@ fn rebase_revision(
); );
num_rebased_descendants += 1; num_rebased_descendants += 1;
} }
num_rebased_descendants += tx.mut_repo().rebase_descendants(ui.settings()); num_rebased_descendants += tx.mut_repo().rebase_descendants(ui.settings())?;
if num_rebased_descendants > 0 { if num_rebased_descendants > 0 {
writeln!( writeln!(
ui, ui,