Skip to content

Commit 0c554e0

Browse files
cruesslerByron
authored andcommitted
feat: add first 'debug' version of gix diff tree.
It's primarily meant to better understand `gix blame`.
1 parent 70c4df5 commit 0c554e0

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

Diff for: gitoxide-core/src/repository/diff.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use gix::bstr::{BString, ByteSlice};
2+
3+
pub fn tree(
4+
repo: gix::Repository,
5+
out: &mut dyn std::io::Write,
6+
old_treeish: BString,
7+
new_treeish: BString,
8+
) -> anyhow::Result<()> {
9+
let old_tree_id = repo.rev_parse_single(old_treeish.as_bstr())?;
10+
let new_tree_id = repo.rev_parse_single(new_treeish.as_bstr())?;
11+
12+
let old_tree = old_tree_id.object()?.peel_to_kind(gix::object::Kind::Tree)?.into_tree();
13+
let new_tree = new_tree_id.object()?.peel_to_kind(gix::object::Kind::Tree)?.into_tree();
14+
15+
let changes = repo.diff_tree_to_tree(&old_tree, &new_tree, None)?;
16+
17+
writeln!(
18+
out,
19+
"Diffing trees `{old_treeish}` ({old_tree_id}) -> `{new_treeish}` ({new_tree_id})"
20+
)?;
21+
writeln!(out)?;
22+
23+
write_changes(out, changes)?;
24+
25+
Ok(())
26+
}
27+
28+
fn write_changes(
29+
mut out: impl std::io::Write,
30+
changes: Vec<gix::diff::tree_with_rewrites::Change>,
31+
) -> Result<(), std::io::Error> {
32+
for change in changes {
33+
match change {
34+
gix::diff::tree_with_rewrites::Change::Addition {
35+
location,
36+
id,
37+
entry_mode,
38+
..
39+
} => {
40+
writeln!(out, "A: {location}")?;
41+
writeln!(out, " {id}")?;
42+
writeln!(out, " -> {:o}", entry_mode.0)?;
43+
}
44+
gix::diff::tree_with_rewrites::Change::Deletion {
45+
location,
46+
id,
47+
entry_mode,
48+
..
49+
} => {
50+
writeln!(out, "D: {location}")?;
51+
writeln!(out, " {id}")?;
52+
writeln!(out, " {:o} ->", entry_mode.0)?;
53+
}
54+
gix::diff::tree_with_rewrites::Change::Modification {
55+
location,
56+
previous_id,
57+
id,
58+
previous_entry_mode,
59+
entry_mode,
60+
} => {
61+
writeln!(out, "M: {location}")?;
62+
writeln!(out, " {previous_id} -> {id}")?;
63+
writeln!(out, " {:o} -> {:o}", previous_entry_mode.0, entry_mode.0)?;
64+
}
65+
gix::diff::tree_with_rewrites::Change::Rewrite {
66+
source_location,
67+
source_id,
68+
id,
69+
location,
70+
source_entry_mode,
71+
entry_mode,
72+
..
73+
} => {
74+
writeln!(out, "R: {source_location} -> {location}")?;
75+
writeln!(out, " {source_id} -> {id}")?;
76+
writeln!(out, " {:o} -> {:o}", source_entry_mode.0, entry_mode.0)?;
77+
}
78+
};
79+
}
80+
81+
Ok(())
82+
}

Diff for: gitoxide-core/src/repository/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub use credential::function as credential;
2828
pub mod attributes;
2929
#[cfg(feature = "clean")]
3030
pub mod clean;
31+
pub mod diff;
3132
pub mod dirty;
3233
#[cfg(feature = "clean")]
3334
pub use clean::function::clean;

Diff for: src/plumbing/main.rs

+16
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,22 @@ pub fn main() -> Result<()> {
189189
core::repository::merge_base(repository(Mode::Lenient)?, first, others, out, format)
190190
},
191191
),
192+
Subcommands::Diff(crate::plumbing::options::diff::Platform { cmd }) => match cmd {
193+
crate::plumbing::options::diff::SubCommands::Tree {
194+
old_treeish,
195+
new_treeish,
196+
} => prepare_and_run(
197+
"diff-tree",
198+
trace,
199+
verbose,
200+
progress,
201+
progress_keep_open,
202+
None,
203+
move |_progress, out, _err| {
204+
core::repository::diff::tree(repository(Mode::Lenient)?, out, old_treeish, new_treeish)
205+
},
206+
),
207+
},
192208
Subcommands::Worktree(crate::plumbing::options::worktree::Platform { cmd }) => match cmd {
193209
crate::plumbing::options::worktree::SubCommands::List => prepare_and_run(
194210
"worktree-list",

Diff for: src/plumbing/options/mod.rs

+25
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub enum Subcommands {
145145
Corpus(corpus::Platform),
146146
MergeBase(merge_base::Command),
147147
Merge(merge::Platform),
148+
Diff(diff::Platform),
148149
Worktree(worktree::Platform),
149150
/// Subcommands that need no git repository to run.
150151
#[clap(subcommand)]
@@ -384,6 +385,30 @@ pub mod merge {
384385
}
385386
}
386387

388+
pub mod diff {
389+
use gix::bstr::BString;
390+
391+
/// Print all changes between two objects
392+
#[derive(Debug, clap::Parser)]
393+
pub struct Platform {
394+
#[clap(subcommand)]
395+
pub cmd: SubCommands,
396+
}
397+
398+
#[derive(Debug, clap::Subcommand)]
399+
pub enum SubCommands {
400+
/// Diff two trees by specifying their revspecs.
401+
Tree {
402+
/// A revspec representing the before or old tree
403+
#[clap(value_parser = crate::shared::AsBString)]
404+
old_treeish: BString,
405+
/// A revspec representing the after or new tree
406+
#[clap(value_parser = crate::shared::AsBString)]
407+
new_treeish: BString,
408+
},
409+
}
410+
}
411+
387412
pub mod config {
388413
use gix::bstr::BString;
389414

0 commit comments

Comments
 (0)