我是否可以调用一个命令来计算Git存储库中特定作者更改的行数?我知道一定有方法来计算提交的数量,因为Github为他们的影响图这样做。
当前回答
我编写了这个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。因为它保存在我的路径中,所以我可以在2020-01-01之后发出命令git line-changes-by-author—before 2018-12-31—以获得2019年的报告。举个例子。如果我拼错了名字,git会建议正确的拼写。
你可能想要调整_get_repo_slug子只包括remote.origin.url的最后一部分,因为我的回购保存为项目/回购,而你的可能不是。
其他回答
@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的速度)。
要统计给定作者(或所有作者)在给定分支上提交的数量,可以使用git-shortlog;特别是它的——编号和——摘要选项,例如在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
我编写了这个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。因为它保存在我的路径中,所以我可以在2020-01-01之后发出命令git line-changes-by-author—before 2018-12-31—以获得2019年的报告。举个例子。如果我拼错了名字,git会建议正确的拼写。
你可能想要调整_get_repo_slug子只包括remote.origin.url的最后一部分,因为我的回购保存为项目/回购,而你的可能不是。
该问题要求提供关于特定作者的信息,但许多答案都是根据修改的代码行返回作者排名列表的解决方案。
这正是我想要的,但现有的解决方案并不完美。为了方便人们通过谷歌找到这个问题,我对它们进行了一些改进,并将其制成一个shell脚本,下面显示该脚本。
它不依赖于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
下面是一个简短的一行代码,用于生成所有作者的统计信息。它比Dan在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
推荐文章
- 如何从终端/命令行调用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合并与强制覆盖