如何计算Git存储库中特定作者更改的总行数?

Gav*_*Gav 420 git statistics command-line repository

是否有一个我可以调用的命令,它将计算Git存储库中特定作者更改的行?我知道必须有方法来计算提交次数,因为Github会为其影响图执行此操作.

Ale*_*lex 569

这提供了有关作者的一些统计信息,根据需要进行修改

使用Gawk:

git log --author="_Your_Name_Here_" --pretty=tformat: --numstat \
| gawk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s removed lines: %s total lines: %s\n", add, subs, loc }' -
Run Code Online (Sandbox Code Playgroud)

在Mac OSX上使用Awk:

git log --author="_Your_Name_Here_" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -
Run Code Online (Sandbox Code Playgroud)

编辑(2017)

在github上有一个新的包看起来很光滑,并使用bash作为依赖(在linux上测试).它更适合直接使用而不是脚本.

这是git-quick-stats(github链接).

复制git-quick-stats到文件夹并将文件夹添加到路径.

mkdir ~/source
cd ~/source
git clone git@github.com:arzzen/git-quick-stats.git
mkdir ~/bin
ln -s ~/source/git-quick-stats/git-quick-stats ~/bin/git-quick-stats
chmod +x ~/bin/git-quick-stats
export PATH=${PATH}:~/bin
Run Code Online (Sandbox Code Playgroud)

用法:

git-quick-stats
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 感谢这个可爱的长衬里!这个awk斑点擦拭了每个人的甲板(准确,快速,没有额外的奇怪输出).这并不奇怪,考虑到这就是awk的设计目的......太糟糕了,你这么晚才参加聚会. (18认同)
  • 这很棒,但我不得不将`gawk`更改为`awk`以使其在OSX终端中正常工作 (9认同)
  • @ zxq9:当问到这个问题时我甚至都没有在stackoverflow,我在这里得到了答案的启发.让我们希望我会慢慢超过这里的每个人,因为人们一直需要这个. (4认同)
  • 你实际上可以做 `brew install git-quick-stats` (4认同)
  • 如果该网址不适合您,请尝试以下操作:`git clone https:// github.com / arzzen / git-quick-stats.git` (2认同)

CB *_*ley 292

以下命令的输出应该相当容易发送到脚本以添加总计:

git log --author="<authorname>" --oneline --shortstat
Run Code Online (Sandbox Code Playgroud)

这为当前HEAD上的所有提交提供了统计信息.如果你想在其他分支中添加统计数据,你必须提供它们作为参数git log.

对于传递给脚本,甚至可以使用空日志格式删除"oneline"格式,并且由JakubNarębski评论,--numstat是另一种选择.它生成每个文件而不是每行统计信息,但更容易解析.

git log --author="<authorname>" --pretty=tformat: --numstat
Run Code Online (Sandbox Code Playgroud)

  • 如果你想更容易地添加统计数据,你可以使用`--numstat`而不是`--shortstat`. (13认同)
  • 对不起这个问题,但有什么数字告诉我?有两排,我不知道他们告诉我什么.线路变得稀少和添加? (9认同)
  • 可能也想在那里添加"--no-merges". (8认同)
  • 什么是--pretty = tformat do vs. --pretty = format? (5认同)
  • 改变了我接受的答案,因为这会以我期望的方式提供输出,并且对于希望实现此目的的其他访问者将更有帮助. (2认同)
  • @ Informatic0re`git help log`告诉我,第一行是添加的行,第二行是删除的。 (2认同)

Dan*_*Dan 199

如果有人想看到他们的代码库中每个用户的统计数据,我的几个同事最近提出了这个可怕的单行:

