gix/repository/
diff.rs

1use gix_object::TreeRefIter;
2
3use crate::{
4    repository::{diff_resource_cache, diff_tree_to_tree},
5    Repository, Tree,
6};
7
8/// Diff-utilities
9impl Repository {
10    /// Create a resource cache for diffable objects, and configured with everything it needs to know to perform diffs
11    /// faithfully just like `git` would.
12    /// `mode` controls what version of a resource should be diffed.
13    /// `worktree_roots` determine if files can be read from the worktree, where each side of the diff operation can
14    /// be represented by its own worktree root. `.gitattributes` are automatically read from the worktree if at least
15    /// one worktree is present.
16    ///
17    /// Note that attributes will always be obtained from the current `HEAD` index even if the resources being diffed
18    /// might live in another tree. Further, if one of the `worktree_roots` are set, attributes will also be read from
19    /// the worktree. Otherwise, it will be skipped and attributes are read from the index tree instead.
20    pub fn diff_resource_cache(
21        &self,
22        mode: gix_diff::blob::pipeline::Mode,
23        worktree_roots: gix_diff::blob::pipeline::WorktreeRoots,
24    ) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
25        let index = self.index_or_load_from_head_or_empty()?;
26        Ok(crate::diff::resource_cache(
27            self,
28            mode,
29            self.attributes_only(
30                &index,
31                if worktree_roots.is_unset() {
32                    gix_worktree::stack::state::attributes::Source::IdMapping
33                } else {
34                    gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping
35                },
36            )?
37            .inner,
38            worktree_roots,
39        )?)
40    }
41
42    /// Produce the changes that would need to be applied to `old_tree` to create `new_tree`.
43    /// If `options` are unset, they will be filled in according to the git configuration of this repository, and with
44    /// [full paths being tracked](crate::diff::Options::track_path()) as well, which typically means that
45    /// rewrite tracking might be disabled if done so explicitly by the user.
46    /// If `options` are set, the user can take full control over the settings.
47    ///
48    /// Note that this method exists to evoke similarity to `git2`, and makes it easier to fully control diff settings.
49    /// A more fluent version [may be used as well](Tree::changes()).
50    pub fn diff_tree_to_tree<'a, 'old_repo: 'a, 'new_repo: 'a>(
51        &self,
52        old_tree: impl Into<Option<&'a Tree<'old_repo>>>,
53        new_tree: impl Into<Option<&'a Tree<'new_repo>>>,
54        options: impl Into<Option<crate::diff::Options>>,
55    ) -> Result<Vec<crate::object::tree::diff::ChangeDetached>, diff_tree_to_tree::Error> {
56        let mut cache = self.diff_resource_cache(gix_diff::blob::pipeline::Mode::ToGit, Default::default())?;
57        let opts = options
58            .into()
59            .map_or_else(|| crate::diff::Options::from_configuration(&self.config), Ok)?
60            .into();
61
62        let empty_tree = self.empty_tree();
63        let old_tree = old_tree.into().unwrap_or(&empty_tree);
64        let new_tree = new_tree.into().unwrap_or(&empty_tree);
65        let mut out = Vec::new();
66        gix_diff::tree_with_rewrites(
67            TreeRefIter::from_bytes(&old_tree.data),
68            TreeRefIter::from_bytes(&new_tree.data),
69            &mut cache,
70            &mut Default::default(),
71            &self.objects,
72            |change| -> Result<_, std::convert::Infallible> {
73                out.push(change.into_owned());
74                Ok(gix_diff::tree_with_rewrites::Action::Continue)
75            },
76            opts,
77        )?;
78        Ok(out)
79    }
80
81    /// Return a resource cache suitable for diffing blobs from trees directly, where no worktree checkout exists.
82    ///
83    /// For more control, see [`diff_resource_cache()`](Self::diff_resource_cache).
84    pub fn diff_resource_cache_for_tree_diff(&self) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
85        self.diff_resource_cache(
86            gix_diff::blob::pipeline::Mode::ToGit,
87            gix_diff::blob::pipeline::WorktreeRoots::default(),
88        )
89    }
90}