Git Blameコミット統計


198

どのように私は非難(またはいくつかのより適切な関数、および/またはシェルコマンドと組み合わせて)を「悪用」して、各コミッターから発信された(コードの)行数が現在リポジトリーにあるかについての統計を提供できますか?

出力例:

Committer 1: 8046 Lines
Committer 2: 4378 Lines

11
そのための組み込みコマンドが本当にあるはずです...あまり一般的でないユースケースのためのコマンドがあります。
Ciro Santilli郝海东冠状病六四事件法轮功

@CiroSantilliですが、gitから呼び出し可能なシェルスクリプトを追加するのは簡単です。
Alex

Gitリポジトリの特定の作成者によって変更された合計行数をカウントする方法の重複の可能性はありますか?それは簡単にその1つに減らすことができるためです。すべての作成者をループするだけです
Ciro Santilli郝海东冠状病六四事件法轮功

1
これは特に素晴らしいコードです。google.com/ p / gitinspectorは、特に生徒のチームによる課題を採点している場合(大規模なプロジェクトは適用する必要はありません...個々のファイルを非難するので遅い)
sehe

回答:


166

更新

git ls-tree -r -z --name-only HEAD -- */*.c | xargs -0 -n1 git blame \
--line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

途中で更新しました。

便宜上、これを独自のコマンドに含めることもできます。

#!/bin/bash

# save as i.e.: git-authors and set the executable flag
git ls-tree -r -z --name-only HEAD -- $1 | xargs -0 -n1 git blame \
 --line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

これをパスのどこかに保存するか、パスを変更して次のように使用します

  • git authors '*/*.c' # look for all files recursively ending in .c
  • git authors '*/*.[ch]' # look for all files recursively ending in .c or .h
  • git authors 'Makefile' # just count lines of authors in the Makefile

元の回答

受け入れられた答えは仕事をしますが、それは非常に遅いです。

$ git ls-tree --name-only -z -r HEAD|egrep -z -Z -E '\.(cc|h|cpp|hpp|c|txt)$' \
  |xargs -0 -n1 git blame --line-porcelain|grep "^author "|sort|uniq -c|sort -nr

ほぼ瞬時です。

現在追跡されているファイルのリストを取得するには、

git ls-tree --name-only -r HEAD

このソリューションではfile、ファイルタイプを判別するための呼び出しを回避し、パフォーマンス上の理由から、grepを使用して必要な拡張子に一致させます。すべてのファイルを含める必要がある場合は、これを行から削除してください。

grep -E '\.(cc|h|cpp|hpp|c)$' # for C/C++ files
grep -E '\.py$'               # for Python files

ファイルにスペースが含まれている可能性がある場合、これはシェルには不適切です。

git ls-tree -z --name-only -r HEAD | egrep -Z -z '\.py'|xargs -0 ... # passes newlines as '\0'

ファイルのリストを(パイプを介して)提供します。xargsを使用してコマンドを呼び出し、引数を配布できます。複数のファイルの処理を可能にするコマンドは、を省略し-n1ます。この場合、呼び出しgit blame --line-porcelainを行い、呼び出しごとに1つの引数を使用します。

xargs -n1 git blame --line-porcelain

次に、「author」の発生について出力をフィルタリングし、リストをソートして、重複する行を次のようにカウントします。

grep "^author "|sort|uniq -c|sort -nr

注意

他の回答は、実際には空白のみを含む行を除外します。

grep -Pzo "author [^\n]*\n([^\n]*\n){10}[\w]*[^\w]"|grep "author "

