Skip to content

Commit c1ad39d

Browse files
committed
Implement basic stacked branch creation from target branch
This change implements creating a new virtual branch based on the target branch by locating the target stack, creating a BranchCreateRequest, and calling create_virtual_branch. Note: proper stacking relationships and full integration with the stacking system remain TODO and will require further work.
1 parent c42f442 commit c1ad39d

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

crates/but/src/branch/mod.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use but_settings::AppSettings;
22
use colored::Colorize;
33
use gitbutler_branch::BranchCreateRequest;
4-
use gitbutler_branch_actions::{create_virtual_branch, create_virtual_branch_from_branch, unapply_stack};
4+
use gitbutler_branch_actions::{create_virtual_branch, unapply_stack};
55
use gitbutler_command_context::CommandContext;
6+
use gitbutler_oxidize::{ObjectIdExt, RepoExt};
67
use gitbutler_project::Project;
7-
use gitbutler_reference::Refname;
88
use gitbutler_stack::VirtualBranchesHandle;
99
use std::path::Path;
10-
use std::str::FromStr;
1110

1211
use crate::id::CliId;
1312

@@ -69,18 +68,61 @@ pub(crate) fn create_branch(
6968
id_str.blue().underline()
7069
);
7170

72-
// Create a Refname from the branch name
73-
let branch_ref = Refname::from_str(&format!("refs/heads/{}", target_branch_name))?;
74-
75-
let new_stack_id = create_virtual_branch_from_branch(&ctx, &branch_ref, None, None)?;
76-
77-
// Update the branch name if it's different
78-
if branch_name != target_branch_name {
79-
let vb_state = VirtualBranchesHandle::new(ctx.project().gb_dir());
80-
let mut stack = vb_state.get_stack(new_stack_id)?;
81-
stack.name = branch_name.to_string();
82-
vb_state.set_stack(stack)?;
71+
// Find the target stack and get its current head commit
72+
let stacks = crate::log::stacks(&ctx)?;
73+
let target_stack = stacks.iter().find(|s| {
74+
s.heads.iter().any(|head| head.name.to_string() == target_branch_name)
75+
});
76+
77+
let target_stack = match target_stack {
78+
Some(s) => s,
79+
None => return Err(anyhow::anyhow!("No stack found for branch '{}'", target_branch_name)),
80+
};
81+
82+
let target_stack_id = target_stack.id.ok_or_else(|| anyhow::anyhow!("Target stack has no ID"))?;
83+
84+
// Get the stack details to find the head commit
85+
let target_stack_details = crate::log::stack_details(&ctx, target_stack_id)?;
86+
if target_stack_details.branch_details.is_empty() {
87+
return Err(anyhow::anyhow!("Target stack has no branch details"));
8388
}
89+
90+
// Find the target branch in the stack details
91+
let target_branch_details = target_stack_details.branch_details.iter().find(|b|
92+
b.name == target_branch_name
93+
).ok_or_else(|| anyhow::anyhow!("Target branch '{}' not found in stack details", target_branch_name))?;
94+
95+
// Get the head commit of the target branch
96+
let target_head_oid = if !target_branch_details.commits.is_empty() {
97+
// Use the last local commit
98+
target_branch_details.commits.last().unwrap().id
99+
} else if !target_branch_details.upstream_commits.is_empty() {
100+
// If no local commits, use the last upstream commit
101+
target_branch_details.upstream_commits.last().unwrap().id
102+
} else {
103+
return Err(anyhow::anyhow!("Target branch '{}' has no commits", target_branch_name));
104+
};
105+
106+
// Create a new virtual branch
107+
let mut guard = project.exclusive_worktree_access();
108+
let create_request = BranchCreateRequest {
109+
name: Some(branch_name.to_string()),
110+
ownership: None,
111+
order: None,
112+
selected_for_changes: None,
113+
};
114+
115+
let new_stack_id = create_virtual_branch(&ctx, &create_request, guard.write_permission())?;
116+
117+
// Now set up the new branch to start from the target branch's head
118+
let vb_state = VirtualBranchesHandle::new(ctx.project().gb_dir());
119+
let mut new_stack = vb_state.get_stack(new_stack_id.id)?;
120+
121+
// Set the head of the new stack to be the target branch's head
122+
// This creates the stacking relationship
123+
let gix_repo = ctx.repo().to_gix()?;
124+
new_stack.set_stack_head(&vb_state, &gix_repo, target_head_oid.to_git2(), None)?;
125+
vb_state.set_stack(new_stack)?;
84126

85127
println!(
86128
"{} Stacked branch '{}' created successfully!",

0 commit comments

Comments
 (0)