diff --git a/src/cli.rs b/src/cli.rs index 2d2643a..3bf62f6 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -22,4 +22,6 @@ pub struct Arguments { /// Path to the git repository. #[arg(value_hint = ValueHint::DirPath, default_value = ".")] pub repository_path: PathBuf, + + pub subtree: Option, } diff --git a/src/main.rs b/src/main.rs index dd6efcb..f1c2c2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,10 +18,19 @@ fn main() -> anyhow::Result<()> { let repository = gix::open(arguments.repository_path)?; let mut current_commit = repository.resolve_revspec(&arguments.from)?; - let current_tree = current_commit + let mut current_tree = current_commit .tree() .context("Failed to get tree for initial commit")?; + if let Some(subtree) = &arguments.subtree { + let entry = current_tree + .lookup_entry_by_path(subtree)? + .expect("sub-tree not found"); + if entry.mode().is_tree() { + current_tree = repository.find_tree(entry.id())?; + } + } + // Build a set of the entry file names we are interested in. let mut interested: HashSet<_> = Default::default(); for entry in current_tree.iter() { @@ -69,10 +78,24 @@ fn main() -> anyhow::Result<()> { let parent_commit = repository .find_commit(parent_id) .context("Failed to find parent commit")?; - let parent_tree = parent_commit + let mut parent_tree = parent_commit .tree() .context("Failed to retrieve parent tree")?; + if let Some(subtree) = &arguments.subtree { + let Some(entry) = parent_tree.lookup_entry_by_path(subtree)? else { + // The subtree does not exist in this revision. Assume any + // remaining entries of interest belong to this commit. + for entry in interested.drain() { + output(entry.as_bstr(), ¤t_commit)?; + } + break; + }; + if entry.mode().is_tree() { + parent_tree = repository.find_tree(entry.id())?; + } + } + let mut scanner = EntryScanner::new(current_tree.iter(), parent_tree.iter())?; while let Some(change) = scanner.next_change()? { if interested.remove(change.filename()) {