如何在存储库历史记录中的每个git commit中查找字数?

Ami*_*ale 3 git perl sed commit

这是关于字数统计的,但我想它也是关​​于在存储库中所有git commit上运行任何程序的。我正在做一个写作项目,后来才意识到我想在每次提交后以编程方式生成字数统计。仅用于tex文件。但是,如何获得项目生命周期的计数呢?我找不到简单的方法来做,所以这就是我要的。

我的解决方案是自动执行手动过程,即在项目生命周期中为每个提交签出一个分支,然后运行我的小shell / sed / perl脚本来获取日期和字数:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.014;
use App::gh::Git;
use IPC::System::Simple qw(capture);

my $repo = Git->repository( Directory => '/home/amiri/MyProject/.git' );
my @commits
    = reverse $repo->command( 'rev-list', '--all', '--date', 'short' );

my $command
    = qq{find /home/amiri/MyProject -name "*.tex" | xargs wc -w | grep total | sed 's/[a-zA-Z[:space:]]//g'};

my $command2
    = q{git log | grep "Date:" | sed -n 1p | perl -pi -e "s/^Date:\s+//g" | perl -pi -e "s/2011 -\d+$/UTC 2011/g"};

for my $commit (@commits) {
    $repo->command( "checkout", "-b", "$commit", "$commit" );
    my $count = capture($command);
    my $date  = capture($command2);
    chomp $date;
    say "$date,$count";
    $repo->command( "checkout", "master" );
    $repo->command( 'branch', "-d", $commit );
}
Run Code Online (Sandbox Code Playgroud)

所以,这可行,但是我不禁感到有更好的方法吗?似乎有点恶心。

Cas*_*bel 5

如果您想要更容易实现的东西,并且不介意有些次优和混乱,则可以执行以下操作:

for commit in `git rev-list --all`; do
    git log -n 1 --pretty=%ad $commit
    git archive $commit | tar -x -O | wc -w
done
Run Code Online (Sandbox Code Playgroud)

这比您所拥有的要短得多,而且我怀疑它可能还会更快,因为它避免了将文件检出到磁盘以再次读取它们以计数字数的麻烦。(要仅将其限制为某些文件,可以将它们作为其他参数传递给git archive,并注意,您可以使用来获得给定提交中所有文件的列表git ls-tree -r --name-only <commit>。)

git log行仅显示提交日期。如果您想要更多,请查看一下man git-log您可以做的事情的描述-基本上有很多占位符,例如%ad作者日期,%s提交主题等。下一行完成工作。git archive用于将给定的树打包成tar / zip进行分发;我们只是立即解压缩并计算单词数。(显然,您可以调整输出格式,并wc -w根据需要替换为自己的计数机制。)

这已经非常快了-在拥有数年历史的笔记本电脑上,一次回购大约需要四分之一秒才能完成,其中包含20MB的工作树。

当然,如果您真的很在乎性能,那么绝对最快的方法可能是每次提交都要走一棵树,对Blob上的字数求和,并为每个Blob存储字数,这样就不必重新计数他们。但是,这需要大量工作。伪代码可能如下所示:

word_counts(range)
    for (commit in `git rev-list <range>`)
        sum = 0
        for (blob in second_field_of(`git ls-tree -r commit`))
            if (!counts[blob])
                counts[blob] = word_count(`git cat-file blob`)
             total_count += counts[blob]
         print pretty_format(commit), total_count

 pretty_format(commit)
     return `git log -n 1 --pretty=... commit`
Run Code Online (Sandbox Code Playgroud)

这避免了任何不必要的中间步骤,并且通过避免必须重新读取任何未更改的文件来进一步优化。在很小的存储库中,这可能没什么大不了的,但是在较大的存储库中,这是一笔不小的交易-想象一个20MB的存储库,其中平均总大小为20KB的触摸文件提交。