Gitリポジトリの特定の作者によって変更された行をカウントするために呼び出すことができるコマンドはありますか? Githubが彼らの影響グラフのためにこれをするようにコミットの数を数える方法がなければならないことを私は知っています。
次のコマンドの出力は、合計を合計するためにスクリプトに送るのがかなり簡単なはずです。
git log --author="<authorname>" --oneline --shortstat
これは現在のHEAD上のすべてのコミットの統計を与えます。他のブランチで統計を合計したい場合は、それらをgit log
への引数として提供する必要があります。
スクリプトに渡すために、 "oneline"フォーマットでさえ削除することは空のログフォーマットで行うことができます、そしてJakubNarębskiによってコメントされているように、--numstat
は別の選択肢です。行ごとの統計ではなくファイルごとの統計を生成しますが、解析がさらに簡単です。
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 }' -
Githubには滑らかに見え、依存関係としてbashを使用する新しいパッケージがあります(Linuxでテスト済み)。スクリプトよりも直接使用に適しています。
それは git-quick-stats(githubリンク)です 。
git-quick-stats
をフォルダにコピーし、そのフォルダをpathに追加します。
mkdir ~/source
cd ~/source
git clone [email protected]: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
誰かが自分のコードベースですべてのユーザーの統計情報を見たい場合は、私の同僚2人が最近この恐ろしいワンライナーを思い付きました。
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名声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データを大量に処理する必要があることを考えると、それが改善されるかどうかはわかりません。
現在コードベースに含まれている行の数が最も多い人を確認するには、次のような方法が便利です。
git ls-files -z | xargs -0n1 git blame -w | Ruby -n -e '$_ =~ /^.*\((.*?)\s[\d]{4}/; puts $1.strip' | sort -f | uniq -c | sort -n
他の答えは主にコミットで変更された行に焦点を当てていますが、コミットが生き残らず上書きされた場合、それらは単に解約されたのかもしれません。上記の呪文は、一度に1つだけではなく、すべてのコミッターを行でソートすることもできます。 git blame(-C -M)にいくつかのオプションを追加して、ファイルの移動やファイル間の行の移動を考慮に入れたより良い数値を得ることができますが、コマンドを実行すると実行時間が長くなります。
また、すべてのコミッターのすべてのコミットで変更された行を探している場合は、次の小さなスクリプトが役立ちます。
与えられたブランチ上の与えられた作者(または全ての作者)によるコミットの数を数えるには 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
AlexのとGerty3000の答えを見て、私はワンライナーを短くする:
基本的に、git log numstatとnotを使って、ファイルの数を追跡します かわった。
Mac OS X上の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 からの 答え は良いのですが、実際には、さらにもう1つのバグがあります。ユーザー名と日付の間にスペースの量が異なると、スペースによってユーザー名が破損することがあります。破損したユーザー名はユーザーカウントのために複数の行を与えるでしょう、そしてあなたはそれらをあなた自身で合計しなければなりません。
この小さな変更で私の問題は解決しました。
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
名前の後から日付までのすべての空白を消費する\ sの後の+に注意してください。
実はこの答えを他の誰かを助けることと同じくらい私自身の記憶のために追加しています。
--show-email
にgit blame -w
を追加しました。これは、異なるコンピュータで異なるName
name__の形式を使用する人がいます。同じGit。これは、すべての作者のための統計を生成する短いワンライナーです。 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
@mmrobins @AaronM @ErikZ @JamesMishraは、共通の問題を抱えている亜種を提供しました。それらは、同じ行のリポジトリからの行の内容を含む、スクリプトの使用を意図していない情報の混合を生成してから、混乱を正規表現で照合する。
これは、いくつかの行が有効なUTF-8テキストではないとき、そしていくつかの行が正規表現に一致するときにも問題になります(これはここで起こりました)。
これはこれらの問題を抱えていない修正された行です。データを別々の行にきれいに出力するようにgitに要求します。これにより、欲しいものを確実にフィルタリングすることが容易になります。
git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n
作者のメール、コミッターなど、他の文字列をgrepすることができます。
おそらく最初にexport LC_ALL=C
(bash
と仮定)を実行してバイトレベルの処理を強制します(これはUTF-8ベースのロケールからのgrepを非常に速くするためにも起こります)。
解決策は途中で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
Charles Baileyの答え に加えて、コマンドに-C
パラメータを追加することをお勧めします。それ以外の場合、ファイルの内容が変更されていなくても、ファイルの名前変更は追加と削除(ファイルに行が含まれているのと同じくらいの数)としてカウントされます。
git log --oneline --shortstat
コマンドを使用したときに、私のプロジェクトの1つからたくさんのファイルが移動される コミット です。
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
あなたは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 <[email protected]>
585 | somelady <[email protected]>
212 | niceguy <[email protected]>
173 | coolguy <[email protected]>
=====================================================
これは最善の方法であり、それはまたあなたにすべてのユーザーによるコミットの総数の明確な絵を与えます
git shortlog -s -n
私は上記の短い答えの修正を提供しました、しかしそれは私のニーズには十分ではありませんでした。コミットされた行と最終的なコードの行の両方を分類できるようにする必要がありました。私はまたファイルによる内訳を望んでいました。このコードは再帰的なものではありません、それは単一のディレクトリの結果を返すだけですが、誰かがさらに行きたがっているならそれは良いスタートです。ファイルにコピーして貼り付けて実行可能にするか、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 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
このスクリプトはここでそれを行います。それを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 ":"
質問は特定の作者に関する情報を求めましたが、答えの多くは変更されたコードの行に基づいて作者のランク付けされたリストを返す解決策でした。
これが私が探していたものでしたが、既存の解決策は全く完璧ではありませんでした。グーグルを通してこの質問を見つけるかもしれない人々の利益のために、私は彼らにいくつかの改良を加えて、そして私が以下に表示するシェルスクリプトにそれらを作りました。注釈付きのもの(私はこれからも維持します)は私の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
これまで私が確認した中で最高のツールは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
あなたは欲しい Git blame 。
いくつかの、よく、統計を印刷するための--show-statsオプションがあります。