113 lines · 3.8 KB · Rust
RawDownload
use gix::bstr::{BString, ByteSlice};use gix::objs::tree::EntryMode;use gix::odb::store::RefreshMode;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()?));    repo.objects.refresh = RefreshMode::Never;     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}