add commit browse
This commit is contained in:
@@ -273,6 +273,42 @@ pub fn worktree_last_commit(workdir: &Path, rel: &Path) -> Result<Option<FileCom
|
||||
last_commit(&gix::open(workdir)?, rel)
|
||||
}
|
||||
|
||||
/// All commits reachable from `HEAD`, newest first, with author and summary.
|
||||
/// Returns `Ok(vec![])` for a repository without any commits yet.
|
||||
pub fn all_commits(repo: &gix::Repository) -> Result<Vec<FileCommit>> {
|
||||
use gix::traverse::commit::simple::CommitTimeOrder;
|
||||
|
||||
let Some(head) = repo.head_id().ok() else {
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
let walk = repo
|
||||
.rev_walk([head])
|
||||
.sorting(gix::revision::walk::Sorting::ByCommitTime(
|
||||
CommitTimeOrder::NewestFirst,
|
||||
));
|
||||
|
||||
let mut commits = Vec::new();
|
||||
for info in walk.all()? {
|
||||
let info = info?;
|
||||
let commit = info.object()?;
|
||||
let author = commit.author()?;
|
||||
let message = commit.message()?;
|
||||
commits.push(FileCommit {
|
||||
id: commit.id().shorten_or_id().to_string(),
|
||||
summary: String::from_utf8_lossy(message.title).trim().to_string(),
|
||||
author: String::from_utf8_lossy(author.name).trim().to_string(),
|
||||
time: author.time()?.seconds,
|
||||
});
|
||||
}
|
||||
Ok(commits)
|
||||
}
|
||||
|
||||
/// Like [`all_commits`], but opens the repository located at `workdir`
|
||||
/// (for non-bare clones the clone root is the worktree) first.
|
||||
pub fn worktree_all_commits(workdir: &Path) -> Result<Vec<FileCommit>> {
|
||||
all_commits(&gix::open(workdir)?)
|
||||
}
|
||||
|
||||
fn collect_entries(root: &Path, dir: &Path, out: &mut Vec<(PathBuf, bool)>) -> Result<()> {
|
||||
for entry in std::fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
@@ -436,6 +472,34 @@ mod tests {
|
||||
assert!(commit.time > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_commits_lists_every_commit() {
|
||||
let (dir, repo) = fixture(&[("a.txt", b"one")]);
|
||||
commit_all(&repo, "initial");
|
||||
|
||||
std::fs::write(dir.path().join("a.txt"), b"two").expect("write");
|
||||
commit_all(&repo, "second");
|
||||
std::fs::write(dir.path().join("b.txt"), b"b").expect("write");
|
||||
commit_all(&repo, "third");
|
||||
|
||||
let commits = all_commits(&repo).expect("commits");
|
||||
let mut summaries: Vec<&str> = commits.iter().map(|c| c.summary.as_str()).collect();
|
||||
summaries.sort();
|
||||
assert_eq!(summaries, vec!["initial", "second", "third"]);
|
||||
assert!(
|
||||
commits
|
||||
.iter()
|
||||
.all(|c| c.author == "Test Author" && !c.id.is_empty() && c.time > 0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_commits_returns_empty_without_head() {
|
||||
let (_dir, repo) = fixture(&[("a.txt", b"one")]);
|
||||
|
||||
assert!(all_commits(&repo).expect("commits").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_commit_returns_none_for_untracked_files() {
|
||||
let (dir, repo) = fixture(&[("a.txt", b"one")]);
|
||||
|
||||
Reference in New Issue
Block a user