Skip to content

Commit 31faad5

Browse files
authored
Merge pull request #10525 from gitbutlerapp/integrate-upstream-workspace-update
integrate-upstream-workspace-update
2 parents 6718975 + e17b2f9 commit 31faad5

File tree

11 files changed

+324
-65
lines changed

11 files changed

+324
-65
lines changed

apps/desktop/cypress/e2e/support/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ Cypress.on('window:before:load', (win) => {
180180
return await Promise.resolve({});
181181
case 'plugin:log|log':
182182
return await Promise.resolve({});
183+
case 'plugin:window|title':
184+
case 'plugin:app|name':
185+
return 'GitButler';
186+
case 'plugin:app|version':
187+
return '0.0.0';
183188
default:
184189
return raiseMissingMockError(command);
185190
}

apps/desktop/cypress/e2e/upstreamIntegration.cy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,27 @@ describe('Upstream Integration', () => {
8484
projectId: PROJECT_ID,
8585
resolutions: [
8686
{
87-
branchId: 'stack-a-id',
87+
stackId: 'stack-a-id',
8888
approach: { type: 'rebase' },
8989
deleteIntegratedBranches: true,
9090
forceIntegratedBranches: []
9191
},
9292
{
93-
branchId: 'stack-b-id',
93+
stackId: 'stack-b-id',
9494
approach: { type: 'delete' },
9595
deleteIntegratedBranches: false,
9696
forceIntegratedBranches: []
9797
},
9898
{
99-
branchId: 'stack-c-id',
99+
stackId: 'stack-c-id',
100100
approach: {
101101
type: 'delete'
102102
},
103103
deleteIntegratedBranches: true,
104104
forceIntegratedBranches: []
105105
}
106106
],
107-
branchResolution: undefined
107+
baseBranchResolution: undefined
108108
});
109109
});
110110
});

apps/desktop/src/components/IntegrateUpstreamModal.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
const dontDelete = someBranchesShouldNotBeDeleted(status.stack.heads.map((b) => b.name));
108108
109109
results.set(status.stack.id, {
110-
branchId: status.stack.id,
110+
stackId: status.stack.id,
111111
approach: getResolutionApproachV3(status),
112112
deleteIntegratedBranches: !dontDelete,
113113
forceIntegratedBranches

apps/desktop/src/lib/upstream/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type ResolutionApproach = {
4949
};
5050

5151
export type Resolution = {
52-
branchId: string;
52+
stackId: string;
5353
approach: ResolutionApproach;
5454
deleteIntegratedBranches: boolean;
5555
forceIntegratedBranches: string[];

crates/but-workspace/src/stack_ext.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,44 @@ impl StackExt for gitbutler_stack::Stack {
6565
Ok(steps)
6666
}
6767
}
68+
69+
/// Extension trait for `but_workspace::ui::StackDetails`.
70+
pub trait StackDetailsExt {
71+
/// Return the stack as a series of rebase steps in the order the steps should be applied.
72+
fn as_rebase_steps(&self, repo: &gix::Repository) -> anyhow::Result<Vec<RebaseStep>>;
73+
/// Return the stack as a series of rebase steps in reverse order, i.e. in the order they were generated.
74+
///
75+
/// The generation order starts at the top of the stack (tip first) and goes down to the merge base (parent most commit).
76+
/// This is useful for operations that need to process the stack in reverse order.
77+
fn as_rebase_steps_rev(&self, repo: &gix::Repository) -> anyhow::Result<Vec<RebaseStep>>;
78+
}
79+
80+
impl StackDetailsExt for crate::ui::StackDetails {
81+
fn as_rebase_steps(&self, repo: &gix::Repository) -> anyhow::Result<Vec<RebaseStep>> {
82+
self.as_rebase_steps_rev(repo).map(|mut steps| {
83+
steps.reverse();
84+
steps
85+
})
86+
}
87+
88+
fn as_rebase_steps_rev(&self, repo: &gix::Repository) -> anyhow::Result<Vec<RebaseStep>> {
89+
let mut steps: Vec<RebaseStep> = Vec::new();
90+
for branch in &self.branch_details {
91+
let reference_step = if let Some(reference) = repo.try_find_reference(&branch.name)? {
92+
RebaseStep::Reference(but_core::Reference::Git(reference.name().to_owned()))
93+
} else {
94+
RebaseStep::Reference(but_core::Reference::Virtual(branch.name.to_string()))
95+
};
96+
steps.push(reference_step);
97+
let commits = &branch.commits;
98+
for commit in commits {
99+
let pick_step = RebaseStep::Pick {
100+
commit_id: commit.id,
101+
new_message: None,
102+
};
103+
steps.push(pick_step);
104+
}
105+
}
106+
Ok(steps)
107+
}
108+
}

crates/but-workspace/src/ui/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::Context;
22
use bstr::{BStr, BString, ByteSlice};
3+
use gix::refs::transaction::{Change, PreviousValue, RefEdit, RefLog};
34
use serde::Serialize;
45

56
/// Utilities for diffing, with workspace integration.
@@ -83,6 +84,27 @@ pub struct StackHeadInfo {
8384
pub is_checked_out: bool,
8485
}
8586

87+
impl StackHeadInfo {
88+
/// Delete the reference for this head from the repository if it exists and matches the expected OID.
89+
pub fn delete_reference(&self, repo: &gix::Repository) -> anyhow::Result<()> {
90+
let oid = self.tip;
91+
let ref_name = format!("refs/heads/{}", self.name.to_str()?.trim_matches('/'));
92+
let current_name: BString = ref_name.into();
93+
if let Some(reference) = repo.try_find_reference(&current_name)? {
94+
let delete = RefEdit {
95+
change: Change::Delete {
96+
expected: PreviousValue::MustExistAndMatch(oid.into()),
97+
log: RefLog::AndReference,
98+
},
99+
name: reference.name().into(),
100+
deref: false,
101+
};
102+
repo.edit_reference(delete)?;
103+
}
104+
Ok(())
105+
}
106+
}
107+
86108
/// Represents a lightweight version of a [`Stack`] for listing.
87109
/// NOTE: this is a UI type mostly because it's still modeled after the legacy stack with StackId, something that doesn't exist anymore.
88110
#[derive(Debug, Clone, Serialize)]

crates/but/src/base/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ pub fn handle(cmd: &Subcommands, project: &Project, json: bool) -> anyhow::Resul
125125
} else {
126126
println!("🔄 Updating branches...");
127127
let mut resolutions = vec![];
128-
for (id, status) in statuses {
128+
for (maybe_stack_id, status) in statuses {
129+
let Some(stack_id) = maybe_stack_id else {
130+
println!("No stack ID, assuming we're on single-branch mode...",);
131+
continue;
132+
};
129133
let approach = if status
130134
.branch_statuses
131135
.iter()
@@ -137,7 +141,7 @@ pub fn handle(cmd: &Subcommands, project: &Project, json: bool) -> anyhow::Resul
137141
ResolutionApproach::Rebase
138142
};
139143
let resolution = Resolution {
140-
branch_id: id, // This is StackId
144+
stack_id,
141145
approach,
142146
delete_integrated_branches: true,
143147
force_integrated_branches: vec![],

0 commit comments

Comments
 (0)