我是否可以调用一个命令来计算Git存储库中特定作者更改的行?我知道必须有方法来计算提交次数,因为Github会为其影响图执行此操作。
答案 0 :(得分:540)
这提供了一些关于作者的统计数据,根据需要进行修改。
使用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 }' -
github上有一个新的包看起来很光滑,并使用bash作为依赖项(在linux上测试)。它更适合直接使用而不是脚本。
这是git-quick-stats (github link)。
将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
用法:
git-quick-stats
答案 1 :(得分:277)
以下命令的输出应该相当容易发送到脚本以添加总计:
git log --author="<authorname>" --oneline --shortstat
这为当前HEAD上的所有提交提供了统计信息。如果您想在其他分支中添加统计信息,则必须将它们作为git log
的参数提供。
对于传递给脚本,甚至可以使用空日志格式删除“oneline”格式,并且如JakubNarębski所评论,--numstat
是另一种选择。它生成每个文件而不是每行统计信息,但更容易解析。
git log --author="<authorname>" --pretty=tformat: --numstat
答案 2 :(得分:178)
如果有人想在他们的代码库中看到每个用户的统计数据,我的几个同事最近想出了这个可怕的单行代码:
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的提交。)
答案 3 :(得分:134)
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
还有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
示例输出:
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数据。
答案 4 :(得分:102)
我发现以下内容对于查看当前代码库中包含最多行的人员非常有用:
git ls-files -z | xargs -0n1 git blame -w | ruby -n -e '$_ =~ /^.*\((.*?)\s[\d]{4}/; puts $1.strip' | sort -f | uniq -c | sort -n
其他答案主要集中在提交中更改的行,但如果提交无法生存并被覆盖,则可能只是流失。上面的咒语也会让你所有提交者按行排序,而不是一次只有一个。您可以为git blame(-C -M)添加一些选项,以获得一些更好的数字,以便将文件移动和文件之间的行移动考虑在内,但是如果你这样做,命令可能运行的时间会更长。
此外,如果您正在寻找所有提交者的所有提交中更改的行,则以下小脚本很有帮助:
答案 5 :(得分:86)
要计算给定分支上给定作者(或所有作者)的提交数,您可以使用git-shortlog;请特别注意其--numbered
和--summary
选项,例如在git repository上运行时:
$ git shortlog v1.6.4 --numbered --summary
6904 Junio C Hamano
1320 Shawn O. Pearce
1065 Linus Torvalds
692 Johannes Schindelin
443 Eric Wong
答案 6 :(得分:68)
在查看 Alex 和 Gerty3000 的答案后,我试图缩短单行:
基本上,使用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
示例:
Jared Burrows added lines: 6826, removed lines: 2825, total lines: 4001
答案 7 :(得分:25)
来自Answer的AaronM使用shell one-liner是好的,但实际上,还有另一个错误,如果空格之间存在不同数量的空格,则会破坏用户名。用户名和日期。损坏的用户名将为用户计数提供多行,您必须自己总结它们。
这个小改动为我解决了这个问题:
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
注意\ after后面的+会消耗从名称到日期的所有空格。
实际上,为了我自己的记忆而添加这个答案,就像帮助其他人一样,因为这至少是我第二次谷歌主题:)
--show-email
添加到git blame -w
以汇总电子邮件,因为有些人在不同的计算机上使用不同的Name
格式,并且有时两个同名的人在同一个git中工作。答案 8 :(得分:22)
这是一个简短的单行程序,为所有作者生成统计数据。它比上面https://stackoverflow.com/a/20414465/1102119的Dan解决方案要快得多(我的时间复杂度为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
答案 9 :(得分:21)
当某些行不是有效的UTF-8文本时,以及当某些行恰好与正则表达式匹配时(这发生在这里),这是一个问题。
这是一条没有这些问题的修改过的行。它要求git在不同的行上干净地输出数据,这样可以很容易地过滤我们想要的内容:
git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n
你可以grep其他字符串,比如author-mail,committer等。
也许首先做export LC_ALL=C
(假设bash
)来强制执行字节级处理(这也恰好可以从基于UTF-8的语言环境中大大加快grep)。
答案 10 :(得分: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
答案 11 :(得分:13)
除了Charles Bailey's answer之外,您可能还想在命令中添加-C
参数。否则文件重命名计为大量添加和删除(尽管文件有行数),即使文件内容未被修改。
为了说明,使用git log --oneline --shortstat
命令时,a commit有很多文件在我的一个项目中移动:
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(-)
在我看来,后者提供了一个更真实的视图,了解一个人对项目的影响,因为重命名文件比从头编写文件要小得多。
答案 12 :(得分:11)
这是一个快速的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
答案 13 :(得分:9)
您可以使用whodid(https://www.npmjs.com/package/whodid)
$ npm install whodid -g
$ cd your-project-dir
和
$ whodid author --include-merge=false --path=./ --valid-threshold=1000 --since=1.week
或只需键入
$ whodid
然后您可以看到这样的结果
Contribution state
=====================================================
score | author
-----------------------------------------------------
3059 | someguy <someguy@tensorflow.org>
585 | somelady <somelady@tensorflow.org>
212 | niceguy <nice@google.com>
173 | coolguy <coolgay@google.com>
=====================================================
答案 14 :(得分:8)
这是最好的方式,它还可以让您清楚地了解所有用户提交的总数
git shortlog -s -n
答案 15 :(得分:6)
git-quick-stats
brew install git-quick-stats
git-quick-stats
只需通过键入列出的数字并按Enter键,从此列表中选择所需的选项即可。
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)
答案 16 :(得分: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};
}
答案 17 :(得分:2)
对于Windows用户,您可以使用以下批处理脚本来计算指定作者的添加/删除行数
@echo off
set added=0
set removed=0
for /f "tokens=1-3 delims= " %%A in ('git log --pretty^=tformat: --numstat --author^=%1') do call :Count %%A %%B %%C
@echo added=%added%
@echo removed=%removed%
goto :eof
:Count
if NOT "%1" == "-" set /a added=%added% + %1
if NOT "%2" == "-" set /a removed=%removed% + %2
goto :eof
https://gist.github.com/zVolodymyr/62e78a744d99d414d56646a5e8a1ff4f
答案 18 :(得分:1)
这个脚本会在这里完成。把它放入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 ":"
答案 19 :(得分:1)
使用以下方法将日志保存到文件中:
git log --author="<authorname>" --oneline --shortstat > logs.txt
对于Python爱好者:
with open(r".\logs.txt", "r", encoding="utf8") as f:
files = insertions = deletions = 0
for line in f:
if ' changed' in line:
line = line.strip()
spl = line.split(', ')
if len(spl) > 0:
files += int(spl[0].split(' ')[0])
if len(spl) > 1:
insertions += int(spl[1].split(' ')[0])
if len(spl) > 2:
deletions += int(spl[2].split(' ')[0])
print(str(files).ljust(10) + ' files changed')
print(str(insertions).ljust(10) + ' insertions')
print(str(deletions).ljust(10) + ' deletions')
您的输出将如下:
225 files changed
6751 insertions
1379 deletions
答案 20 :(得分:1)
我编写了这个Perl脚本来完成该任务。
#!/usr/bin/env perl
use strict;
use warnings;
# save the args to pass to the git log command
my $ARGS = join(' ', @ARGV);
#get the repo slug
my $NAME = _get_repo_slug();
#get list of authors
my @authors = _get_authors();
my ($projectFiles, $projectInsertions, $projectDeletions) = (0,0,0);
#for each author
foreach my $author (@authors) {
my $command = qq{git log $ARGS --author="$author" --oneline --shortstat --no-merges};
my ($files, $insertions, $deletions) = (0,0,0);
my @lines = `$command`;
foreach my $line (@lines) {
if ($line =~ m/^\s(\d+)\s\w+\s\w+,\s(\d+)\s\w+\([\+|\-]\),\s(\d+)\s\w+\([\+|\-]\)$|^\s(\d+)\s\w+\s\w+,\s(\d+)\s\w+\(([\+|\-])\)$/) {
my $lineFiles = $1 ? $1 : $4;
my $lineInsertions = (defined $6 && $6 eq '+') ? $5 : (defined $2) ? $2 : 0;
my $lineDeletions = (defined $6 && $6 eq '-') ? $5 : (defined $3) ? $3 : 0;
$files += $lineFiles;
$insertions += $lineInsertions;
$deletions += $lineDeletions;
$projectFiles += $lineFiles;
$projectInsertions += $lineInsertions;
$projectDeletions += $lineDeletions;
}
}
if ($files || $insertions || $deletions) {
printf(
"%s,%s,%s,+%s,-%s,%s\n",
$NAME,
$author,
$files,
$insertions,
$deletions,
$insertions - $deletions
);
}
}
printf(
"%s,%s,%s,+%s,-%s,%s\n",
$NAME,
'PROJECT_TOTAL',
$projectFiles,
$projectInsertions,
$projectDeletions,
$projectInsertions - $projectDeletions
);
exit 0;
#get the remote.origin.url joins that last two pieces (project and repo folder)
#and removes any .git from the results.
sub _get_repo_slug {
my $get_remote_url = "git config --get remote.origin.url";
my $remote_url = `$get_remote_url`;
chomp $remote_url;
my @parts = split('/', $remote_url);
my $slug = join('-', @parts[-2..-1]);
$slug =~ s/\.git//;
return $slug;
}
sub _get_authors {
my $git_authors = 'git shortlog -s | cut -c8-';
my @authors = `$git_authors`;
chomp @authors;
return @authors;
}
我将其命名为git-line-changes-by-author
,然后放入/usr/local/bin
。因为它已保存在我的路径中,所以我可以发出命令git line-changes-by-author --before 2018-12-31 --after 2020-01-01
来获取2019年的报告。举个例子。如果我拼错了名字,git会建议正确的拼写。
您可能需要调整_get_repo_slug
子项,使其仅包含remote.origin.url
的最后一部分,因为我的存储库另存为project/repo
,而您可能没有。
答案 21 :(得分:0)
你想要Git blame。
有一个--show-stats选项可以打印一些好的统计数据。
答案 22 :(得分:0)
该问题要求提供有关特定作者的信息,但许多答案都是根据代码行更改返回作者排名列表的解决方案。
这就是我所寻求的,但现有的解决方案并不完美。为了可能通过Google找到这个问题的人的利益,我已经对它们做了一些改进,并将它们变成了一个shell脚本,我将在下面显示。带注释的(我将继续维护)可以是found on my Github。
Perl或Ruby上都有 no 依赖项。此外,行更改计数中会考虑空格,重命名和行移动。只需将其放入文件并将您的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
答案 23 :(得分:0)
到目前为止我认识的最好的工具是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