Skip to main content

changeset_git/repository/
staging.rs

1use std::path::Path;
2
3use crate::Result;
4
5use super::Repository;
6
7impl Repository {
8    /// # Errors
9    ///
10    /// Returns an error if staging any of the files fails.
11    pub fn stage_files(&self, paths: &[&Path]) -> Result<()> {
12        let mut index = self.inner.index()?;
13
14        for path in paths {
15            let relative_path = self.to_relative_path(path);
16
17            if path.exists() || self.root().join(&relative_path).exists() {
18                index.add_path(&relative_path)?;
19            } else {
20                index.remove_path(&relative_path)?;
21            }
22        }
23
24        index.write()?;
25        Ok(())
26    }
27
28    /// # Errors
29    ///
30    /// Returns an error if the staging operation fails.
31    pub fn stage_all(&self) -> Result<()> {
32        let mut index = self.inner.index()?;
33
34        index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?;
35        index.write()?;
36
37        Ok(())
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::super::tests::setup_test_repo;
44    use std::fs;
45    use std::path::Path;
46
47    #[test]
48    fn stage_single_file() -> anyhow::Result<()> {
49        let (dir, repo) = setup_test_repo()?;
50
51        fs::write(dir.path().join("file.txt"), "content")?;
52
53        repo.stage_files(&[Path::new("file.txt")])?;
54
55        let index = repo.inner.index()?;
56        assert!(index.get_path(Path::new("file.txt"), 0).is_some());
57
58        Ok(())
59    }
60
61    #[test]
62    fn stage_multiple_files() -> anyhow::Result<()> {
63        let (dir, repo) = setup_test_repo()?;
64
65        fs::write(dir.path().join("file1.txt"), "content1")?;
66        fs::write(dir.path().join("file2.txt"), "content2")?;
67
68        repo.stage_files(&[Path::new("file1.txt"), Path::new("file2.txt")])?;
69
70        let index = repo.inner.index()?;
71        assert!(index.get_path(Path::new("file1.txt"), 0).is_some());
72        assert!(index.get_path(Path::new("file2.txt"), 0).is_some());
73
74        Ok(())
75    }
76
77    #[test]
78    fn stage_all_files() -> anyhow::Result<()> {
79        let (dir, repo) = setup_test_repo()?;
80
81        fs::write(dir.path().join("file1.txt"), "content1")?;
82        fs::write(dir.path().join("file2.txt"), "content2")?;
83
84        repo.stage_all()?;
85
86        let index = repo.inner.index()?;
87        assert!(index.get_path(Path::new("file1.txt"), 0).is_some());
88        assert!(index.get_path(Path::new("file2.txt"), 0).is_some());
89
90        Ok(())
91    }
92
93    #[test]
94    fn stage_deleted_file() -> anyhow::Result<()> {
95        let (dir, repo) = setup_test_repo()?;
96
97        fs::write(dir.path().join("file.txt"), "content")?;
98        repo.stage_files(&[Path::new("file.txt")])?;
99
100        let sig = git2::Signature::now("Test", "test@example.com")?;
101        let mut index = repo.inner.index()?;
102        let tree_id = index.write_tree()?;
103        let tree = repo.inner.find_tree(tree_id)?;
104        let parent = repo.inner.head()?.peel_to_commit()?;
105        repo.inner
106            .commit(Some("HEAD"), &sig, &sig, "Add file", &tree, &[&parent])?;
107
108        fs::remove_file(dir.path().join("file.txt"))?;
109        repo.stage_files(&[Path::new("file.txt")])?;
110
111        let index = repo.inner.index()?;
112        assert!(index.get_path(Path::new("file.txt"), 0).is_none());
113
114        Ok(())
115    }
116}