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    /// Upgrade a [`delete`](Self::delete) to a force delete (`-D` instead of
98    /// `-d`). Has no effect unless `delete` is also set.
99    pub fn force_delete(&mut self) -> &mut Self {
100        self.force_delete = true;
101        self
102    }
103
104    /// Rename branch (`-m <old> <new>`).
105    pub fn rename(&mut self, from: impl Into<String>, to: impl Into<String>) -> &mut Self {
106        self.rename_from = Some(from.into());
107        self.rename_to = Some(to.into());
108        self
109    }
110
111    /// Set upstream.
112    pub fn set_upstream_to(&mut self, s: impl Into<String>) -> &mut Self {
113        self.set_upstream_to = Some(s.into());
114        self
115    }
116
117    /// Unset upstream.
118    pub fn unset_upstream(&mut self) -> &mut Self {
119        self.unset_upstream = true;
120        self
121    }
122
123    /// `--track`.
124    pub fn track(&mut self) -> &mut Self {
125        self.track = true;
126        self
127    }
128
129    /// `--no-track`.
130    pub fn no_track(&mut self) -> &mut Self {
131        self.no_track = true;
132        self
133    }
134
135    /// `--show-current`.
136    pub fn show_current(&mut self) -> &mut Self {
137        self.show_current = true;
138        self
139    }
140
141    /// Filter branches containing commit.
142    pub fn contains(&mut self, c: impl Into<String>) -> &mut Self {
143        self.contains = Some(c.into());
144        self
145    }
146
147    /// Filter branches merged into commit.
148    pub fn merged(&mut self, c: impl Into<String>) -> &mut Self {
149        self.merged = Some(c.into());
150        self
151    }
152}
153
154#[async_trait]
155impl GitCommand for BranchCommand {
156    type Output = CommandOutput;
157    fn get_executor(&self) -> &CommandExecutor {
158        &self.executor
159    }
160    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
161        &mut self.executor
162    }
163    fn build_command_args(&self) -> Vec<String> {
164        let mut args = vec!["branch".to_string()];
165        if self.list {
166            args.push("--list".into());
167        }
168        if self.all {
169            args.push("--all".into());
170        }
171        if self.remotes {
172            args.push("--remotes".into());
173        }
174        if self.verbose {
175            args.push("--verbose".into());
176        }
177        if self.track {
178            args.push("--track".into());
179        }
180        if self.no_track {
181            args.push("--no-track".into());
182        }
183        if self.unset_upstream {
184            args.push("--unset-upstream".into());
185        }
186        if self.show_current {
187            args.push("--show-current".into());
188        }
189        if let Some(u) = &self.set_upstream_to {
190            args.push(format!("--set-upstream-to={u}"));
191        }
192        if let Some(c) = &self.contains {
193            args.push(format!("--contains={c}"));
194        }
195        if let Some(m) = &self.merged {
196            args.push(format!("--merged={m}"));
197        }
198        if let Some(d) = &self.delete {
199            args.push(if self.force_delete { "-D" } else { "-d" }.into());
200            args.push(d.clone());
201        } else if let (Some(from), Some(to)) = (&self.rename_from, &self.rename_to) {
202            args.push("-m".into());
203            args.push(from.clone());
204            args.push(to.clone());
205        } else if let Some(name) = &self.name {
206            args.push(name.clone());
207            if let Some(sp) = &self.start_point {
208                args.push(sp.clone());
209            }
210        }
211        args
212    }
213    async fn execute(&self) -> Result<CommandOutput> {
214        self.execute_raw().await
215    }
216}