1use crate::core::git::GitOperations;
2use crate::core::validation::Validate;
3use crate::{GitXError, Result};
4use std::process::Command;
5
6pub fn run(branch_name: String, from: Option<String>) -> Result<String> {
7 Validate::branch_name(&branch_name)?;
9
10 if branch_exists(&branch_name) {
12 return Err(GitXError::GitCommand(format!(
13 "Branch '{branch_name}' already exists"
14 )));
15 }
16
17 let base_branch = match from {
19 Some(ref branch) => {
20 if !branch_exists(branch) && !is_valid_ref(branch) {
21 return Err(GitXError::GitCommand(format!(
22 "Base branch or ref '{branch}' does not exist"
23 )));
24 }
25 branch.clone()
26 }
27 None => get_current_branch_result()?,
28 };
29
30 let mut output = Vec::new();
31 output.push(branch_name.clone());
32
33 create_branch_result(&branch_name, &base_branch)?;
35
36 switch_to_branch_result(&branch_name)?;
38
39 output.push(branch_name.clone());
40 Ok(output.join("\n"))
41}
42
43fn branch_exists(branch_name: &str) -> bool {
44 Command::new("git")
45 .args([
46 "show-ref",
47 "--verify",
48 "--quiet",
49 &format!("refs/heads/{branch_name}"),
50 ])
51 .status()
52 .map(|status| status.success())
53 .unwrap_or(false)
54}
55
56fn is_valid_ref(ref_name: &str) -> bool {
57 Command::new("git")
58 .args(["rev-parse", "--verify", "--quiet", ref_name])
59 .status()
60 .map(|status| status.success())
61 .unwrap_or(false)
62}
63
64fn get_current_branch_result() -> Result<String> {
65 GitOperations::current_branch()
66 .map_err(|e| GitXError::GitCommand(format!("Failed to get current branch: {e}")))
67}
68
69fn create_branch_result(branch_name: &str, base_branch: &str) -> Result<()> {
70 let output = Command::new("git")
71 .args(["branch", branch_name, base_branch])
72 .output()
73 .map_err(|_| GitXError::GitCommand("Failed to execute git branch command".to_string()))?;
74
75 if !output.status.success() {
76 let stderr = String::from_utf8_lossy(&output.stderr);
77 return Err(GitXError::GitCommand(format!(
78 "Failed to create branch: {}",
79 stderr.trim()
80 )));
81 }
82
83 Ok(())
84}
85
86fn switch_to_branch_result(branch_name: &str) -> Result<()> {
87 let output = Command::new("git")
88 .args(["switch", branch_name])
89 .output()
90 .map_err(|_| GitXError::GitCommand("Failed to execute git switch command".to_string()))?;
91
92 if !output.status.success() {
93 let stderr = String::from_utf8_lossy(&output.stderr);
94 return Err(GitXError::GitCommand(format!(
95 "Failed to switch to new branch: {}",
96 stderr.trim()
97 )));
98 }
99
100 Ok(())
101}