From 6a056f9ad72e175440b2dc9517c2dccfcdfceb85 Mon Sep 17 00:00:00 2001 From: Kiril Videlov Date: Wed, 16 Oct 2024 22:09:59 +0200 Subject: [PATCH] refactor integrate_upstream_commits_for_series --- .../src/branch_upstream_integration.rs | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/crates/gitbutler-branch-actions/src/branch_upstream_integration.rs b/crates/gitbutler-branch-actions/src/branch_upstream_integration.rs index 6740fbb61..59300b35e 100644 --- a/crates/gitbutler-branch-actions/src/branch_upstream_integration.rs +++ b/crates/gitbutler-branch-actions/src/branch_upstream_integration.rs @@ -6,7 +6,7 @@ use gitbutler_repo::{ LogUntil, RepositoryExt as _, }; use gitbutler_stack::StackId; -use gitbutler_stack_api::{commit_by_oid_or_change_id, StackExt}; +use gitbutler_stack_api::{commit_by_oid_or_change_id, Series, StackExt}; use crate::{ branch_trees::{ @@ -34,28 +34,59 @@ pub fn integrate_upstream_commits_for_series( "No remote has been configured for the target branch" ))?; - let series = all_series + let subject_series = all_series .iter() .find(|series| series.head.name == series_name) .ok_or(anyhow!("Series not found"))?; - let upstream_reference = series.head.remote_reference(remote.as_str())?; + let upstream_reference = subject_series.head.remote_reference(remote.as_str())?; let remote_head = repo.find_reference(&upstream_reference)?.peel_to_commit()?; - let stack_merge_base = repo.merge_base(branch.head(), default_target.sha)?; - let upstream_to_local_merge_base = repo.merge_base(branch.head(), remote_head.id())?; + + let new_stack_head = new_stack_head( + repo, + branch.allow_rebasing, + branch.head(), + remote_head.id(), + default_target.sha, + all_series.clone(), + subject_series, + )?; + // Find what the new head and branch tree should be + let BranchHeadAndTree { head, tree } = + compute_updated_branch_head_for_commits(repo, branch.head(), branch.tree, new_stack_head)?; + + let mut branch = branch.clone(); + + branch.set_stack_head(ctx, head, Some(tree))?; + checkout_branch_trees(ctx, perm)?; + crate::integration::update_workspace_commit(&vb_state, ctx)?; + Ok(()) +} + +fn new_stack_head( + repo: &git2::Repository, + allow_rebasing: bool, + branch_head: git2::Oid, + remote_head: git2::Oid, + target_head: git2::Oid, + all_series: Vec, + subject_series: &Series, +) -> Result { + let stack_merge_base = repo.merge_base(branch_head, target_head)?; + let upstream_to_local_merge_base = repo.merge_base(branch_head, remote_head)?; // Rebasing will be performed if configured. // If the series to integrate is not the latest one, it will also do a rebase. - let new_stack_head = if branch.allow_rebasing || Some(series) != all_series.first() { + let new_stack_head = if allow_rebasing || Some(subject_series) != all_series.first() { // commits to rebase let mut ordered_commits_to_rebase = vec![]; for series in all_series.clone() { // if this is the series that is getting the upstream commits, they are added first - if series.head.name == series_name { + if series.head.name == subject_series.head.name { for id in series.upstream_only_commits.iter() { let commit = commit_by_oid_or_change_id( id, repo, - remote_head.id(), + remote_head, upstream_to_local_merge_base, )?; ordered_commits_to_rebase.push(commit.id()); @@ -63,7 +94,7 @@ pub fn integrate_upstream_commits_for_series( } // now add the existing local commits to the rebase list for id in series.local_commits.iter() { - let commit = commit_by_oid_or_change_id(id, repo, branch.head(), stack_merge_base)?; + let commit = commit_by_oid_or_change_id(id, repo, branch_head, stack_merge_base)?; ordered_commits_to_rebase.push(commit.id()); } } @@ -75,34 +106,25 @@ pub fn integrate_upstream_commits_for_series( } else { // If rebase is not allowed AND this is the latest series - create a merge commit on top let series_head_commit = commit_by_oid_or_change_id( - &series.head.target, + &subject_series.head.target, repo, - branch.head(), + branch_head, upstream_to_local_merge_base, )?; + let remote_head_commit = repo.find_commit(remote_head)?; let merge_commit = gitbutler_merge_commits( repo, series_head_commit, - remote_head.clone(), - &series.head.name, // for error messages only - &series + remote_head_commit, + &subject_series.head.name, // for error messages only + &subject_series .head - .remote_reference(&default_target.sha.to_string())?, // for error messages only + .remote_reference(&target_head.to_string())?, // for error messages only )?; // the new merge commit is now the stack and series head merge_commit.id() }; - - // Find what the new head and branch tree should be - let BranchHeadAndTree { head, tree } = - compute_updated_branch_head_for_commits(repo, branch.head(), branch.tree, new_stack_head)?; - - let mut branch = branch.clone(); - - branch.set_stack_head(ctx, head, Some(tree))?; - checkout_branch_trees(ctx, perm)?; - crate::integration::update_workspace_commit(&vb_state, ctx)?; - Ok(()) + Ok(new_stack_head) } /// Integrates upstream work from a remote branch.