Skip to main content

git_spawn/command/
branch.rs

1//! `git branch` — list, create, or delete branches.
2
3use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Builder for `git branch`.
8#[derive(Debug, Clone, Default)]
9pub struct BranchCommand {
10    /// Shared executor.
11    pub executor: CommandExecutor,
12    /// `-l` list.
13    pub list: bool,
14    /// `-a` include remotes.
15    pub all: bool,
16    /// `-r` remotes only.
17    pub remotes: bool,
18    /// `-v` verbose.
19    pub verbose: bool,
20    /// Branch to create or operate on.
21    pub name: Option<String>,
22    /// Start-point for creation.
23    pub start_point: Option<String>,
24    /// `-d`.
25    pub delete: Option<String>,
26    /// `-D` force delete.
27    pub force_delete: bool,
28    /// `-m`.
29    pub rename_from: Option<String>,
30    /// `-m` target.
31    pub rename_to: Option<String>,
32    /// `--track`.
33    pub track: bool,
34    /// `--no-track`.
35    pub no_track: bool,
36    /// `--set-upstream-to`.
37    pub set_upstream_to: Option<String>,
38    /// `--unset-upstream`.
39    pub unset_upstream: bool,
40    /// `--show-current`.
41    pub show_current: bool,
42    /// `--contains` filter.
43    pub contains: Option<String>,
44    /// `--merged` filter.
45    pub merged: Option<String>,
46}
47
48impl BranchCommand {
49    /// New `branch` command.
50    #[must_use]
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// List mode.
56    pub fn list(&mut self) -> &mut Self {
57        self.list = true;
58        self
59    }
60
61    /// Include remote-tracking branches.
62    pub fn all(&mut self) -> &mut Self {
63        self.all = true;
64        self
65    }
66
67    /// Remote-tracking branches only.
68    pub fn remotes(&mut self) -> &mut Self {
69        self.remotes = true;
70        self
71    }
72
73    /// `-v`.
74    pub fn verbose(&mut self) -> &mut Self {
75        self.verbose = true;
76        self
77    }
78
79    /// Create a branch with this name.
80    pub fn create(&mut self, name: impl Into<String>) -> &mut Self {
81        self.name = Some(name.into());
82        self
83    }
84
85    /// Start-point for `create`.
86    pub fn start_point(&mut self, sp: impl Into<String>) -> &mut Self {
87        self.start_point = Some(sp.into());
88        self
89    }
90
91    /// Delete a branch (`-d`).
92    pub fn delete(&mut self, name: impl Into<String>) -> &mut Self {
93        self.delete = Some(name.into());
94        self
95    }
96
97    /// Force delete.
98    pub fn force_delete(&mut self) -> &mut Self {
99        self.force_delete = true;
100        self
101    }
102
103    /// Rename branch (`-m <old> <new>`).
104    pub fn rename(&mut self, from: impl Into<String>, to: impl Into<String>) -> &mut Self {
105        self.rename_from = Some(from.into());
106        self.rename_to = Some(to.into());
107        self
108    }
109
110    /// Set upstream.
111    pub fn set_upstream_to(&mut self, s: impl Into<String>) -> &mut Self {
112        self.set_upstream_to = Some(s.into());
113        self
114    }
115
116    /// Unset upstream.
117    pub fn unset_upstream(&mut self) -> &mut Self {
118        self.unset_upstream = true;
119        self
120    }
121
122    /// `--track`.
123    pub fn track(&mut self) -> &mut Self {
124        self.track = true;
125        self
126    }
127
128    /// `--no-track`.
129    pub fn no_track(&mut self) -> &mut Self {
130        self.no_track = true;
131        self
132    }
133
134    /// `--show-current`.
135    pub fn show_current(&mut self) -> &mut Self {
136        self.show_current = true;
137        self
138    }
139
140    /// Filter branches containing commit.
141    pub fn contains(&mut self, c: impl Into<String>) -> &mut Self {
142        self.contains = Some(c.into());
143        self
144    }
145
146    /// Filter branches merged into commit.
147    pub fn merged(&mut self, c: impl Into<String>) -> &mut Self {
148        self.merged = Some(c.into());
149        self
150    }
151}
152
153#[async_trait]
154impl GitCommand for BranchCommand {
155    type Output = CommandOutput;
156    fn get_executor(&self) -> &CommandExecutor {
157        &self.executor
158    }
159    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
160        &mut self.executor
161    }
162    fn build_command_args(&self) -> Vec<String> {
163        let mut args = vec!["branch".to_string()];
164        if self.list {
165            args.push("--list".into());
166        }
167        if self.all {
168            args.push("--all".into());
169        }
170        if self.remotes {
171            args.push("--remotes".into());
172        }
173        if self.verbose {
174            args.push("--verbose".into());
175        }
176        if self.force_delete {
177            args.push("-D".into());
178        }
179        if self.track {
180            args.push("--track".into());
181        }
182        if self.no_track {
183            args.push("--no-track".into());
184        }
185        if self.unset_upstream {
186            args.push("--unset-upstream".into());
187        }
188        if self.show_current {
189            args.push("--show-current".into());
190        }
191        if let Some(u) = &self.set_upstream_to {
192            args.push(format!("--set-upstream-to={u}"));
193        }
194        if let Some(c) = &self.contains {
195            args.push(format!("--contains={c}"));
196        }
197        if let Some(m) = &self.merged {
198            args.push(format!("--merged={m}"));
199        }
200        if let Some(d) = &self.delete {
201            args.push("-d".into());
202            args.push(d.clone());
203        } else if let (Some(from), Some(to)) = (&self.rename_from, &self.rename_to) {
204            args.push("-m".into());
205            args.push(from.clone());
206            args.push(to.clone());
207        } else if let Some(name) = &self.name {
208            args.push(name.clone());
209            if let Some(sp) = &self.start_point {
210                args.push(sp.clone());
211            }
212        }
213        args
214    }
215    async fn execute(&self) -> Result<CommandOutput> {
216        self.execute_raw().await
217    }
218}