lattice_vcs/branch.rs
1use crate::{Repository, Result, VcsError};
2
3/// Branch operations — checkout, create, delete.
4///
5/// Uses the git CLI.
6pub struct Branch;
7
8impl Branch {
9 /// Check out an existing branch by name.
10 ///
11 /// Equivalent to `git checkout <name>`.
12 pub fn checkout(repo: &Repository, name: &str) -> Result<()> {
13 repo.run_git(["checkout", name])
14 .map(|_| ())
15 .map_err(|e| VcsError::Index(format!("branch checkout {}: {}", name, e)))
16 }
17
18 /// Create a new branch and optionally check it out.
19 ///
20 /// If `checkout` is `true`, equivalent to `git checkout -b <name>
21 /// [<from>]`. Otherwise equivalent to `git branch <name> [<from>]`.
22 /// `from` is the base ref to branch off of; `None` uses git's own
23 /// default (HEAD).
24 pub fn create(repo: &Repository, name: &str, checkout: bool, from: Option<&str>) -> Result<()> {
25 let mut args = if checkout {
26 vec!["checkout", "-b", name]
27 } else {
28 vec!["branch", name]
29 };
30 if let Some(base) = from {
31 args.push(base);
32 }
33 repo.run_git(args)
34 .map(|_| ())
35 .map_err(|e| VcsError::Index(format!("branch create {}: {}", name, e)))
36 }
37
38 /// Delete a branch by name.
39 ///
40 /// Uses `-D` (force-delete). Callers should confirm with the user
41 /// before calling this on unmerged branches.
42 pub fn delete(repo: &Repository, name: &str) -> Result<()> {
43 repo.run_git(["branch", "-D", name])
44 .map(|_| ())
45 .map_err(|e| VcsError::Index(format!("branch delete {}: {}", name, e)))
46 }
47
48 /// Rename a branch.
49 ///
50 /// Equivalent to `git branch -m <old> <new>`. Deliberately **not**
51 /// `-M`: the lowercase form refuses when `new` already names a
52 /// branch, and the uppercase one overwrites it. Overwriting here
53 /// destroys whatever `new` pointed at, silently, so the refusal is
54 /// the behaviour we want and the error is propagated rather than
55 /// swallowed.
56 ///
57 /// Renaming the checked-out branch carries HEAD with it (git's own
58 /// behaviour); it does not detach.
59 pub fn rename(repo: &Repository, old: &str, new: &str) -> Result<()> {
60 repo.run_git(["branch", "-m", old, new])
61 .map(|_| ())
62 .map_err(|e| VcsError::Index(format!("branch rename {} -> {}: {}", old, new, e)))
63 }
64
65 /// List all local branches.
66 ///
67 /// Equivalent to `git branch --format=%(refname:short)`.
68 pub fn list(repo: &Repository) -> Result<Vec<String>> {
69 repo.run_git_lines(["branch", "--format=%(refname:short)"])
70 }
71}