使用 libgit2 高效地获取 git 存储库中的作者列表

get the list of authors in a git repository efficiently with libgit2

我需要获取 git 存储库的作者列表,就像 git shortlog -s 在命令行中所做的那样。

我目前正在做的工作是进行一次 revwalk(遍历所有修订)并一次收集所有提交的作者列表,但这非常慢,尤其是与到命令行 git 命令。

我正在使用 Rust,但我希望解决方案在 C 或其他绑定到 lib 的语言中类似git2。

这是我当前工作但速度较慢的代码:

        let repo = Repository::open(&git_path)?;
        let mut revwalk = repo.revwalk()?;
        revwalk.push_head()?;
        let mut authors: Vec<String> = revwalk
            .map(|r| {
                let oid = r?;
                repo.find_commit(oid)
            })
            .filter_map(|c| match c {
                Ok(commit) => Some(commit),
                Err(e) => {
                    println!("Error walking the revisions {}, skipping", e);
                    None
                }
            })
            .fold(HashSet::new(), |mut sofar, cur| {
                if let Some(name) = cur.author().name() {
                    sofar.insert(name.to_string());
                }
                sofar
            })
            .into_iter()
            .collect();
        authors.sort();

EDIT 好的,在发布模式下使用 Rust 构建时速度明显更快。我仍然想知道是否还有更有效的方法。

不幸的是,没有更有效的方法,除非您对存储库结构有所了解(例如,特定点之前的所有提交都是由特定用户进行的)。如果您想了解有关每个提交的信息,则必须遍历每个提交。 Git 不提供此信息的缓存,因此需要遍历历史记录。

libgit2 更通用一些,可能无法利用与 Git 本身相同的优化,但整体算法是相同的。

通用算法已尽善尽美:您必须遍历每次提交才能收集所有作者姓名,没有办法绕过它。

Nitpick:您正在为每个提交的作者姓名分配 String。首先检查名称是否已经在集合中可能会更快,它仅适用于 &str (!sofar.contains(name)).

在夜间,您可以将 sofar.insert(name.to_string()); 更改为 sofar.get_or_insert_with(name, str::to_string);get_or_insert_with 将只执行一次查找,而不是使用 contains/insert 对执行两次查找。