1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Repository-scoped tree and index diffs via [`Diff`].
use crate::diff::targets::collect_files_for_target;
use crate::diff::{
diff_index_to_tree, diff_index_to_worktree, diff_trees, diff_trees_with_renames_and_policy,
DiffEntry, DiffOptions,
};
use crate::diff::{DiffTarget, FileDiff, UncommittedDiff};
use crate::error::Result;
use crate::index::Index;
use crate::objects::ObjectId;
use crate::repo::Repository;
/// Compare trees, the index, and the working tree for one repository.
#[derive(Debug, Copy, Clone)]
pub struct Diff<'repo> {
repo: &'repo Repository,
}
impl<'repo> Diff<'repo> {
/// Bind diff helpers to `repo`.
#[inline]
#[must_use]
pub fn new(repo: &'repo Repository) -> Self {
Self { repo }
}
/// Underlying repository.
#[inline]
#[must_use]
pub fn repository(&self) -> &'repo Repository {
self.repo
}
/// Diff two tree oids (either side may be `None` for an empty tree).
///
/// Reads tree metadata without loading blobs and skips identical subtree ids.
/// The walk retains active directory frames alongside the ODB's bounded tree
/// cache; the returned vector owns metadata for every changed path.
///
/// # Errors
///
/// Propagates ODB read and tree walk errors.
///
/// # Examples
///
/// See the library guide on [diffing](https://grit-scm.com/docs/library/diff/).
#[inline]
pub fn tree_to_tree(
&self,
old_tree: Option<&ObjectId>,
new_tree: Option<&ObjectId>,
) -> Result<Vec<DiffEntry>> {
diff_trees(self.repo.odb(), old_tree, new_tree, "")
}
/// Like [`Self::tree_to_tree`], then pair renames using `options.renames` (Git `-M`).
///
/// # Errors
///
/// Propagates ODB read, tree walk, and rename detection errors.
pub fn tree_to_tree_renames(
&self,
old_tree: Option<&ObjectId>,
new_tree: Option<&ObjectId>,
options: &DiffOptions,
) -> Result<Vec<DiffEntry>> {
let config = self.repo.config()?;
diff_trees_with_renames_and_policy(
self.repo.odb(),
old_tree,
new_tree,
"",
options.rename_threshold_u32(),
config.as_ref(),
&self.repo.thread_policy(),
)
}
/// Diff the index against a tree (typically `HEAD`'s tree).
///
/// # Errors
///
/// Propagates ODB and index diff errors.
#[inline]
pub fn index_to_tree(
&self,
index: &Index,
tree_oid: Option<&ObjectId>,
ignore_submodules: bool,
) -> Result<Vec<DiffEntry>> {
diff_index_to_tree(self.repo.odb(), index, tree_oid, ignore_submodules)
}
/// Diff the working tree against the index.
///
/// # Errors
///
/// Returns an error when the repository has no work tree or diff I/O fails.
#[inline]
pub fn worktree_to_index(
&self,
index: &mut Index,
ignore_submodule_untracked: bool,
simplify_gitlinks: bool,
) -> Result<Vec<DiffEntry>> {
let work_tree = self
.repo
.work_tree()
.ok_or(crate::error::Error::RequiresWorkTree)?;
diff_index_to_worktree(
self.repo.odb(),
index,
work_tree,
ignore_submodule_untracked,
simplify_gitlinks,
)
}
/// Staged, unstaged, and working-tree diffs over the repository's on-disk index.
///
/// # Errors
///
/// Returns index read errors.
pub fn uncommitted(&self) -> Result<UncommittedDiff<'repo>> {
let index = self.repo.index_handle().load_preserving_sparse()?;
Ok(UncommittedDiff::new(self.repo, index))
}
/// Structured per-file diffs for `target`, honoring `pathspecs` and line-diff `opts`.
///
/// # Errors
///
/// Propagates index, ODB, and worktree diff failures.
pub fn files(
&self,
target: &DiffTarget,
pathspecs: &[String],
opts: &DiffOptions,
) -> Result<Vec<FileDiff>> {
collect_files_for_target(self.repo, target, pathspecs, opts.clone())
}
}