gitoxide_core/repository/
diff.rsuse gix::bstr::{BString, ByteSlice};
use gix::objs::tree::EntryMode;
use gix::prelude::ObjectIdExt;
pub fn tree(
mut repo: gix::Repository,
out: &mut dyn std::io::Write,
old_treeish: BString,
new_treeish: BString,
) -> anyhow::Result<()> {
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?));
let old_tree_id = repo.rev_parse_single(old_treeish.as_bstr())?;
let new_tree_id = repo.rev_parse_single(new_treeish.as_bstr())?;
let old_tree = old_tree_id.object()?.peel_to_tree()?;
let new_tree = new_tree_id.object()?.peel_to_tree()?;
let changes = repo.diff_tree_to_tree(&old_tree, &new_tree, None)?;
writeln!(
out,
"Diffing trees `{old_treeish}` ({old_tree_id}) -> `{new_treeish}` ({new_tree_id})\n"
)?;
write_changes(&repo, out, changes)?;
Ok(())
}
fn write_changes(
repo: &gix::Repository,
mut out: impl std::io::Write,
changes: Vec<gix::diff::tree_with_rewrites::Change>,
) -> Result<(), std::io::Error> {
for change in changes {
match change {
gix::diff::tree_with_rewrites::Change::Addition {
location,
id,
entry_mode,
..
} => {
writeln!(out, "A: {}", typed_location(location, entry_mode))?;
writeln!(out, " {}", id.attach(repo).shorten_or_id())?;
writeln!(out, " -> {:o}", entry_mode.0)?;
}
gix::diff::tree_with_rewrites::Change::Deletion {
location,
id,
entry_mode,
..
} => {
writeln!(out, "D: {}", typed_location(location, entry_mode))?;
writeln!(out, " {}", id.attach(repo).shorten_or_id())?;
writeln!(out, " {:o} ->", entry_mode.0)?;
}
gix::diff::tree_with_rewrites::Change::Modification {
location,
previous_id,
id,
previous_entry_mode,
entry_mode,
} => {
writeln!(out, "M: {}", typed_location(location, entry_mode))?;
writeln!(
out,
" {previous_id} -> {id}",
previous_id = previous_id.attach(repo).shorten_or_id(),
id = id.attach(repo).shorten_or_id()
)?;
if previous_entry_mode != entry_mode {
writeln!(out, " {:o} -> {:o}", previous_entry_mode.0, entry_mode.0)?;
}
}
gix::diff::tree_with_rewrites::Change::Rewrite {
source_location,
source_id,
id,
location,
source_entry_mode,
entry_mode,
..
} => {
writeln!(
out,
"R: {source} -> {dest}",
source = typed_location(source_location, source_entry_mode),
dest = typed_location(location, entry_mode)
)?;
writeln!(
out,
" {source_id} -> {id}",
source_id = source_id.attach(repo).shorten_or_id(),
id = id.attach(repo).shorten_or_id()
)?;
if source_entry_mode != entry_mode {
writeln!(out, " {:o} -> {:o}", source_entry_mode.0, entry_mode.0)?;
}
}
};
}
Ok(())
}
fn typed_location(mut location: BString, mode: EntryMode) -> BString {
if mode.is_tree() {
location.push(b'/');
}
location
}