我是否可以调用一个命令来计算Git存储库中特定作者更改的行数?我知道一定有方法来计算提交的数量,因为Github为他们的影响图这样做。
当前回答
@mmrobins @AaronM @ErikZ @JamesMishra提供的变体都有一个共同的问题:他们要求git生成不用于脚本使用的信息的混合物,包括来自存储库的行内容在同一行,然后用regexp匹配混乱。
当某些行不是有效的UTF-8文本时,以及当某些行恰好与regexp匹配时(这里发生了这种情况),就会出现问题。
这是一条修改过的线,没有这些问题。它要求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等。
也许首先要导出LC_ALL=C(假设是bash)以强制进行字节级处理(这碰巧也大大加快了来自基于utf -8的区域设置的grep的速度)。
其他回答
我对上面的一个简短的回答作了修改,但这不足以满足我的需要。我需要能够对提交的行和最终代码中的行进行分类。我还想按文件进行细分。这段代码不递归,它只返回单个目录的结果,但如果有人想进一步了解,这是一个很好的开始。复制并粘贴到文件中并使其可执行或使用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
一个解决方案是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
在看了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
你想责怪Git。
有一个——show-stats选项来打印一些统计数据。
推荐文章
- 如何从终端/命令行调用VS代码编辑器
- 为什么我需要显式地推一个新分支?
- 如何撤消最后的git添加?
- Rubymine:如何让Git忽略Rubymine创建的.idea文件
- 在Jar文件中运行类
- Gitignore二进制文件,没有扩展名
- Git隐藏错误:Git隐藏弹出并最终与合并冲突
- 如何在Windows命令提示符下运行.sh ?
- 了解Git和GitHub的基础知识
- 没有。Git目录的Git克隆
- 如何从命令行通过mysql运行一个查询?
- Git与Mercurial仓库的互操作性
- 忽略git中修改(但未提交)的文件?
- “git restore”命令是什么?“git restore”和“git reset”之间有什么区别?
- Git合并与强制覆盖