mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-23 20:54:50 +03:00
Resolve upstream integration
Add a method to determine which should be the new base branch target commit ID based on what resolution approach is selected
This commit is contained in:
parent
e4cd357b8a
commit
2091025227
@ -10,6 +10,7 @@
|
||||
getResolutionApproach,
|
||||
sortStatusInfo,
|
||||
UpstreamIntegrationService,
|
||||
type BaseBranchResolutionApproach,
|
||||
type BranchStatusesWithBranches,
|
||||
type BranchStatusInfo,
|
||||
type Resolution
|
||||
@ -39,6 +40,8 @@
|
||||
let results = $state(new SvelteMap<string, Resolution>());
|
||||
let statuses = $state<BranchStatusInfo[]>([]);
|
||||
let expanded = $state<boolean>(false);
|
||||
let baseResolutionApproach = $state<BaseBranchResolutionApproach>('hardReset');
|
||||
let targetId = $state<string | undefined>(undefined);
|
||||
|
||||
$effect(() => {
|
||||
if ($branchStatuses?.type !== 'updatesRequired') {
|
||||
@ -68,6 +71,17 @@
|
||||
statuses = statusesTmp;
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (targetId) {
|
||||
branchStatuses = upstreamIntegrationService.upstreamStatuses(targetId);
|
||||
}
|
||||
});
|
||||
|
||||
async function handleBaseResolutionSelection(resolution: BaseBranchResolutionApproach) {
|
||||
baseResolutionApproach = resolution;
|
||||
targetId = await upstreamIntegrationService.resolveUpstreamIntegration(resolution);
|
||||
}
|
||||
|
||||
async function integrate() {
|
||||
integratingUpstream = 'loading';
|
||||
await tick();
|
||||
@ -144,6 +158,34 @@
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $base?.diverged}
|
||||
<div class="branch-status">
|
||||
<div class="description">
|
||||
<h5 class="text-16">{$base.branchName ?? 'Unknown'}</h5>
|
||||
<p>Diverged</p>
|
||||
</div>
|
||||
|
||||
<div class="action">
|
||||
<Select
|
||||
value={baseResolutionApproach}
|
||||
onselect={handleBaseResolutionSelection}
|
||||
options={[
|
||||
{ label: 'Rebase', value: 'rebase' },
|
||||
{ label: 'Merge', value: 'merge' },
|
||||
{ label: 'Hard reset', value: 'hardReset' }
|
||||
]}
|
||||
>
|
||||
{#snippet itemSnippet({ item, highlighted })}
|
||||
<SelectItem selected={highlighted} {highlighted}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
{/snippet}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if statuses.length > 0}
|
||||
<div class="statuses">
|
||||
{#each statuses as { branch, status }}
|
||||
@ -168,11 +210,8 @@
|
||||
onselect={(value) => {
|
||||
const result = results.get(branch.id)!;
|
||||
|
||||
results.set(branch.id, {
|
||||
...result,
|
||||
approach: { type: value as 'rebase' | 'merge' | 'unapply' }
|
||||
});
|
||||
}}
|
||||
results.set(branch.id, {...result, approach: { type: value }})
|
||||
}}
|
||||
options={[
|
||||
{ label: 'Rebase', value: 'rebase' },
|
||||
{ label: 'Merge', value: 'merge' },
|
||||
|
@ -37,6 +37,8 @@ export type Resolution = {
|
||||
approach: ResolutionApproach;
|
||||
};
|
||||
|
||||
export type BaseBranchResolutionApproach = 'rebase' | 'merge' | 'hardReset';
|
||||
|
||||
export function getResolutionApproach(statusInfo: BranchStatusInfo): ResolutionApproach {
|
||||
if (statusInfo.status.type === 'fullyIntegrated') {
|
||||
return { type: 'delete' };
|
||||
@ -79,7 +81,7 @@ export class UpstreamIntegrationService {
|
||||
private virtualBranchService: VirtualBranchService
|
||||
) {}
|
||||
|
||||
upstreamStatuses(): Readable<BranchStatusesWithBranches | undefined> {
|
||||
upstreamStatuses(_targetId?: string): Readable<BranchStatusesWithBranches | undefined> {
|
||||
const branchStatuses = readable<BranchStatusesResponse | undefined>(undefined, (set) => {
|
||||
invoke<BranchStatusesResponse>('upstream_integration_statuses', {
|
||||
projectId: this.project.id
|
||||
@ -116,4 +118,11 @@ export class UpstreamIntegrationService {
|
||||
async integrateUpstream(resolutions: Resolution[]) {
|
||||
return await invoke('integrate_upstream', { projectId: this.project.id, resolutions });
|
||||
}
|
||||
|
||||
async resolveUpstreamIntegration(type: BaseBranchResolutionApproach) {
|
||||
return await invoke<string>('resolve_upstream_integration', {
|
||||
projectId: this.project.id,
|
||||
resolutionApproach: { type }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
use super::r#virtual as vbranch;
|
||||
use crate::upstream_integration::{self, BranchStatuses, Resolution, UpstreamIntegrationContext};
|
||||
use crate::move_commits;
|
||||
use crate::reorder_commits;
|
||||
use crate::upstream_integration::{
|
||||
self, BaseBranchResolutionApproach, BranchStatuses, Resolution, UpstreamIntegrationContext,
|
||||
};
|
||||
use crate::{
|
||||
base,
|
||||
base::BaseBranch,
|
||||
@ -9,7 +13,6 @@ use crate::{
|
||||
remote::{RemoteBranch, RemoteBranchData, RemoteCommit},
|
||||
VirtualBranchesExt,
|
||||
};
|
||||
use crate::{move_commits, reorder_commits};
|
||||
use anyhow::{Context, Result};
|
||||
use gitbutler_branch::{BranchCreateRequest, BranchId, BranchOwnershipClaims, BranchUpdateRequest};
|
||||
use gitbutler_command_context::CommandContext;
|
||||
@ -544,6 +547,20 @@ pub fn integrate_upstream(project: &Project, resolutions: &[Resolution]) -> Resu
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_upstream_integration(
|
||||
project: &Project,
|
||||
resolution_approach: BaseBranchResolutionApproach,
|
||||
) -> Result<git2::Oid> {
|
||||
let command_context = CommandContext::open(project)?;
|
||||
let mut guard = project.exclusive_worktree_access();
|
||||
|
||||
upstream_integration::resolve_upstream_integration(
|
||||
&command_context,
|
||||
resolution_approach,
|
||||
guard.write_permission(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn open_with_verify(project: &Project) -> Result<CommandContext> {
|
||||
let ctx = CommandContext::open(project)?;
|
||||
let mut guard = project.exclusive_worktree_access();
|
||||
|
@ -9,10 +9,10 @@ pub use actions::{
|
||||
integrate_upstream_commits, list_local_branches, list_remote_commit_files,
|
||||
list_virtual_branches, list_virtual_branches_cached, move_commit, move_commit_file,
|
||||
push_base_branch, push_virtual_branch, reorder_commit, reset_files, reset_virtual_branch,
|
||||
save_and_unapply_virutal_branch, set_base_branch, set_target_push_remote, squash,
|
||||
unapply_ownership, unapply_without_saving_virtual_branch, undo_commit, update_base_branch,
|
||||
update_branch_order, update_commit_message, update_virtual_branch,
|
||||
upstream_integration_statuses,
|
||||
resolve_upstream_integration, save_and_unapply_virutal_branch, set_base_branch,
|
||||
set_target_push_remote, squash, unapply_ownership, unapply_without_saving_virtual_branch,
|
||||
undo_commit, update_base_branch, update_branch_order, update_commit_message,
|
||||
update_virtual_branch, upstream_integration_statuses,
|
||||
};
|
||||
|
||||
mod r#virtual;
|
||||
|
@ -32,6 +32,14 @@ pub enum BranchStatuses {
|
||||
UpdatesRequired(Vec<(BranchId, BranchStatus)>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "type", content = "subject", rename_all = "camelCase")]
|
||||
pub enum BaseBranchResolutionApproach {
|
||||
Rebase,
|
||||
Merge,
|
||||
HardReset,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "type", content = "subject", rename_all = "camelCase")]
|
||||
enum ResolutionApproach {
|
||||
@ -313,6 +321,39 @@ pub(crate) fn integrate_upstream(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_upstream_integration(
|
||||
command_context: &CommandContext,
|
||||
resolution_approach: BaseBranchResolutionApproach,
|
||||
permission: &mut WorktreeWritePermission,
|
||||
) -> Result<git2::Oid> {
|
||||
let context = UpstreamIntegrationContext::open(command_context, permission)?;
|
||||
let repo = command_context.repository();
|
||||
let new_target_id = context.new_target.id();
|
||||
let old_target_id = context.old_target.id();
|
||||
let fork_point = repo.merge_base(old_target_id, new_target_id)?;
|
||||
|
||||
match resolution_approach {
|
||||
BaseBranchResolutionApproach::HardReset => Ok(new_target_id),
|
||||
BaseBranchResolutionApproach::Merge => {
|
||||
let new_head = gitbutler_merge_commits(
|
||||
repo,
|
||||
context.old_target,
|
||||
context.new_target,
|
||||
&context.target_branch_name,
|
||||
&context.target_branch_name,
|
||||
)?;
|
||||
|
||||
Ok(new_head.id())
|
||||
}
|
||||
BaseBranchResolutionApproach::Rebase => {
|
||||
let commits = repo.l(old_target_id, LogUntil::Commit(fork_point))?;
|
||||
let new_head = cherry_rebase_group(repo, new_target_id, &commits, true)?;
|
||||
|
||||
Ok(new_head)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_resolutions(
|
||||
context: &UpstreamIntegrationContext,
|
||||
resolutions: &[Resolution],
|
||||
|
@ -188,6 +188,7 @@ fn main() {
|
||||
virtual_branches::commands::normalize_branch_name,
|
||||
virtual_branches::commands::upstream_integration_statuses,
|
||||
virtual_branches::commands::integrate_upstream,
|
||||
virtual_branches::commands::resolve_upstream_integration,
|
||||
virtual_branches::commands::find_commit,
|
||||
stack::create_series,
|
||||
stack::remove_series,
|
||||
|
@ -4,7 +4,9 @@ pub mod commands {
|
||||
BranchCreateRequest, BranchId, BranchOwnershipClaims, BranchUpdateRequest,
|
||||
};
|
||||
use gitbutler_branch_actions::internal::PushResult;
|
||||
use gitbutler_branch_actions::upstream_integration::{BranchStatuses, Resolution};
|
||||
use gitbutler_branch_actions::upstream_integration::{
|
||||
BaseBranchResolutionApproach, BranchStatuses, Resolution,
|
||||
};
|
||||
use gitbutler_branch_actions::{
|
||||
BaseBranch, BranchListing, BranchListingDetails, BranchListingFilter, RemoteBranch,
|
||||
RemoteBranchData, RemoteBranchFile, RemoteCommit, VirtualBranches,
|
||||
@ -597,6 +599,21 @@ pub mod commands {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[instrument(skip(projects), err(Debug))]
|
||||
pub fn resolve_upstream_integration(
|
||||
projects: State<'_, projects::Controller>,
|
||||
project_id: ProjectId,
|
||||
resolution_approach: BaseBranchResolutionApproach,
|
||||
) -> Result<String, Error> {
|
||||
let project = projects.get(project_id)?;
|
||||
|
||||
let new_target_id =
|
||||
gitbutler_branch_actions::resolve_upstream_integration(&project, resolution_approach)?;
|
||||
let commit_id = git2::Oid::to_string(&new_target_id);
|
||||
Ok(commit_id)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_vbranches(windows: &WindowState, project_id: projects::ProjectId) {
|
||||
if let Err(error) = windows.post(gitbutler_watcher::Action::CalculateVirtualBranches(
|
||||
project_id,
|
||||
|
Loading…
Reference in New Issue
Block a user