process merge-bases in the background

This way, only the first branch has to wait, all further branches will
likely have their merge-base already computed then.
This commit is contained in:
Sebastian Thiel 2024-08-21 19:28:25 +02:00
parent bdd109047e
commit fcafaec2be
No known key found for this signature in database
GPG Key ID: 9CB5EE7895E8268B

View File

@ -426,7 +426,6 @@ pub fn get_branch_listing_details(
.map(TryInto::try_into) .map(TryInto::try_into)
.filter_map(Result::ok) .filter_map(Result::ok)
.collect(); .collect();
let git2_repo = ctx.repository();
let repo = ctx.gix_repository_minimal()?.for_tree_diffing()?; let repo = ctx.gix_repository_minimal()?.for_tree_diffing()?;
let branches = list_branches(ctx, None, Some(branch_names))?; let branches = list_branches(ctx, None, Some(branch_names))?;
@ -453,7 +452,7 @@ pub fn get_branch_listing_details(
}; };
let mut enriched_branches = Vec::new(); let mut enriched_branches = Vec::new();
let diffstats = { let (diffstats, merge_bases) = {
let (start, start_rx) = std::sync::mpsc::channel::<( let (start, start_rx) = std::sync::mpsc::channel::<(
std::sync::mpsc::Receiver<gix::object::tree::diff::ChangeDetached>, std::sync::mpsc::Receiver<gix::object::tree::diff::ChangeDetached>,
std::sync::mpsc::Sender<(usize, usize, usize)>, std::sync::mpsc::Sender<(usize, usize, usize)>,
@ -492,17 +491,45 @@ pub fn get_branch_listing_details(
Ok(()) Ok(())
} }
})?; })?;
for branch in branches {
let other_branch_commit_id = if let Some(virtual_branch) = branch.virtual_branch { let all_other_branch_commit_ids: Vec<_> = branches
if virtual_branch.in_workspace { .iter()
default_target_seen_at_last_update .map(|branch| {
} else { (
default_target_current_upstream_commit_id branch
.virtual_branch
.as_ref()
.and_then(|vb| {
vb.in_workspace
.then_some(default_target_seen_at_last_update)
})
.unwrap_or(default_target_current_upstream_commit_id),
branch.head,
)
})
.collect();
let (merge_tx, merge_rx) = std::sync::mpsc::channel();
let merge_bases = std::thread::Builder::new()
.name("gitbutler-mergebases".into())
.spawn({
let git_dir = ctx.repository().path().to_owned();
move || -> anyhow::Result<()> {
let git2_repo = git2::Repository::open(git_dir)?;
for (other_branch_commit_id, branch_head) in all_other_branch_commit_ids {
// TODO(ST): use `gix` for two-way mergebases.
let base = git2_repo
.merge_base(other_branch_commit_id, branch_head)
.ok();
if merge_tx.send(base).is_err() {
break;
}
}
Ok(())
} }
} else { })?;
default_target_current_upstream_commit_id
}; for branch in branches {
let Ok(base) = git2_repo.merge_base(other_branch_commit_id, branch.head) else { let Some(base) = merge_rx.recv()? else {
continue; continue;
}; };
@ -556,9 +583,10 @@ pub fn get_branch_listing_details(
}; };
enriched_branches.push(branch_data); enriched_branches.push(branch_data);
} }
diffstats (diffstats, merge_bases)
}; };
diffstats.join().expect("no panic")?; diffstats.join().expect("no panic")?;
merge_bases.join().expect("no panic")?;
Ok(enriched_branches) Ok(enriched_branches)
} }