Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/examples/custom-command/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ async fn run_custom_command(
let new_commit = tx
.repo_mut()
.rewrite_commit(&commit)
.await
.set_description("Frobnicated!")
.write()
.await?;
Expand Down
1 change: 1 addition & 0 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1984,6 +1984,7 @@ to the current parents may contain changes from multiple commits.
let mut_repo = tx.repo_mut();
let commit = mut_repo
.rewrite_commit(&wc_commit)
.await
.set_tree(new_tree.clone())
.write()
.await
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/abandon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub(crate) async fn cmd_abandon(
if to_abandon.contains(rewriter.old_commit().id()) {
rewriter.abandon();
} else if args.restore_descendants {
rewriter.reparent().write().await?;
rewriter.reparent().await.write().await?;
num_rebased += 1;
} else {
rewriter.rebase().await?.write().await?;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ new working-copy commit.
)?;
}

let mut commit_builder = tx.repo_mut().rewrite_commit(&commit).detach();
let mut commit_builder = tx.repo_mut().rewrite_commit(&commit).await.detach();
commit_builder.set_tree(tree);
if args.reset_author {
commit_builder.set_author(commit_builder.committer().clone());
Expand Down
44 changes: 21 additions & 23 deletions cli/src/commands/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,28 +200,26 @@ pub(crate) async fn cmd_describe(
.map(join_message_paragraphs)
};

let mut commit_builders = commits
.iter()
.map(|commit| {
let mut commit_builder = tx.repo_mut().rewrite_commit(commit).detach();
if let Some(description) = &shared_description {
commit_builder.set_description(description);
}
if args.reset_author {
let new_author = commit_builder.committer().clone();
commit_builder.set_author(new_author);
}
if let Some((name, email)) = args.author.clone() {
let new_author = Signature {
name,
email,
timestamp: commit_builder.author().timestamp,
};
commit_builder.set_author(new_author);
}
commit_builder
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work to still call .map() but with an async closure and then wrap the whole think in try_join_all()? We've done that in lots of other places. It would mean that the commits are written concurrently if the backend supports it.

Copy link
Contributor

@ilyagr ilyagr Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Non-actionable, also mostly just wrong) I only glanced at this, but it sounds a bit similar to what I'm doing in #9087 maybe: create a stream of futures, and then convert it into a stream of outputs of these futures via .buffered.

I am not sure I whole-heatedly recommend it at this point, it does seem to add complexity.

Update: I think I misunderstood what Martin said as I started writing this. I'll leave it here, I think the analogy is interesting, but it's less actionable than Martin's comment.

Update 2: The approach of #9087 is not useful here, since you don't need streaming. You need to wait to get all the values before you can do anything with them.

.collect_vec();
let mut commit_builders = Vec::with_capacity(commits.len());
for commit in &commits {
let mut commit_builder = tx.repo_mut().rewrite_commit(commit).await.detach();
if let Some(description) = &shared_description {
commit_builder.set_description(description);
}
if args.reset_author {
let new_author = commit_builder.committer().clone();
commit_builder.set_author(new_author);
}
if let Some((name, email)) = args.author.clone() {
let new_author = Signature {
name,
email,
timestamp: commit_builder.author().timestamp,
};
commit_builder.set_author(new_author);
}
commit_builders.push(commit_builder);
}

let use_editor = args.editor || args.edit || (shared_description.is_none() && !args.no_edit);

Expand Down Expand Up @@ -320,7 +318,7 @@ pub(crate) async fn cmd_describe(
commit_builders.keys().map(|&id| id.clone()).collect(),
async |rewriter| {
let old_commit_id = rewriter.old_commit().id().clone();
let commit_builder = rewriter.reparent();
let commit_builder = rewriter.reparent().await;
if let Some(temp_builder) = commit_builders.get(&old_commit_id) {
commit_builder
.set_description(temp_builder.description())
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/diffedit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ don't make any changes, then the operation will be aborted.",
} else {
tx.repo_mut()
.rewrite_commit(&target_commit)
.await
.set_tree(edited_tree)
.write()
.await?;
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/file/chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub(crate) async fn cmd_file_chmod(
let new_tree = tree_builder.write_tree().await?;
tx.repo_mut()
.rewrite_commit(&commit)
.await
.set_tree(new_tree)
.write()
.await?;
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/file/untrack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub(crate) async fn cmd_file_untrack(
let new_commit = tx
.repo_mut()
.rewrite_commit(&wc_commit)
.await
.set_tree(new_tree)
.write()
.await?;
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/gerrit/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ pub async fn cmd_gerrit_upload(
let new_commit = tx
.repo_mut()
.rewrite_commit(&original_commit)
.await
.set_description(new_description)
.set_parents(new_parents)
// Set the timestamp back to the timestamp of the original commit.
Expand Down
3 changes: 2 additions & 1 deletion cli/src/commands/git/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,13 +627,14 @@ async fn sign_commits_before_push(
if commit_ids.contains(&old_commit_id) {
let commit = rewriter
.reparent()
.await
.set_sign_behavior(sign_behavior)
.write()
.await?;
old_to_new_commits_map.insert(old_commit_id, commit.id().clone());
} else {
num_rebased_descendants += 1;
let commit = rewriter.reparent().write().await?;
let commit = rewriter.reparent().await.write().await?;
old_to_new_commits_map.insert(old_commit_id, commit.id().clone());
}
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/metaedit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ pub(crate) async fn cmd_metaedit(
|| rewriter.parents_changed();

let old_author = rewriter.old_commit().author().clone();
let mut commit_builder = rewriter.reparent();
let mut commit_builder = rewriter.reparent().await;
let mut new_author = commit_builder.author().clone();
if let Some((name, email)) = args.author.clone() {
new_author.name = name;
Expand Down Expand Up @@ -253,7 +253,7 @@ pub(crate) async fn cmd_metaedit(
modified.push(new_commit);
}
} else if rewriter.parents_changed() {
rewriter.reparent().write().await?;
rewriter.reparent().await.write().await?;
num_reparented += 1;
}
Ok(())
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub(crate) async fn cmd_resolve(
let new_commit = tx
.repo_mut()
.rewrite_commit(&commit)
.await
.set_tree(new_tree)
.write()
.await?;
Expand Down
1 change: 1 addition & 0 deletions cli/src/commands/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ pub(crate) async fn cmd_restore(
let mut tx = workspace_command.start_transaction();
tx.repo_mut()
.rewrite_commit(&to_commit)
.await
.set_tree(new_tree)
.write()
.await?;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub async fn cmd_sign(
to_sign.iter().ids().cloned().collect_vec(),
async |rewriter| {
let old_commit = rewriter.old_commit().clone();
let mut commit_builder = rewriter.reparent();
let mut commit_builder = rewriter.reparent().await;

if let Some(writer) = &mut progress_writer {
writer
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/simplify_parents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) async fn cmd_simplify_parents(
let num_new_heads = rewriter.new_parents().len();

if rewriter.parents_changed() {
rewriter.reparent().write().await?;
rewriter.reparent().await.write().await?;

if num_new_heads < num_old_heads {
simplified_commits += 1;
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ pub(crate) async fn cmd_split(

// Create the first commit, which includes the changes selected by the user.
let first_commit = {
let mut commit_builder = tx.repo_mut().rewrite_commit(&target.commit).detach();
let mut commit_builder = tx.repo_mut().rewrite_commit(&target.commit).await.detach();
commit_builder.set_tree(target.selected_tree.clone());
if use_move_flags {
commit_builder.clear_rewrite_source();
Expand Down Expand Up @@ -356,7 +356,7 @@ pub(crate) async fn cmd_split(
} else {
vec![first_commit.id().clone()]
};
let mut commit_builder = tx.repo_mut().rewrite_commit(&target.commit).detach();
let mut commit_builder = tx.repo_mut().rewrite_commit(&target.commit).await.detach();
commit_builder.set_parents(parents).set_tree(new_tree);
let mut show_editor = args.editor;
if !use_move_flags {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/unsign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub async fn cmd_unsign(
to_unsign.iter().ids().cloned().collect_vec(),
async |rewriter| {
let old_commit = rewriter.old_commit().clone();
let commit_builder = rewriter.reparent();
let commit_builder = rewriter.reparent().await;

if to_unsign.contains(&old_commit) {
let new_commit = commit_builder
Expand Down
38 changes: 20 additions & 18 deletions cli/src/merge_tools/diff_working_copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,28 +146,30 @@ pub(crate) async fn check_out_trees(
let temp_path = temp_dir.path();

// Checkout a tree into our temp directory with the given prefix.
let check_out = |name: &str, tree| -> Result<TreeState, DiffCheckoutError> {
let wc_path = temp_path.join(name);
let state_dir = temp_path.join(format!("{name}_state"));
std::fs::create_dir(&wc_path).map_err(DiffCheckoutError::SetUpDir)?;
std::fs::create_dir(&state_dir).map_err(DiffCheckoutError::SetUpDir)?;
let tree_state_settings = TreeStateSettings {
conflict_marker_style,
eol_conversion_mode: EolConversionMode::None,
exec_change_setting: ExecChangeSetting::Auto,
fsmonitor_settings: FsmonitorSettings::None,
let check_out =
async |name: &str, tree| -> Result<TreeState, DiffCheckoutError> {
let wc_path = temp_path.join(name);
let state_dir = temp_path.join(format!("{name}_state"));
std::fs::create_dir(&wc_path).map_err(DiffCheckoutError::SetUpDir)?;
std::fs::create_dir(&state_dir).map_err(DiffCheckoutError::SetUpDir)?;
let tree_state_settings = TreeStateSettings {
conflict_marker_style,
eol_conversion_mode: EolConversionMode::None,
exec_change_setting: ExecChangeSetting::Auto,
fsmonitor_settings: FsmonitorSettings::None,
};
let mut state =
TreeState::init(store.clone(), wc_path, state_dir, &tree_state_settings)?;
state.set_sparse_patterns(changed_files.clone()).await?;
state.check_out(tree).await?;
Ok(state)
};
let mut state = TreeState::init(store.clone(), wc_path, state_dir, &tree_state_settings)?;
state.set_sparse_patterns(changed_files.clone())?;
state.check_out(tree)?;
Ok(state)
};

let left = check_out("left", trees.before)?;
let right = check_out("right", trees.after)?;
let left = check_out("left", trees.before).await?;
let right = check_out("right", trees.after).await?;
let output = match diff_type {
DiffType::TwoWay => None,
DiffType::ThreeWay => Some(check_out("output", trees.after)?),
DiffType::ThreeWay => Some(check_out("output", trees.after).await?),
};
Ok(DiffWorkingCopies {
_temp_dir: temp_dir,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/absorb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ pub async fn absorb_hunks(
repo.transform_descendants(selected_trees.keys().cloned().collect(), async |rewriter| {
// Remove selected hunks from the source commit by reparent()
if rewriter.old_commit().id() == source.commit.id() {
let commit_builder = rewriter.reparent();
let commit_builder = rewriter.reparent().await;
if commit_builder.is_discardable().await? {
commit_builder.abandon();
} else {
Expand Down
6 changes: 2 additions & 4 deletions lib/src/commit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

use std::sync::Arc;

use pollster::FutureExt as _;

use crate::backend;
use crate::backend::BackendError;
use crate::backend::BackendResult;
Expand Down Expand Up @@ -224,7 +222,7 @@ impl DetachedCommitBuilder {

/// Only called from [`MutableRepo::rewrite_commit`]. Use that function
/// instead.
pub(crate) fn for_rewrite_from(
pub(crate) async fn for_rewrite_from(
repo: &dyn Repo,
settings: &UserSettings,
predecessor: &Commit,
Expand All @@ -249,7 +247,7 @@ impl DetachedCommitBuilder {
&& commit.author.email == commit.committer.email
&& predecessor
.is_discardable(repo)
.block_on()
.await
.unwrap_or_default()
{
commit.author.timestamp = commit.committer.timestamp;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,13 @@ pub async fn fix_files(
if has_changes {
summary.num_fixed_commits += 1;
let new_tree = tree_builder.write_tree().await?;
let builder = rewriter.reparent();
let builder = rewriter.reparent().await;
let new_commit = builder.set_tree(new_tree).write().await?;
summary
.rewrites
.insert(old_commit_id, new_commit.id().clone());
} else if rewriter.parents_changed() {
let new_commit = rewriter.reparent().write().await?;
let new_commit = rewriter.reparent().await.write().await?;
summary
.rewrites
.insert(old_commit_id, new_commit.id().clone());
Expand Down
18 changes: 11 additions & 7 deletions lib/src/local_working_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2127,16 +2127,19 @@ impl TreeState {
.map_err(|err| checkout_error_for_mtime_out_of_range(err, disk_path))
}

pub fn check_out(&mut self, new_tree: &MergedTree) -> Result<CheckoutStats, CheckoutError> {
pub async fn check_out(
&mut self,
new_tree: &MergedTree,
) -> Result<CheckoutStats, CheckoutError> {
let old_tree = self.tree.clone();
let stats = self
.update(&old_tree, new_tree, self.sparse_matcher().as_ref())
.block_on()?;
.await?;
self.tree = new_tree.clone();
Ok(stats)
}

pub fn set_sparse_patterns(
pub async fn set_sparse_patterns(
&mut self,
sparse_patterns: Vec<RepoPathBuf>,
) -> Result<CheckoutStats, CheckoutError> {
Expand All @@ -2146,10 +2149,10 @@ impl TreeState {
let added_matcher = DifferenceMatcher::new(&new_matcher, &old_matcher);
let removed_matcher = DifferenceMatcher::new(&old_matcher, &new_matcher);
let empty_tree = self.store.empty_merged_tree();
let added_stats = self.update(&empty_tree, &tree, &added_matcher).block_on()?;
let added_stats = self.update(&empty_tree, &tree, &added_matcher).await?;
let removed_stats = self
.update(&tree, &empty_tree, &removed_matcher)
.block_on()?;
.await?;
self.sparse_patterns = sparse_patterns;
assert_eq!(added_stats.updated_files, 0);
assert_eq!(added_stats.removed_files, 0);
Expand Down Expand Up @@ -2797,7 +2800,7 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
let new_tree = commit.tree();
let tree_state = self.wc.tree_state_mut()?;
if tree_state.tree.tree_ids_and_labels() != new_tree.tree_ids_and_labels() {
let stats = tree_state.check_out(&new_tree)?;
let stats = tree_state.check_out(&new_tree).await?;
self.tree_state_dirty = true;
Ok(stats)
} else {
Expand Down Expand Up @@ -2836,7 +2839,8 @@ impl LockedWorkingCopy for LockedLocalWorkingCopy {
let stats = self
.wc
.tree_state_mut()?
.set_sparse_patterns(new_sparse_patterns)?;
.set_sparse_patterns(new_sparse_patterns)
.await?;
self.tree_state_dirty = true;
Ok(stats)
}
Expand Down
8 changes: 5 additions & 3 deletions lib/src/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,9 +964,11 @@ impl MutableRepo {
}

/// Returns a [`CommitBuilder`] to rewrite an existing commit in the repo.
pub fn rewrite_commit(&mut self, predecessor: &Commit) -> CommitBuilder<'_> {
pub async fn rewrite_commit(&mut self, predecessor: &Commit) -> CommitBuilder<'_> {
let settings = self.base_repo.settings();
DetachedCommitBuilder::for_rewrite_from(self, settings, predecessor).attach(self)
DetachedCommitBuilder::for_rewrite_from(self, settings, predecessor)
.await
.attach(self)
// CommitBuilder::write will record the rewrite in
// `self.rewritten_commits`
}
Expand Down Expand Up @@ -1466,7 +1468,7 @@ impl MutableRepo {
let mut num_reparented = 0;
self.transform_descendants(roots, async |rewriter| {
if rewriter.parents_changed() {
let builder = rewriter.reparent();
let builder = rewriter.reparent().await;
builder.write().await?;
num_reparented += 1;
}
Expand Down
Loading
Loading