use gix_object::TreeRefIter; use crate::{ Repository, Tree, repository::{diff_resource_cache, diff_tree_to_tree},}; /// Diff-utilitiesimpl Repository { /// Create a resource cache for diffable objects, and configured with everything it needs to know to perform diffs /// faithfully just like `git` would. /// `mode` controls what version of a resource should be diffed. /// `worktree_roots` determine if files can be read from the worktree, where each side of the diff operation can /// be represented by its own worktree root. `.gitattributes` are automatically read from the worktree if at least /// one worktree is present. /// /// Note that attributes will always be obtained from the current `HEAD` index even if the resources being diffed /// might live in another tree. Further, if one of the `worktree_roots` are set, attributes will also be read from /// the worktree. Otherwise, it will be skipped and attributes are read from the index tree instead. pub fn diff_resource_cache( &self, mode: gix_diff::blob::pipeline::Mode, worktree_roots: gix_diff::blob::pipeline::WorktreeRoots, ) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> { let index = self.index_or_load_from_head_or_empty()?; Ok(crate::diff::resource_cache( self, mode, self.attributes_only( &index, if worktree_roots.is_unset() { gix_worktree::stack::state::attributes::Source::IdMapping } else { gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping }, )? .inner, worktree_roots, )?) } /// Produce the changes that would need to be applied to `old_tree` to create `new_tree`. /// If `options` are unset, they will be filled in according to the git configuration of this repository, and with /// [full paths being tracked](crate::diff::Options::track_path()) as well, which typically means that /// rewrite tracking might be disabled if done so explicitly by the user. /// If `options` are set, the user can take full control over the settings. /// /// Note that this method exists to evoke similarity to `git2`, and makes it easier to fully control diff settings. /// A more fluent version [may be used as well](Tree::changes()). pub fn diff_tree_to_tree<'a, 'old_repo: 'a, 'new_repo: 'a>( &self, old_tree: impl Into<Option<&'a Tree<'old_repo>>>, new_tree: impl Into<Option<&'a Tree<'new_repo>>>, options: impl Into<Option<crate::diff::Options>>, ) -> Result<Vec<crate::object::tree::diff::ChangeDetached>, diff_tree_to_tree::Error> { let mut cache = self.diff_resource_cache(gix_diff::blob::pipeline::Mode::ToGit, Default::default())?; let opts = options .into() .map_or_else(|| crate::diff::Options::from_configuration(&self.config), Ok)? .into(); let empty_tree = self.empty_tree(); let old_tree = old_tree.into().unwrap_or(&empty_tree); let new_tree = new_tree.into().unwrap_or(&empty_tree); let mut out = Vec::new(); gix_diff::tree_with_rewrites( TreeRefIter::from_bytes(&old_tree.data, old_tree.id.kind()), TreeRefIter::from_bytes(&new_tree.data, new_tree.id.kind()), &mut cache, &mut Default::default(), &self.objects, |change| -> Result<_, std::convert::Infallible> { out.push(change.into_owned()); Ok(std::ops::ControlFlow::Continue(())) }, opts, )?; Ok(out) } /// Return a resource cache suitable for diffing blobs from trees directly, where no worktree checkout exists. /// /// For more control, see [`diff_resource_cache()`](Self::diff_resource_cache). pub fn diff_resource_cache_for_tree_diff(&self) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> { self.diff_resource_cache( gix_diff::blob::pipeline::Mode::ToGit, gix_diff::blob::pipeline::WorktreeRoots::default(), ) }}
use gix_object::TreeRefIter;
use crate::{
Repository, Tree,
repository::{diff_resource_cache, diff_tree_to_tree},
};
/// Diff-utilities
impl Repository {
/// Create a resource cache for diffable objects, and configured with everything it needs to know to perform diffs
/// faithfully just like `git` would.
/// `mode` controls what version of a resource should be diffed.
/// `worktree_roots` determine if files can be read from the worktree, where each side of the diff operation can
/// be represented by its own worktree root. `.gitattributes` are automatically read from the worktree if at least
/// one worktree is present.
///
/// Note that attributes will always be obtained from the current `HEAD` index even if the resources being diffed
/// might live in another tree. Further, if one of the `worktree_roots` are set, attributes will also be read from
/// the worktree. Otherwise, it will be skipped and attributes are read from the index tree instead.
pub fn diff_resource_cache(
&self,
mode: gix_diff::blob::pipeline::Mode,
worktree_roots: gix_diff::blob::pipeline::WorktreeRoots,
) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
let index = self.index_or_load_from_head_or_empty()?;
Ok(crate::diff::resource_cache(
self,
mode,
self.attributes_only(
&index,
if worktree_roots.is_unset() {
gix_worktree::stack::state::attributes::Source::IdMapping
} else {
gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping
},
)?
.inner,
worktree_roots,
)?)
}
/// Produce the changes that would need to be applied to `old_tree` to create `new_tree`.
/// If `options` are unset, they will be filled in according to the git configuration of this repository, and with
/// [full paths being tracked](crate::diff::Options::track_path()) as well, which typically means that
/// rewrite tracking might be disabled if done so explicitly by the user.
/// If `options` are set, the user can take full control over the settings.
///
/// Note that this method exists to evoke similarity to `git2`, and makes it easier to fully control diff settings.
/// A more fluent version [may be used as well](Tree::changes()).
pub fn diff_tree_to_tree<'a, 'old_repo: 'a, 'new_repo: 'a>(
&self,
old_tree: impl Into<Option<&'a Tree<'old_repo>>>,
new_tree: impl Into<Option<&'a Tree<'new_repo>>>,
options: impl Into<Option<crate::diff::Options>>,
) -> Result<Vec<crate::object::tree::diff::ChangeDetached>, diff_tree_to_tree::Error> {
let mut cache = self.diff_resource_cache(gix_diff::blob::pipeline::Mode::ToGit, Default::default())?;
let opts = options
.into()
.map_or_else(|| crate::diff::Options::from_configuration(&self.config), Ok)?
.into();
let empty_tree = self.empty_tree();
let old_tree = old_tree.into().unwrap_or(&empty_tree);
let new_tree = new_tree.into().unwrap_or(&empty_tree);
let mut out = Vec::new();
gix_diff::tree_with_rewrites(
TreeRefIter::from_bytes(&old_tree.data, old_tree.id.kind()),
TreeRefIter::from_bytes(&new_tree.data, new_tree.id.kind()),
&mut cache,
&mut Default::default(),
&self.objects,
|change| -> Result<_, std::convert::Infallible> {
out.push(change.into_owned());
Ok(std::ops::ControlFlow::Continue(()))
},
opts,
)?;
Ok(out)
}
/// Return a resource cache suitable for diffing blobs from trees directly, where no worktree checkout exists.
///
/// For more control, see [`diff_resource_cache()`](Self::diff_resource_cache).
pub fn diff_resource_cache_for_tree_diff(&self) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
self.diff_resource_cache(
gix_diff::blob::pipeline::Mode::ToGit,
gix_diff::blob::pipeline::WorktreeRoots::default(),
)
}
}