Skip to main content

grit_lib/diff/
handle.rs

1//! Repository-scoped tree and index diffs via [`Diff`].
2use crate::diff::targets::collect_files_for_target;
3use crate::diff::{diff_index_to_tree, diff_index_to_worktree, diff_trees, DiffEntry, DiffOptions};
4use crate::diff::{DiffTarget, FileDiff};
5use crate::error::Result;
6use crate::index::Index;
7use crate::objects::ObjectId;
8use crate::repo::Repository;
9
10/// Compare trees, the index, and the working tree for one repository.
11#[derive(Debug, Copy, Clone)]
12pub struct Diff<'repo> {
13    repo: &'repo Repository,
14}
15
16impl<'repo> Diff<'repo> {
17    /// Bind diff helpers to `repo`.
18    #[inline]
19    #[must_use]
20    pub fn new(repo: &'repo Repository) -> Self {
21        Self { repo }
22    }
23
24    /// Underlying repository.
25    #[inline]
26    #[must_use]
27    pub fn repository(&self) -> &'repo Repository {
28        self.repo
29    }
30
31    /// Diff two tree oids (either side may be `None` for an empty tree).
32    ///
33    /// # Errors
34    ///
35    /// Propagates ODB read and tree walk errors.
36    ///
37    /// # Examples
38    ///
39    /// See the library guide on [diffing](https://grit-scm.com/docs/library/diff/).
40    #[inline]
41    pub fn tree_to_tree(
42        &self,
43        old_tree: Option<&ObjectId>,
44        new_tree: Option<&ObjectId>,
45    ) -> Result<Vec<DiffEntry>> {
46        diff_trees(self.repo.odb(), old_tree, new_tree, "")
47    }
48
49    /// Diff the index against a tree (typically `HEAD`'s tree).
50    ///
51    /// # Errors
52    ///
53    /// Propagates ODB and index diff errors.
54    #[inline]
55    pub fn index_to_tree(
56        &self,
57        index: &Index,
58        tree_oid: Option<&ObjectId>,
59        ignore_submodules: bool,
60    ) -> Result<Vec<DiffEntry>> {
61        diff_index_to_tree(self.repo.odb(), index, tree_oid, ignore_submodules)
62    }
63
64    /// Diff the working tree against the index.
65    ///
66    /// # Errors
67    ///
68    /// Returns an error when the repository has no work tree or diff I/O fails.
69    #[inline]
70    pub fn worktree_to_index(
71        &self,
72        index: &mut Index,
73        ignore_submodule_untracked: bool,
74        simplify_gitlinks: bool,
75    ) -> Result<Vec<DiffEntry>> {
76        let work_tree = self
77            .repo
78            .work_tree()
79            .ok_or(crate::error::Error::RequiresWorkTree)?;
80        diff_index_to_worktree(
81            self.repo.odb(),
82            index,
83            work_tree,
84            ignore_submodule_untracked,
85            simplify_gitlinks,
86        )
87    }
88
89    /// Structured per-file diffs for `target`, honoring `pathspecs` and line-diff `opts`.
90    ///
91    /// # Errors
92    ///
93    /// Propagates index, ODB, and worktree diff failures.
94    pub fn files(
95        &self,
96        target: &DiffTarget,
97        pathspecs: &[String],
98        opts: &DiffOptions,
99    ) -> Result<Vec<FileDiff>> {
100        collect_files_for_target(self.repo, target, pathspecs, opts.clone())
101    }
102}