Skip to main content

cargo_resolvediff/
git.rs

1// Copyright (C) 2026 by GiGa infosystems
2
3//! Git helpers for the application to add changes & commit them
4
5use crate::cmd::cmd;
6use color_eyre::Result;
7use std::path::{Path, PathBuf};
8
9/// A `git` repository
10pub struct Repository {
11    /// The path to the repository
12    path: Option<PathBuf>,
13    /// If any changes got `git add`ed to the repository
14    dirty: bool,
15}
16
17impl Repository {
18    /// Open an existing [`Repository`] at the given path.
19    ///
20    /// This does not check if the repository actually exist, methods on this type will simply fail
21    /// if it doesn't.
22    pub fn new(path: Option<PathBuf>) -> Self {
23        Repository { path, dirty: false }
24    }
25
26    /// `git add` a given path if it includes changes.
27    pub fn add(&mut self, path: &Path) -> Result<()> {
28        let changed = !cmd!([git diff] ["-s" "--exit-code" "--" (path)] -> bool in &self.path)?;
29        if changed {
30            self.dirty = true;
31            cmd!([git add] [(path)] in &self.path)?;
32        }
33        Ok(())
34    }
35
36    /// Returns the current commit ID
37    pub fn current_commit(&self) -> Result<String> {
38        cmd!([git "rev-parse"] [HEAD] -> String in &self.path)
39    }
40
41    /// `git commit` everything that got added, if there were any changes, and return the commit
42    /// ID.
43    ///
44    /// If there were no changes, it returns `Ok(None)`.
45    pub fn commit(&mut self, message: &str) -> Result<Option<String>> {
46        if !self.dirty {
47            return Ok(None);
48        }
49        cmd!([git commit] ["-m" (message)] in &self.path)?;
50        self.dirty = false;
51        Ok(Some(self.current_commit()?))
52    }
53
54    /// Returns the current branch, if any, or the current commit ID
55    pub fn current_branch_or_commit(&self) -> Result<String> {
56        let branch = cmd!([git branch] ["--show-current"] -> String in &self.path)?;
57        if !branch.is_empty() {
58            Ok(branch)
59        } else {
60            Ok(self.current_commit()?)
61        }
62    }
63
64    /// Checks out a given branch or commit ID
65    pub fn checkout(&mut self, target: &str) -> Result<()> {
66        cmd!([git "checkout"] [(target)] in &self.path)
67    }
68}