如何统计Git仓库中特定作者更改的总行数?

有一个命令,我可以调用这将计算由Git存储库中的特定作者更改的行? 我知道必须有方法来计算Github为其影响图所做的提交次数。

以下命令的输出应该相当容易发送给脚本来合计总和:

 git log --author="<authorname>" --oneline --shortstat 

这给出了当前HEAD上所有提交的统计信息。 如果你想在其他分支添加统计信息,你将不得不把它们作为参数提供给git log

为了传递给脚本,甚至可以用空的日志格式来删除“oneline”格式,并且如JakubNarębski所评论的那样,– --numstat是另一种select。 它生成每个文件而不是每行统计信息,但更容易parsing。

 git log --author="<authorname>" --pretty=tformat: --numstat 

这给出了一些关于作者的统计信息,根据需要进行修改

使用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 }' - 

在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 }' - 

编辑(2017)

在github上有一个新的包,看起来很漂亮,并使用bash作为依赖项(在linux上testing)。 它更适合直接使用而不是脚本。

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

git-quick-stats复制到一个文件夹并将该文件夹添加到path。

 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 

用法:

 git-quick-stats 

在这里输入图像说明

如果有人想要查看代码库中每个用户的统计信息,最近有几个同事提出了这个可怕的单线程:

 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";}' 

(需要花费几分钟的时间来完成我们的回购,这个回购大约有10-15k次提交。)

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

是一个很好的工具来获得所有作者一次计数,包括提交和修改的文件计数:

 sudo apt-get install ruby-dev sudo gem install git_fame cd /path/to/gitdir && git fame 

https://github.com/casperdcl/git-fame上也有Python版本(由@fracz提到):;

 sudo apt-get install python-pip python-dev build-essential pip install git-fame cd /path/to/gitdir && git fame 

示例输出:

 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 | +------------------------+--------+---------+-------+--------------------+ 

但要注意的是,正如Jared在评论中所提到的,在一个非常大的存储库上执行这个操作需要几个小时。 不知道是否可以改善,考虑到它必须处理这么多的Git数据。

我发现以下内容对于查看目前代码库中行数最多的用户非常有用:

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

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

另外,如果您正在寻找所有提交者的所有提交中更改的行,那么遵循下面的小脚本是有帮助的:

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

要计算给定作者(或所有作者)在给定分支上的提交数量,可以使用git-shortlog ; 尤其是看它的编号和--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 

看过AlexGerty3000的回答后,我试图缩短一行:

基本上,使用git日志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 

例:

 Jared Burrows added lines: 6826, removed lines: 2825, total lines: 4001 

AaronM使用shell的答案很好,但实际上,还有另外一个bug,如果用户名和date之间有不同数量的空格,空格会破坏用户名。 损坏的用户名会给用户数量多行,你必须自己总结。

这个小小的变化为我解决了这个问题:

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

注意\之后的+,它将消耗从名称到date的所有空格。

其实join这个答案尽可能为我自己的记忆,至于帮助其他人,因为这是至less第二次我谷歌主题:)

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

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

这是一个修改后的行,没有这些问题。 它要求git在单独的行上干净地输出数据,这可以很容易地过滤我们想要的东西:

 git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n 

您可以grep其他string,如作者邮件,提交者等

也许首先export LC_ALL=C (假设为bash )来强制字节级处理(这也正好加速了基于UTF-8的语言环境的grep)。

一个解决scheme是在中间给ruby,默认情况下是一个更多一点的可用这里是一个替代使用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 

除了Charles Bailey的回答之外 ,您可能需要将-C参数添加到命令中。 否则,即使文件内容未被修改,文件重命名也会被视为大量的添加和删除(与文件中的行数相同)。

为了说明,在使用git log --oneline --shortstat命令时,下面是一个提交了大量文件的提交 :

 9052459 Reorganized project structure 43 files changed, 1049 insertions(+), 1000 deletions(-) 

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

 9052459 Reorganized project structure 27 files changed, 134 insertions(+), 85 deletions(-) 

在我看来,后者给出了一个更现实的观点,即一个人对项目有多大的影响,因为重命名文件比从头开始编写文件要小得多。

这是一个快速的ruby脚本,它可以对每个用户对给定的日志查询产生影响。

例如,对于rubinius :

 Brian Ford: 4410668 Evan Phoenix: 1906343 Ryan Davis: 855674 Shane Becker: 242904 Alexander Kellett: 167600 Eric Hodel: 132986 Dirkjan Bussink: 113756 ... 

剧本:

 #!/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 

这是一个简短的一行,为所有作者生成统计信息。 这比Dan的解决scheme要快得多,在https://stackoverflow.com/a/20414465/1102119 (我的时间复杂度是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 

我提供了一个简短的回答上面的修改,但它不足以满足我的需要。 我需要能够在最终的代码中对承诺的行和行进行分类。 我也想通过文件分解。 这个代码不会recursion,它只会返回单个目录的结果,但如果有人想进一步的话,这是一个好的开始。 复制并粘贴到一个文件,并使可执行文件或与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}; } 

这是最好的方式,它也让你清楚地了解所有用户提交的总数

 git shortlog -s -n 

这个脚本将做到这一点。 把它放到authorship.sh,chmod + x它,你就全部设置好了。

 #!/bin/sh declare -A map while read line; do if grep "^[a-zA-Z]" <<< "$line" > /dev/null; then current="$line" if [ -z "${map[$current]}" ]; then map[$current]=0 fi elif grep "^[0-9]" <<<"$line" >/dev/null; then for i in $(cut -f 1,2 <<< "$line"); do map[$current]=$((map[$current] + $i)) done fi done <<< "$(git log --numstat --pretty="%aN")" for i in "${!map[@]}"; do echo -e "$i:${map[$i]}" done | sort -nr -t ":" -k 2 | column -t -s ":" 

你想要Git责备 。

有一个–show-stats选项来打印一些,以及统计。

这个问题被要求提供一个特定作者的信息,但是许多答案都是根据他们的代码行改变而返回排列的作者列表的解决scheme。

这正是我所期待的,但现有的解决scheme并不完美。 为了让那些可能通过Googlefind这个问题的人感兴趣,我对它们进行了一些改进,并将它们变成了一个shell脚本,我将在下面展示它。 可以在我的Github上find一个注释(我将继续保留)。

Perl或Ruby 没有依赖关系。 此外,在换行计数中考虑了空格,重命名和行移动。 把这个放到一个文件中,并把你的Git仓库作为第一个参数。

 #!/bin/bash git --git-dir="$1/.git" log > /dev/null 2> /dev/null if [ $? -eq 128 ] then echo "Not a git repository!" exit 128 else echo -e "Lines | Name\nChanged|" git --work-tree="$1" --git-dir="$1/.git" ls-files -z |\ xargs -0n1 git --work-tree="$1" --git-dir="$1/.git" blame -C -M -w |\ cut -d'(' -f2 |\ cut -d2 -f1 |\ sed -e "s/ \{1,\}$//" |\ sort |\ uniq -c |\ sort -nr fi 

到目前为止我所认定的最好的工具是gitinspector。 它给每个用户设置报告,每周等你可以像下面安装npm

npm install -g gitinspector

获取更多细节的链接

https://www.npmjs.com/package/gitinspector

https://github.com/ejwa/gitinspector/wiki/Documentation

https://github.com/ejwa/gitinspector

示例命令是

 gitinspector -lmrTw gitinspector --since=1-1-2017 etc 
Interesting Posts