1use crate::Result;
2use git2::Repository;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct BranchInfo {
7 pub name: String,
8 pub is_current: bool,
9 pub upstream: Option<String>,
10 pub commit_id: Option<String>,
11}
12
13impl BranchInfo {
14 pub fn current(repo: &Repository) -> Result<Option<Self>> {
15 let head = match repo.head() {
16 Ok(h) => h,
17 Err(_) => return Ok(None),
18 };
19
20 if head.is_branch() {
21 let name = head
22 .name()
23 .map(|n| n.strip_prefix("refs/heads/").unwrap_or(n).to_string())
24 .unwrap_or_else(|| "HEAD".to_string());
25
26 let commit_id = head.peel_to_commit().ok().map(|c| c.id().to_string());
27
28 return Ok(Some(Self {
29 name,
30 is_current: true,
31 upstream: None,
32 commit_id,
33 }));
34 }
35
36 Ok(None)
37 }
38
39 pub fn list(repo: &Repository) -> Result<Vec<Self>> {
40 let mut branches = Vec::new();
41 let current = Self::current(repo)?;
42 let current_name = current.as_ref().map(|b| b.name.clone());
43
44 let branch_names = repo.branches(None)?;
45 for branch in branch_names.flatten() {
46 if let Ok(Some(name)) = branch.0.name() {
47 let name = name.strip_prefix("refs/heads/").unwrap_or(name).to_string();
48 let is_current = current_name.as_ref() == Some(&name);
49 let commit_id = branch
50 .0
51 .get()
52 .peel_to_commit()
53 .ok()
54 .map(|c| c.id().to_string());
55
56 branches.push(Self {
57 name,
58 is_current,
59 upstream: None,
60 commit_id,
61 });
62 }
63 }
64
65 Ok(branches)
66 }
67}