git2-rs
git2-rs copied to clipboard
[Documentation] Improve revwalk examples. Finding last change to file?
The revwalk documentation is unclear about how to find the last commit changing a file (a pretty basic usage).
Example:
fn recipe_modified(path: PathBuf) -> Result<i32, Box<dyn Error>> {
let repo = git2::Repository::discover(path)?;
let mut revwalk = repo.revwalk()?;
revwalk.push_head()?;
revwalk.set_sorting(git2::Sort::TIME)?;
for rev in revwalk {
let commit = repo.find_commit(rev?)?;
let message = commit.summary_bytes().unwrap_or_else(|| commit.message_bytes());
println!("{}\t{}", commit.id(), String::from_utf8_lossy(message));
}
Ok(0)
}
Here, provided a git repo, we pull all of the commits for it.. but I don't see a clear way to:
- Check the files included in a commit.
- Revwalk only on commits impacting a file.
This seems like a really common usage scenario, but little documentation on it,
same problem, I try to get files changes
I have the same issue. Does anyone solved it already?
git2-rs is a basic wrapper around libgit2, functionality you miss in here that are not rust specific are better adressed in upstream: https://github.com/libgit2/libgit2
pretty sure this question came up there already
for each revision you walk over you can use diff_tree_to_tree to find the files the commit touched.
gitui uses something like that to show a diff of a commit: https://github.com/extrawurst/gitui/blob/master/asyncgit/src/sync/commit_files.rs#L42
Thank you for this suggestion.
I am actually doing this. I just figured, that my code had different issues making it buggy.
One thing is bugging me though: The git2::Delta has no "Merged" status. So, if the last commit message was done before a merge, it shows me the merge message of the commit. But I want to have the commit message of the last modification. Do you have a hint on how to get that?
Old thread, but first google result. Here's some further pointers that I've used:
- Sort order should be set to
Sort::TOPOLOGICAL, notSort::Time. Times on commits can be arbitrary, and are not reliable to sort on. TOPOLOGICAL sorts according to the real git history, matching the behaviour of e.g.git log. - Use
revwalk.simplify_first_parent()to ignore the history of merged in branches. This will still include the merge commits themselves, but it won't walk the individual commits of the branch1. This is useful, because with this option enabled successive commits in the revwalk are always actual successive commits in the history (i.e. child then parent). Without this option revwalk will visit all branches of the history, and as a result successive revs in the iterable do not necessarily have a child-parent relation, and thus we can't directly compare them to find in which commit files have changed. - With the above 2, revwalk will give us a linear history, and we can compare successive commits in the revwalk to find out what has changed where. We can either use
diff_tree_to_tree(as @extrawurst suggested) to get the full changes between commits, or if you're only interested in a single file, you can compare thefile_id2 of its path between successive commits to see where the file has changed.
- I suppose that if you want to walk through the history of the merged-in branches then you could start a new revwalk that only includes the commits for that specific branch. This way, we're still only ever dealing with linear histories. I haven't tried this myself though.
- To get the file id:
let commit = repo.find_commit(rev)?; let tree = repo.find_tree(commit.tree_id())?; let file_id = tree.get_path(Path::new(file_path_str)).ok();