git_workflow/state/
sync.rs1use crate::error::Result;
4use crate::git;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum SyncState {
9 NoUpstream,
11 Synced,
13 HasUnpushedCommits { count: usize },
15 Behind { count: usize },
17 Diverged { ahead: usize, behind: usize },
19}
20
21impl SyncState {
22 pub fn detect(branch: &str) -> Result<Self> {
24 if !git::has_remote_tracking(branch) {
25 return Ok(SyncState::NoUpstream);
26 }
27
28 let ahead = git::unpushed_commit_count(branch).unwrap_or(0);
29 let behind = git::behind_upstream_count(branch).unwrap_or(0);
30
31 Ok(match (ahead, behind) {
32 (0, 0) => SyncState::Synced,
33 (a, 0) if a > 0 => SyncState::HasUnpushedCommits { count: a },
34 (0, b) if b > 0 => SyncState::Behind { count: b },
35 (a, b) => SyncState::Diverged {
36 ahead: a,
37 behind: b,
38 },
39 })
40 }
41
42 pub fn has_unpushed(&self) -> bool {
44 matches!(
45 self,
46 SyncState::HasUnpushedCommits { .. } | SyncState::Diverged { .. }
47 )
48 }
49
50 pub fn unpushed_count(&self) -> usize {
52 match self {
53 SyncState::HasUnpushedCommits { count } => *count,
54 SyncState::Diverged { ahead, .. } => *ahead,
55 _ => 0,
56 }
57 }
58
59 pub fn description(&self) -> String {
61 match self {
62 SyncState::NoUpstream => "no upstream".to_string(),
63 SyncState::Synced => "synced".to_string(),
64 SyncState::HasUnpushedCommits { count } => format!("{count} unpushed commit(s)"),
65 SyncState::Behind { count } => format!("{count} commit(s) behind"),
66 SyncState::Diverged { ahead, behind } => {
67 format!("{ahead} ahead, {behind} behind")
68 }
69 }
70 }
71}