WIP: List the most recent change to each top-level entry in a git tree

feat: support sub-trees

Signed-off-by: tjh <did:plc:65gha4t3avpfpzmvpbwovss7>

authored by tjh.dev and committed by tjh.dev 8c1c2687 315666bf

verified
Changed files
+27 -2
src
+2
src/cli.rs
··· 22 22 /// Path to the git repository. 23 23 #[arg(value_hint = ValueHint::DirPath, default_value = ".")] 24 24 pub repository_path: PathBuf, 25 + 26 + pub subtree: Option<PathBuf>, 25 27 }
+25 -2
src/main.rs
··· 18 18 let repository = gix::open(arguments.repository_path)?; 19 19 20 20 let mut current_commit = repository.resolve_revspec(&arguments.from)?; 21 - let current_tree = current_commit 21 + let mut current_tree = current_commit 22 22 .tree() 23 23 .context("Failed to get tree for initial commit")?; 24 + 25 + if let Some(subtree) = &arguments.subtree { 26 + let entry = current_tree 27 + .lookup_entry_by_path(subtree)? 28 + .expect("sub-tree not found"); 29 + if entry.mode().is_tree() { 30 + current_tree = repository.find_tree(entry.id())?; 31 + } 32 + } 24 33 25 34 // Build a set of the entry file names we are interested in. 26 35 let mut interested: HashSet<_> = Default::default(); ··· 69 78 let parent_commit = repository 70 79 .find_commit(parent_id) 71 80 .context("Failed to find parent commit")?; 72 - let parent_tree = parent_commit 81 + let mut parent_tree = parent_commit 73 82 .tree() 74 83 .context("Failed to retrieve parent tree")?; 84 + 85 + if let Some(subtree) = &arguments.subtree { 86 + let Some(entry) = parent_tree.lookup_entry_by_path(subtree)? else { 87 + // The subtree does not exist in this revision. Assume any 88 + // remaining entries of interest belong to this commit. 89 + for entry in interested.drain() { 90 + output(entry.as_bstr(), &current_commit)?; 91 + } 92 + break; 93 + }; 94 + if entry.mode().is_tree() { 95 + parent_tree = repository.find_tree(entry.id())?; 96 + } 97 + } 75 98 76 99 let mut scanner = EntryScanner::new(current_tree.iter(), parent_tree.iter())?; 77 100 while let Some(change) = scanner.next_change()? {