git log --shortstat --pretty="%cE" | sed 's/\(.*\)@.*/\1/' | grep -v "^$" | awk 'BEGIN { line=""; } !/^ / { if (line=="" || !match(line, $0)) {line = $0 "," line }} /^ / { print line " # " $0; line=""}' | sort | sed -E 's/# //;s/ files? changed,//;s/([0-9]+) ([0-9]+ deletion)/\1 0 insertions\(+\), \2/;s/\(\+\)$/\(\+\), 0 deletions\(-\)/;s/insertions?\(\+\), //;s/ deletions?\(-\)//' | awk 'BEGIN {name=""; files=0; insertions=0; deletions=0;} {if ($1 != name && name != "") { print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net"; files=0; insertions=0; deletions=0; name=$1; } name=$1; files+=$2; insertions+=$3; deletions+=$4} END {print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net";}'
Run Code Online (Sandbox Code Playgroud)

(花几分钟时间来处理我们的仓库,它有大约10-15k的提交.)

  • 棒极了!`michael ,:6057文件更改,854902插入(+),26973删除( - ),827929 net` (11认同)
  • 这是唯一一个为存储库提供总结果并且没有任何插件运行的命令. (11认同)
  • @Damon,我通过添加 --no-merges git log --shortstat --no-merges --pretty="%cE" 解决了列出在一起的用户的问题... (7认同)
  • 我将一堆用户列在一起,几乎所有可能的开发人员组合都回来了。我的结局很奇怪吗? (4认同)
  • @BenSewards你可以使用适用于Linux的Windows子系统在Windows上使用Bash,更多信息[这里](https://msdn.microsoft.com/commandline/wsl/about) (2认同)

Cir*_*四事件 139

Git成名 https://github.com/oleander/git-fame-rb

是一个很好的工具,可以同时获取所有作者的计数,包括提交和修改的文件数:

sudo apt-get install ruby-dev
sudo gem install git_fame
cd /path/to/gitdir && git fame
Run Code Online (Sandbox Code Playgroud)

还有https://github.com/casperdcl/git-fame的 Python版本(@fracz提到):

sudo apt-get install python-pip python-dev build-essential 
pip install --user git-fame
cd /path/to/gitdir && git fame
Run Code Online (Sandbox Code Playgroud)

样本输出:

Total number of files: 2,053
Total number of lines: 63,132
Total number of commits: 4,330

+------------------------+--------+---------+-------+--------------------+
| name                   | loc    | commits | files | percent            |
+------------------------+--------+---------+-------+--------------------+
| Johan Sørensen         | 22,272 | 1,814   | 414   | 35.3 / 41.9 / 20.2 |
| Marius Mathiesen       | 10,387 | 502     | 229   | 16.5 / 11.6 / 11.2 |
| Jesper Josefsson       | 9,689  | 519     | 191   | 15.3 / 12.0 / 9.3  |
| Ole Martin Kristiansen | 6,632  | 24      | 60    | 10.5 / 0.6 / 2.9   |
| Linus Oleander         | 5,769  | 705     | 277   | 9.1 / 16.3 / 13.5  |
| Fabio Akita            | 2,122  | 24      | 60    | 3.4 / 0.6 / 2.9    |
| August Lilleaas        | 1,572  | 123     | 63    | 2.5 / 2.8 / 3.1    |
| David A. Cuadrado      | 731    | 111     | 35    | 1.2 / 2.6 / 1.7    |
| Jonas Ängeslevä        | 705    | 148     | 51    | 1.1 / 3.4 / 2.5    |
| Diego Algorta          | 650    | 6       | 5     | 1.0 / 0.1 / 0.2    |
| Arash Rouhani          | 629    | 95      | 31    | 1.0 / 2.2 / 1.5    |
| Sofia Larsson          | 595    | 70      | 77    | 0.9 / 1.6 / 3.8    |
| Tor Arne Vestbø        | 527    | 51      | 97    | 0.8 / 1.2 / 4.7    |
| spontus                | 339    | 18      | 42    | 0.5 / 0.4 / 2.0    |
| Pontus                 | 225    | 49      | 34    | 0.4 / 1.1 / 1.7    |
+------------------------+--------+---------+-------+--------------------+
Run Code Online (Sandbox Code Playgroud)

但要注意:正如Jared在评论中所提到的那样,在一个非常大的存储库上进行它需要几个小时.不确定是否可以改进,考虑到它必须处理如此多的Git数据.

  • 在 2015 年中期的 macbook 和中型 Android 项目(127k LoC'is)上运行良好。几分钟。 (2认同)
  • @Vincent当前用户的toal loc/commits/files的百分比. (2认同)
  • 还有[python中的git成名](https://pypi.python.org/pypi/git-fame/1.1.0). (2认同)

mmr*_*ins 103

我发现以下内容对于查看当前代码库中包含最多行的人员非常有用:

git ls-files -z | xargs -0n1 git blame -w | ruby -n -e '$_ =~ /^.*\((.*?)\s[\d]{4}/; puts $1.strip' | sort -f | uniq -c | sort -n
Run Code Online (Sandbox Code Playgroud)

其他答案主要集中在提交中更改的行,但如果提交无法生存并被覆盖,则可能只是流失.上面的咒语也会让你所有提交者按行排序,而不是一次只有一个.您可以为git blame(-C -M)添加一些选项,以获得一些更好的数字,以便将文件移动和文件之间的行移动考虑在内,但是如果这样做,命令可能会运行更长时间.

此外,如果您要查找所有提交的所有提交中更改的行,则以下小脚本很有用:

http://git-wt-commit.rubyforge.org/#git-rank-contributors

  • 我准备给+1,但后来我意识到解决方案取决于红宝石...... :( (31认同)
  • 对我不起作用:-e:1:在`<main>'中:UTF-8中的无效字节序列(ArgumentError) (20认同)
  • 您可以将其修改为不容易使用ruby,因为我只使用ruby进行字符串替换.你可以使用perl,sed,python等 (3认同)

Jak*_*ski 88

要计算给定分支上给定作者(或所有作者)的提交次数,您可以使用git-shortlog ; 特别参见它--numbered--summary选项,例如在git仓库上运行时:

$ git shortlog v1.6.4 --numbered --summary
  6904  Junio C Hamano
  1320  Shawn O. Pearce
  1065  Linus Torvalds
    692  Johannes Schindelin
    443  Eric Wong
Run Code Online (Sandbox Code Playgroud)

  • 啊,不,我错过了"在git存储库上运行时".公平地说,大多数人*不会在git repo上运行此命令.实际上,相当大的余地. (5认同)
  • `git shortlog -sne`或者,如果你不想包括合并`git shortlog -sne --no-merges` (4认同)
  • -1它没有回答这个问题 (3认同)
  • 请注意,在此示例中,`v1.6.4`是为了使输出具有确定性:无论何时从git存储库进行克隆和/或获取,它都是相同的. (2认同)

Jar*_*ows 71

在看了AlexGerty3000的答案后,我试图缩短单线:

基本上,使用git log numstat并且跟踪已更改的文件数.

Mac OSX上的Git版本2.1.0:

git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done
Run Code Online (Sandbox Code Playgroud)

例:

Jared Burrows   added lines: 6826, removed lines: 2825, total lines: 4001
Run Code Online (Sandbox Code Playgroud)


Eri*_*vic 29

来自AaronM的使用shell 单行答案是好的,但实际上,还有另一个错误,如果用户名和日期之间有不同数量的空格,空格将破坏用户名.损坏的用户名将为用户计数提供多行,您必须自己总结它们.

这个小改动为我解决了这个问题:

git ls-files -z | xargs -0n1 git blame -w --show-email | perl -n -e '/^.*?\((.*?)\s+[\d]{4}/; print $1,"\n"' | sort -f | uniq -c | sort -n
Run Code Online (Sandbox Code Playgroud)

注意+ after后面会消耗从名称到日期的所有空格.

实际上添加这个答案对我自己的记忆和帮助其他人一样多,因为这至少是我第二次谷歌主题:)

  • 编辑2019-01-23添加--show-emailgit blame -w电子邮件聚合,因为有些人Name在不同的计算机上使用不同的格式,有时两个同名的人在同一个git中工作.


kcc*_*qzy 23

这是一个简短的单行程序,为所有作者生成统计数据.它比上面的Dan解决方案快得多,速度为/sf/answers/1429012581/(我的时间复杂度为O(N)而不是O(NM),其中N是提交数,M是作者数).

git log --no-merges --pretty=format:%an --numstat | awk '/./ && !author { author = $0; next } author { ins[author] += $1; del[author] += $2 } /^$/ { author = ""; next } END { for (a in ins) { printf "%10d %10d %10d %s\n", ins[a] - del[a], ins[a], del[a], a } }' | sort -rn
Run Code Online (Sandbox Code Playgroud)

  • 很好,但输出意味着什么? (4认同)
  • ins [a] - del [a],ins [a],del [a],a,所以如果我是正确的插入 - 删除,插入,删除,名称 (2认同)

Sté*_*hon 21

@mmrobins @AaronM @ErikZ @JamesMishra提供的变体都有一个共同的问题:他们要求git生成一个不用于脚本消费的信息混合,包括来自同一行上的存储库的行内容,然后将该混乱与正则表达式匹配.

当某些行不是有效的UTF-8文本时,以及当某些行恰好与正则表达式匹配时(这发生在这里),这是一个问题.

这是一条没有这些问题的修改过的行.它要求git在不同的行上干净地输出数据,这样可以很容易地过滤我们想要的内容:

git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n
Run Code Online (Sandbox Code Playgroud)

你可以grep其他字符串,如author-mail,committer等.

也许首先export LC_ALL=C(假设bash)强制执行字节级处理(这也恰好可以从基于UTF-8的语言环境中大大加快grep).


Aar*_*onM 16

在中间给出了ruby的解决方案,perl在默认情况下更加可用,这是作者对当前行使用perl的替代方案.

git ls-files -z | xargs -0n1 git blame -w | perl -n -e '/^.*\((.*?)\s*[\d]{4}/; print $1,"\n"' | sort -f | uniq -c | sort -n
Run Code Online (Sandbox Code Playgroud)

  • 更新的正则表达式并没有产生有意义的差异,并且因为你没有逃脱第一个paren而被打破.但是,我可以看到一些情况,我前一个可能会在代码行中找到一些要锁定的位.这样可以更可靠地工作:git ls-files -z | xargs -0n1 git blame -w | perl -n -e'/^.*?\\((.*?)\s[\d]{4}/; print $ 1,"\n"'| sort -f | uniq -c | sort -n (5认同)

Esk*_*ola 13

除了Charles Bailey的回答,您可能还想将-C参数添加到命令中.否则,文件重命名计为大量添加和删除(尽管文件有行数),即使文件内容未被修改也是如此.

为了说明,这里是一个提交,在使用git log --oneline --shortstat命令时,我的一个项目会移动大量文件:

9052459 Reorganized project structure
 43 files changed, 1049 insertions(+), 1000 deletions(-)
Run Code Online (Sandbox Code Playgroud)

这里使用git log --oneline --shortstat -C检测文件副本和重命名的命令进行相同的提交:

9052459 Reorganized project structure
 27 files changed, 134 insertions(+), 85 deletions(-)
Run Code Online (Sandbox Code Playgroud)

在我看来,后者提供了一个更真实的视图,了解一个人对项目的影响,因为重命名文件比从头开始编写文件要小得多.

  • 当我执行"git log --oneline --shortstat"时,我没有获得你的结果.我有一个提交列表,其中包含版本数,但不包括总数.如何获得在所有git存储库中编辑的总行数? (2认同)

Nev*_*vir 11

这是一个快速的ruby脚本,可以根据给定的日志查询来确定每个用户的影响.

例如,对于rubinius:

Brian Ford: 4410668
Evan Phoenix: 1906343
Ryan Davis: 855674
Shane Becker: 242904
Alexander Kellett: 167600
Eric Hodel: 132986
Dirkjan Bussink: 113756
...
Run Code Online (Sandbox Code Playgroud)

剧本:

#!/usr/bin/env ruby

impact = Hash.new(0)

IO.popen("git log --pretty=format:\"%an\" --shortstat #{ARGV.join(' ')}") do |f|
  prev_line = ''
  while line = f.gets
    changes = /(\d+) insertions.*(\d+) deletions/.match(line)

    if changes
      impact[prev_line] += changes[1].to_i + changes[2].to_i
    end

    prev_line = line # Names are on a line of their own, just before the stats
  end
end

impact.sort_by { |a,i| -i }.each do |author, impact|
  puts "#{author.strip}: #{impact}"
end
Run Code Online (Sandbox Code Playgroud)

  • 这个脚本很棒,但不包括只有单行提交的作者!要修复,请更改如下:更改= /(\ d +)插入.*(\ d +)删除/ .match(行) (2认同)

小智 11

你可以使用whodid(https://www.npmjs.com/package/whodid)

$ npm install whodid -g
$ cd your-project-dir
Run Code Online (Sandbox Code Playgroud)

$ whodid author --include-merge=false --path=./ --valid-threshold=1000 --since=1.week
Run Code Online (Sandbox Code Playgroud)

或者只是输入

$ whodid
Run Code Online (Sandbox Code Playgroud)

然后你可以看到这样的结果

Contribution state
=====================================================
 score  | author
-----------------------------------------------------
 3059   | someguy <someguy@tensorflow.org>
 585    | somelady <somelady@tensorflow.org>
 212    | niceguy <nice@google.com>
 173    | coolguy <coolgay@google.com>
=====================================================
Run Code Online (Sandbox Code Playgroud)

  • “分数”是什么意思? (2认同)

小智 8

这是最好的方法,它还可以让您清楚地了解所有用户提交的总数

git shortlog -s -n
Run Code Online (Sandbox Code Playgroud)

  • 有用,但那是提交数而不是总代码行数 (2认同)

jas*_*ard 7

这是一个很棒的 repo,可以让您的生活更轻松

git-quick-stats

在安装了 brew 的 Mac 上

brew install git-quick-stats

git-quick-stats

只需输入列出的数字并按回车键,即可从此列表中选择您想要的选项。

 Generate:
    1) Contribution stats (by author)
    2) Contribution stats (by author) on a specific branch
    3) Git changelogs (last 10 days)
    4) Git changelogs by author
    5) My daily status
    6) Save git log output in JSON format

 List:
    7) Branch tree view (last 10)
    8) All branches (sorted by most recent commit)
    9) All contributors (sorted by name)
   10) Git commits per author
   11) Git commits per date
   12) Git commits per month
   13) Git commits per weekday
   14) Git commits per hour
   15) Git commits by author per hour

 Suggest:
   16) Code reviewers (based on git history)

Run Code Online (Sandbox Code Playgroud)


Aar*_*onM 5

我在上面提供了一个简短答案的修改,但它不足以满足我的需求.我需要能够在最终代码中对提交的行和行进行分类.我也希望按文件分解.此代码不会递归,它只会返回单个目录的结果,但如果有人想要更进一步,这是一个良好的开端.复制并粘贴到文件中并生成可执行文件或使用Perl运行它.

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $dir = shift;

die "Please provide a directory name to check\n"
    unless $dir;

chdir $dir
    or die "Failed to enter the specified directory '$dir': $!\n";

if ( ! open(GIT_LS,'-|','git ls-files') ) {
    die "Failed to process 'git ls-files': $!\n";
}
my %stats;
while (my $file = <GIT_LS>) {
    chomp $file;
    if ( ! open(GIT_LOG,'-|',"git log --numstat $file") ) {
        die "Failed to process 'git log --numstat $file': $!\n";
    }
    my $author;
    while (my $log_line = <GIT_LOG>) {
        if ( $log_line =~ m{^Author:\s*([^<]*?)\s*<([^>]*)>} ) {
            $author = lc($1);
        }
        elsif ( $log_line =~ m{^(\d+)\s+(\d+)\s+(.*)} ) {
            my $added = $1;
            my $removed = $2;
            my $file = $3;
            $stats{total}{by_author}{$author}{added}        += $added;
            $stats{total}{by_author}{$author}{removed}      += $removed;
            $stats{total}{by_author}{total}{added}          += $added;
            $stats{total}{by_author}{total}{removed}        += $removed;

            $stats{total}{by_file}{$file}{$author}{added}   += $added;
            $stats{total}{by_file}{$file}{$author}{removed} += $removed;
            $stats{total}{by_file}{$file}{total}{added}     += $added;
            $stats{total}{by_file}{$file}{total}{removed}   += $removed;
        }
    }
    close GIT_LOG;

    if ( ! open(GIT_BLAME,'-|',"git blame -w $file") ) {
        die "Failed to process 'git blame -w $file': $!\n";
    }
    while (my $log_line = <GIT_BLAME>) {
        if ( $log_line =~ m{\((.*?)\s+\d{4}} ) {
            my $author = $1;
            $stats{final}{by_author}{$author}     ++;
            $stats{final}{by_file}{$file}{$author}++;

            $stats{final}{by_author}{total}       ++;
            $stats{final}{by_file}{$file}{total}  ++;
            $stats{final}{by_file}{$file}{total}  ++;
        }
    }
    close GIT_BLAME;
}
close GIT_LS;

print "Total lines committed by author by file\n";
printf "%25s %25s %8s %8s %9s\n",'file','author','added','removed','pct add';
foreach my $file (sort keys %{$stats{total}{by_file}}) {
    printf "%25s %4.0f%%\n",$file
            ,100*$stats{total}{by_file}{$file}{total}{added}/$stats{total}{by_author}{total}{added};
    foreach my $author (sort keys %{$stats{total}{by_file}{$file}}) {
        next if $author eq 'total';
        if ( $stats{total}{by_file}{$file}{total}{added} ) {
            printf "%25s %25s %8d %8d %8.0f%%\n",'', $author,@{$stats{total}{by_file}{$file}{$author}}{qw{added removed}}
            ,100*$stats{total}{by_file}{$file}{$author}{added}/$stats{total}{by_file}{$file}{total}{added};
        } else {
            printf "%25s %25s %8d %8d\n",'', $author,@{$stats{total}{by_file}{$file}{$author}}{qw{added removed}} ;
        }
    }
}
print "\n";

print "Total lines in the final project by author by file\n";
printf "%25s %25s %8s %9s %9s\n",'file','author','final','percent', '% of all';
foreach my $file (sort keys %{$stats{final}{by_file}}) {
    printf "%25s %4.0f%%\n",$file
            ,100*$stats{final}{by_file}{$file}{total}/$stats{final}{by_author}{total};
    foreach my $author (sort keys %{$stats{final}{by_file}{$file}}) {
        next if $author eq 'total';
        printf "%25s %25s %8d %8.0f%% %8.0f%%\n",'', $author,$stats{final}{by_file}{$file}{$author}
            ,100*$stats{final}{by_file}{$file}{$author}/$stats{final}{by_file}{$file}{total}
            ,100*$stats{final}{by_file}{$file}{$author}/$stats{final}{by_author}{total}
        ;
    }
}
print "\n";


print "Total lines committed by author\n";
printf "%25s %8s %8s %9s\n",'author','added','removed','pct add';
foreach my $author (sort keys %{$stats{total}{by_author}}) {
    next if $author eq 'total';
    printf "%25s %8d %8d %8.0f%%\n",$author,@{$stats{total}{by_author}{$author}}{qw{added removed}}
        ,100*$stats{total}{by_author}{$author}{added}/$stats{total}{by_author}{total}{added};
};
print "\n";


print "Total lines in the final project by author\n";
printf "%25s %8s %9s\n",'author','final','percent';
foreach my $author (sort keys %{$stats{final}{by_author}}) {
    printf "%25s %8d %8.0f%%\n",$author,$stats{final}{by_author}{$author}
        ,100*$stats{final}{by_author}{$author}/$stats{final}{by_author}{total};
}
Run Code Online (Sandbox Code Playgroud)