上記のコマンドは、空白以外の文字を少なくとも1つ含む行の作者を出力します。また\w*[^\w#]、最初の空白以外の文字がaではない行を除外する一致を使用することもできます#(多くのスクリプト言語のコメント)。


2
@nilbus:できません。echo "a\nb\nc"|xargs -n1 cmdに拡張されますcmd a; cmd b; cmd d
Alex

2
--line-porcelainが機能しなくなった(git 1.7.5.4)代わりに--porcelainを使用してください
isoiphone

4
OSXのユーザーは、(まだ自分の名前に改行のファイルでは動作しません)次のことを試してください:git ls-tree --name-only -r HEAD | grep -E '\.(cc|h|m|hpp|c)$' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr
ウェイン

3
現在のパスの下にあるすべてのものを任意の深さにしたい場合は、パスフィルターとして「./」を使用します(回答者が「/ .c」を入力した場所)。
Ben Dilts、2014

2
コードのみが再フォーマットされたときに多分より良いコードの所有権を取得するには、「非難-w」を使用stackoverflow.com/questions/4112410/...
sleeplessnerd

124

役に立つかもしれないgit-fameと呼ばれる宝石を書きました。

インストールと使用法:

  1. $ gem install git_fame
  2. $ cd /path/to/gitdir
  3. $ git fame

出力:

Statistics based on master
Active files: 21
Active lines: 967
Total commits: 109

Note: Files matching MIME type image, binary has been ignored

+----------------+-----+---------+-------+---------------------+
| name           | loc | commits | files | distribution (%)    |
+----------------+-----+---------+-------+---------------------+
| Linus Oleander | 914 | 106     | 21    | 94.5 / 97.2 / 100.0 |
| f1yegor        | 47  | 2       | 7     |  4.9 /  1.8 / 33.3  |
| David Selassie | 6   | 1       | 2     |  0.6 /  0.9 /  9.5  |
+----------------+-----+---------+-------+---------------------+

5
+1最後に1は機能し、実用的な数値を提供するように見えますが、残りのコマンドラインは、utilsの非互換性のためにOSXで機能しないか、私のリポジトリに小さな数値を提供します。これはOSXとruby 1.9.3(brew)にあります
Karthik T

9
@tcaswell、ばかげてはいけません。あなたがたまたまその何かを書いた人であったとしても、有用なものを指すのはスパムではありません。
ウェイン

5
私自身の質問に答える:git fame --exclude = paths / to / files、paths / to / other / files
Maciej Swic '

2
@アダム:まだ問題がありますか?OS X 10.9.5では、私にとって非常にうまく機能します。
Sam Dutton、2015年

2
数回のコミットよりも大きいレポの場合、このgemが実行する必要がある時間は天文学的なものです
Erik Aigner

48
git ls-tree -r HEAD|sed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c

ステップバイステップの説明:

バージョン管理下にあるすべてのファイルを一覧表示します

git ls-tree -r HEAD|sed -re 's/^.{53}//'

リストをテキストファイルのみに切り詰める

|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'

Gitは空白の変更を無視してすべてのテキストファイルを非難します

|while read filename; do git blame -w "$filename"; done

著者名を引き出します

|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'

著者のリストをソートし、uniqに連続して繰り返される行の数をカウントさせる

|sort|uniq -c

出力例:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda

1
私は別のsedバージョンを持っているようですが、私のものは-rフラグを理解しておらず、正規表現に問題があります(余剰を削除しても、括弧のバランスが取れていないというメッセージがあり(ます)。
Erik Aigner、2011年

7
気にしないで、sudo brew install gnu-sedそれを解決しました。魅力的な作品!
Erik Aigner、2011年

5
またはport install gsedMacPortsユーザーの場合。
Gavin Brock

私はsudo brew install gnu-sed(うまくいった)しましたが、それでもsedが-rを認識しないエラーが発生します。:(
アダム・タトル

1
OSXでmacportsを介してgsedをインストールした後、このコマンドを実行して動作させました(sedをgsedに置き換えました):git ls-tree -r HEAD|gsed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|gsed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|gsed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c
nerdherd

38

git summarygit-extrasパッケージによって提供されるものがまさに必要なものです。git-extras-git-summaryでドキュメントをチェックアウトしてください:

git summary --line

次のような出力が得られます。

project  : TestProject
lines    : 13397
authors  :
8927 John Doe            66.6%
4447 Jane Smith          33.2%
  23 Not Committed Yet   0.2%

1
いいですが、パスフィルター、または少なくともサブディレクトリ引数をサポートしていないようです。より良いでしょう。
spinkus

1
素敵でクリーンなソリューション。@Alexの回答では、何らかの理由で行数が非常に少なくなりました。これは、箱から出してすぐに機能しました。数百のファイルにまたがる〜200k行に30秒のようなものを取りました。
fgblomqvist

6

Erikのソリューションは素晴らしかったですが、発音区別符号(LC_*環境変数が表面的には正しく設定されているにもかかわらず)と、実際に日付が含まれているコード行から漏れるノイズに問題がありました。私のsed-fuは貧弱なので、ルビが含まれたこのフランケンシュタインのスニペットになりましたが、200,000以上のLOCで問題なく動作し、結果をソートします。

git ls-tree -r HEAD | gsed -re 's/^.{53}//' | \
while read filename; do file "$filename"; done | \
grep -E ': .*text' | gsed -r -e 's/: .*//' | \
while read filename; do git blame "$filename"; done | \
ruby -ne 'puts $1.strip if $_ =~ /^\w{8} \((.*?)\s*\d{4}-\d{2}-\d{2}/' | \
sort | uniq -c | sort -rg

また、gsed代わりにsed、それはバイナリの自作インストールであるため、システムsedをそのままにしておくことに注意してください。


4

git shortlog -sn

これにより、作成者ごとのコミットのリストが表示されます。


17
これは、行数ではなく、作成者ごとのコミット数を返します。
v64、2011年

プロジェクト/ディレクトリ/ファイルへの主要な貢献者を特定するのに非常に役立ちます
アレス

4

@Alexの回答からの主要なスニペットは、実際に非難行を集約する操作を実行します。私は、ファイルのセットではなく、単一のファイルを操作するためにそれを切り詰めました。

git blame --line-porcelain path/to/file.txt | grep  "^author " | sort | uniq -c | sort -nr

私はこれをここに投稿します。なぜなら、私はこの回答に頻繁に戻り、投稿を再度読み、例を再消化して、課税対象とする価値がある部分を抽出するためです。また、私のユースケースでは十分に一般的でもありません。その範囲はCプロジェクト全体です。


私はファイルごとの統計を一覧表示したいのですが、xargsの可読性が低く、使用/記憶が難しいのではforなく、bash イテレータを使用して達成しました。xargs xargsの利点/欠点は、他の場所で説明する必要があります。

以下は、各ファイルの結果を個別に表示する実用的なスニペットです。

for file in $(git ls-files); do \
    echo $file; \
    git blame --line-porcelain $file \
        | grep  "^author " | sort | uniq -c | sort -nr; \
    echo; \
done

そして私がテストしたところ、bashシェルでこのstrightを実行するとctrl + c安全です。これをbashスクリプト内に配置する必要がある場合、ユーザーがforループを中断できるようにするには、SIGINTとSIGTERMトラップする必要があります。


1
git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nr私が探していた統計をより正確に表す、git blame ここへの微調整を見つけました。具体的には、-Mおよび-C -Cオプション(これらは意図的に2つのCです)。-Mはファイル内の移動を検出し、-C -Cは他のファイルからコピーされた行を検出します。こちらのドキュメントをご覧ください。完全を期すために、-wは空白を無視します。
John Lee、


1

すべてのテキストファイル(バイナリファイルを除く、バージョン管理されたファイルも含む)の非難された行を数えるこのソリューションがあります。

IFS=$'\n'
for file in $(git ls-files); do
    git blame `git symbolic-ref --short HEAD` --line-porcelain "$file" | \
        grep  "^author " | \
        grep -v "Binary file (standard input) matches" | \
        grep -v "Not Committed Yet" | \
        cut -d " " -f 2-
    done | \
        sort | \
        uniq -c | \
        sort -nr

1

これは、特定のソースモジュールを検査する場合に備えて、リポジトリのソース構造の任意のディレクトリで機能します。

find . -name '*.c' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr

0

私はPowershell のトップ回答を採用しました:

(git ls-tree -rz --name-only HEAD).Split(0x00) | where {$_ -Match '.*\.py'} |%{git blame -w --line-porcelain HEAD $_} | Select-String -Pattern '^author ' | Group-Object | Select-Object -Property Count, Name | Sort-Object -Property Count -Descending

スイッチで実行git blameするかどうかはオプションですが、-w空白の変更を無視するために追加しました。

BashソリューションはWSL2の下で実行されていましたが、私のマシンのパフォーマンスはPowershellに有利でした(同じリポジトリの場合は〜50秒から〜65秒)。


-1

@nilbusと@Alexを組み合わせた独自のスクリプトを作成

#!/bin/sh

for f in $(git ls-tree -r  --name-only HEAD --);
do
    j=$(file "$f" | grep -E ': .*text'| sed -r -e 's/: .*//');
    if [ "$f" != "$j" ]; then
        continue;
    fi
    git blame -w --line-porcelain HEAD "$f" | grep  "^author " | sed 's/author //'`enter code here`
done | sort | uniq -c | sort -nr

私にとって、あなたのenter code here問題が原因でした...これは正しく動作しますか?
Menios

-1

MacOSで実行される単一のソースファイルを対象とするBash関数。

function glac {
    # git_line_author_counts
    git blame -w "$1" |  sed -E "s/.*\((.*) +[0-9]{4}-[0-9]{2}.*/\1/g" | sort | uniq -c | sort -nr
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.