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 { 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>>, new_tree: impl Into>>, options: impl Into>, ) -> Result, 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 { self.diff_resource_cache( gix_diff::blob::pipeline::Mode::ToGit, gix_diff::blob::pipeline::WorktreeRoots::default(), ) } }