Skip to content

Commit 71902aa

Browse files
committed
Implement but branch new stacked branch
When doing `but branch new <branchname>` you can also pass `--anchor <branch|commit>` or `-a <branch|commit>` to create a stacked branch
1 parent f396b7c commit 71902aa

File tree

1 file changed

+78
-9
lines changed

1 file changed

+78
-9
lines changed

crates/but/src/branch/mod.rs

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::path::Path;
22

3+
use but_settings::AppSettings;
4+
use gitbutler_command_context::CommandContext;
35
use gitbutler_project::Project;
46

57
#[derive(Debug, clap::Parser)]
@@ -14,21 +16,88 @@ pub enum Subcommands {
1416
New {
1517
/// Name of the new branch
1618
branch_name: Option<String>,
19+
/// Anchor point - either a commit ID or branch name to create the new branch from
20+
#[clap(long, short = 'a')]
21+
anchor: Option<String>,
1722
},
1823
}
1924

2025
pub fn handle(cmd: &Subcommands, repo_path: &Path, _json: bool) -> anyhow::Result<()> {
2126
let project = Project::find_by_path(repo_path)?;
2227
match cmd {
23-
Subcommands::New { branch_name } => {
24-
let req = gitbutler_branch::BranchCreateRequest {
25-
name: branch_name.clone(),
26-
ownership: None,
27-
order: None,
28-
selected_for_changes: None,
29-
};
30-
but_api::virtual_branches::create_virtual_branch(project.id, req)?;
31-
Ok(())
28+
Subcommands::New {
29+
branch_name,
30+
anchor,
31+
} => {
32+
if let Some(anchor_str) = anchor {
33+
// Use the new create_reference API when anchor is provided
34+
let ctx = CommandContext::open(
35+
&project,
36+
AppSettings::load_from_default_path_creating()?,
37+
)?;
38+
let mut ctx = ctx; // Make mutable for CliId resolution
39+
40+
// Resolve the anchor string to a CliId
41+
let anchor_ids = crate::id::CliId::from_str(&mut ctx, anchor_str)?;
42+
if anchor_ids.is_empty() {
43+
return Err(anyhow::anyhow!("Could not find anchor: {}", anchor_str));
44+
}
45+
if anchor_ids.len() > 1 {
46+
return Err(anyhow::anyhow!(
47+
"Ambiguous anchor '{}', matches multiple items",
48+
anchor_str
49+
));
50+
}
51+
let anchor_id = &anchor_ids[0];
52+
53+
// Get branch name or use canned name
54+
let branch_name = if let Some(name) = branch_name {
55+
name.clone()
56+
} else {
57+
but_api::workspace::canned_branch_name(project.id)?
58+
};
59+
60+
// Create the anchor for create_reference
61+
let anchor = match anchor_id {
62+
crate::id::CliId::Commit { oid } => {
63+
Some(but_api::stack::create_reference::Anchor::AtCommit {
64+
commit_id: (*oid).into(),
65+
position: but_workspace::branch::create_reference::Position::Above,
66+
})
67+
}
68+
crate::id::CliId::Branch { name } => {
69+
Some(but_api::stack::create_reference::Anchor::AtReference {
70+
short_name: name.clone(),
71+
position: but_workspace::branch::create_reference::Position::Above,
72+
})
73+
}
74+
_ => {
75+
return Err(anyhow::anyhow!(
76+
"Invalid anchor type: {}, expected commit or branch",
77+
anchor_id.kind()
78+
));
79+
}
80+
};
81+
82+
// Use create_reference API
83+
let request = but_api::stack::create_reference::Request {
84+
new_name: branch_name.clone(),
85+
anchor,
86+
};
87+
but_api::stack::create_reference(project.id, request)?;
88+
println!("Created branch {branch_name}");
89+
Ok(())
90+
} else {
91+
// Create an independent branch
92+
let req = gitbutler_branch::BranchCreateRequest {
93+
name: branch_name.clone(),
94+
ownership: None,
95+
order: None,
96+
selected_for_changes: None,
97+
};
98+
but_api::virtual_branches::create_virtual_branch(project.id, req)?;
99+
Ok(())
100+
}
32101
}
33102
}
34103
}

0 commit comments

Comments
 (0)