Skip to content

Commit b5268ff

Browse files
committed
backend: use workspace commit state for integration checks and remove git2 usage
Refactor upstream integration logic to remove direct git2 repo traversal and instead rely on gix and workspace-provided commit state. Changes in crates/gitbutler-branch-actions/src/upstream_integration.rs: - Removed usage of git2::Repository and IsCommitIntegrated checks that relied on git2 traversal. - Introduced std::collections::HashMap to map commit ids to workspace commits. - Use branch.commits first item to determine empty branches and map integrated state from but_workspace::ui::CommitState::Integrated. - Cleaned up duplicated logic and removed unnecessary gix/git2 based graph and upstream commit computations. - Built a commit_map of commits from details.branch_details for quick lookup when deciding if a commit is integrated. These changes adjust integration checks to use in-memory workspace state instead of git2 interactions, and handle empty branches more robustly.
1 parent 4367a49 commit b5268ff

File tree

2 files changed

+29
-80
lines changed

2 files changed

+29
-80
lines changed

crates/gitbutler-branch-actions/src/upstream_integration.rs

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::{r#virtual::IsCommitIntegrated, BranchManagerExt, VirtualBranchesExt as _};
1+
use std::collections::HashMap;
2+
3+
use crate::{BranchManagerExt, VirtualBranchesExt as _};
24
use anyhow::{anyhow, bail, Context, Result};
35
use bstr::ByteSlice;
46
use but_core::Reference;
@@ -264,30 +266,11 @@ fn stack_details(
264266
/// Takes both a gix and git2 repository. The git2 repository can't be in
265267
/// memory as the gix repository needs to be able to access those commits
266268
fn get_stack_status(
267-
repo: &git2::Repository,
268269
gix_repo: &gix::Repository,
269-
target: Target,
270270
new_target_commit_id: gix::ObjectId,
271271
stack_id: Option<StackId>,
272272
ctx: &CommandContext,
273273
) -> Result<StackStatus> {
274-
let cache = gix_repo.commit_graph_if_enabled()?;
275-
let mut graph = gix_repo.revision_graph(cache.as_ref());
276-
let upstream_commit_oids = repo.l(
277-
gix_to_git2_oid(new_target_commit_id),
278-
LogUntil::Commit(target.sha),
279-
true,
280-
)?;
281-
let new_target_tree_id = gix_repo.find_commit(new_target_commit_id)?.tree_id()?;
282-
let mut check_commit = IsCommitIntegrated::new_basic(
283-
gix_repo,
284-
repo,
285-
&mut graph,
286-
git2_to_gix_object_id(target.sha),
287-
new_target_tree_id.detach(),
288-
upstream_commit_oids,
289-
);
290-
291274
let mut unintegrated_branch_found = false;
292275

293276
let mut last_head: git2::Oid = gix_to_git2_oid(new_target_commit_id);
@@ -298,10 +281,25 @@ fn get_stack_status(
298281

299282
let branches = details.branch_details;
300283
for branch in &branches {
301-
let branch_head = repo.find_commit(branch.tip.to_git2())?;
284+
let local_commits = &branch.commits;
285+
286+
let Some(branch_head) = local_commits.first() else {
287+
branch_statuses.push(NameAndStatus {
288+
name: branch.name.to_string(),
289+
status: BranchStatus::Empty,
290+
});
291+
292+
continue;
293+
};
294+
302295
// If an integrated branch has been found, there is no need to bother
303296
// with subsequent branches.
304-
if !unintegrated_branch_found && check_commit.is_integrated(&branch_head)? {
297+
if !unintegrated_branch_found
298+
&& matches!(
299+
branch_head.state,
300+
but_workspace::ui::CommitState::Integrated
301+
)
302+
{
305303
branch_statuses.push(NameAndStatus {
306304
name: branch.name.to_string(),
307305
status: BranchStatus::Integrated,
@@ -317,17 +315,6 @@ fn get_stack_status(
317315
// mergable is rebasable.
318316
// Doing both would be preferable, but we don't communicate that
319317
// to the frontend at the minute.
320-
let local_commits = &branch.commits;
321-
322-
if local_commits.is_empty() {
323-
branch_statuses.push(NameAndStatus {
324-
name: branch.name.to_string(),
325-
status: BranchStatus::Empty,
326-
});
327-
328-
continue;
329-
}
330-
331318
let local_commit_ids = local_commits
332319
.iter()
333320
.map(|commit| commit.id)
@@ -455,9 +442,7 @@ pub fn upstream_integration_statuses(
455442
Ok((
456443
stack.id,
457444
get_stack_status(
458-
repo,
459445
&gix_repo_in_memory,
460-
target.clone(),
461446
git2_to_gix_object_id(new_target.id()),
462447
stack.id,
463448
context.ctx,
@@ -756,20 +741,6 @@ fn compute_resolutions(
756741
))
757742
}
758743
ResolutionApproach::Rebase => {
759-
let gix_repo = gitbutler_command_context::gix_repo_for_merging(repo.path())?;
760-
let cache = gix_repo.commit_graph_if_enabled()?;
761-
let mut graph = gix_repo.revision_graph(cache.as_ref());
762-
let upstream_commit_oids =
763-
repo.l(new_target.id(), LogUntil::Commit(target.sha), true)?;
764-
let mut check_commit = IsCommitIntegrated::new_basic(
765-
&gix_repo,
766-
repo,
767-
&mut graph,
768-
git2_to_gix_object_id(target.sha),
769-
git2_to_gix_object_id(new_target.tree_id()),
770-
upstream_commit_oids,
771-
);
772-
773744
// Rebase the commits, then try rebasing the tree. If
774745
// the tree ends up conflicted, commit the tree.
775746

@@ -782,6 +753,12 @@ fn compute_resolutions(
782753
};
783754

784755
let details = stack_details(context.ctx, stack.id)?;
756+
let mut commit_map = HashMap::new();
757+
for branch in &details.branch_details {
758+
for commit in &branch.commits {
759+
commit_map.insert(commit.id, commit.clone());
760+
}
761+
}
785762

786763
let all_steps = details.as_rebase_steps(context.gix_repo)?;
787764
let branches_before = as_buckets(all_steps.clone());
@@ -794,7 +771,9 @@ fn compute_resolutions(
794771
new_message: _,
795772
} => {
796773
let commit = repo.find_commit(commit_id.to_git2()).ok()?;
797-
let is_integrated = check_commit.is_integrated(&commit).ok()?;
774+
let is_integrated = commit_map.get(&commit_id).is_some_and(|c| {
775+
matches!(c.state, but_workspace::ui::CommitState::Integrated)
776+
});
798777
let forced = forced_integrated(
799778
&resolution.force_integrated_branches,
800779
&branches_before,

crates/gitbutler-branch-actions/src/virtual.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -326,36 +326,6 @@ impl<'repo, 'cache, 'graph> IsCommitIntegrated<'repo, 'cache, 'graph> {
326326
upstream_change_ids,
327327
})
328328
}
329-
330-
/// Used to construct [`IsCommitIntegrated`] without a [`CommandContext`]. If
331-
/// you have a `CommandContext` available, use [`Self::new`] instead.
332-
pub(crate) fn new_basic(
333-
gix_repo: &'repo gix::Repository,
334-
repo: &'repo git2::Repository,
335-
graph: &'graph mut MergeBaseCommitGraph<'repo, 'cache>,
336-
target_commit_id: gix::ObjectId,
337-
upstream_tree_id: gix::ObjectId,
338-
mut upstream_commits: Vec<git2::Oid>,
339-
) -> Self {
340-
// Ensure upstream commits are sorted for binary search
341-
upstream_commits.sort();
342-
let upstream_change_ids = upstream_commits
343-
.iter()
344-
.filter_map(|oid| {
345-
let commit = repo.find_commit(*oid).ok()?;
346-
commit.change_id()
347-
})
348-
.sorted()
349-
.collect();
350-
Self {
351-
gix_repo,
352-
graph,
353-
target_commit_id,
354-
upstream_tree_id,
355-
upstream_commits,
356-
upstream_change_ids,
357-
}
358-
}
359329
}
360330

361331
impl IsCommitIntegrated<'_, '_, '_> {

0 commit comments

Comments
 (0)