Skip to content

Commit 3c15d22

Browse files
authored
Merge pull request #10521 from gitbutlerapp/integrate-upstream-workspace-update
Integrate upstream & update stacks logic in workspace
2 parents 6af0714 + 77f52aa commit 3c15d22

File tree

5 files changed

+186
-60
lines changed

5 files changed

+186
-60
lines changed

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)