Git Blame Commit Statistics


198

Wie kann ich Schuld (oder eine besser geeignete Funktion und / oder in Verbindung mit Shell-Befehlen) "missbrauchen", um eine Statistik darüber zu erhalten, wie viele Zeilen (Code) sich derzeit im Repository befinden, die von jedem Committer stammen?

Beispielausgabe:

Committer 1: 8046 Lines
Committer 2: 4378 Lines

11
Es sollte wirklich einen eingebauten Befehl dafür geben ... es gibt Befehle für viel weniger häufige Anwendungsfälle.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

@CiroSantilli, aber es ist einfach, ein Shellscript hinzuzufügen, das von Git aus aufgerufen werden kann.
Alex

Mögliches Duplikat von Wie werden die von einem bestimmten Autor geänderten Zeilen in einem Git-Repository gezählt? weil es leicht auf dieses reduziert werden kann: einfach alle Autoren
durchlaufen

1
Dies ist ziemlich beeindruckend. code.google.com/p/gitinspector, insbesondere wenn Sie Aufgaben von Schülerteams bewerten (große Projekte müssen nicht
angewendet werden

Antworten:


165

Aktualisieren

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

Ich habe unterwegs einige Dinge aktualisiert.

Der Einfachheit halber können Sie dies auch in einen eigenen Befehl einfügen:

#!/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

Speichern Sie dies irgendwo in Ihrem Pfad oder ändern Sie Ihren Pfad und verwenden Sie ihn wie folgt

  • 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

Ursprüngliche Antwort

Während die akzeptierte Antwort die Arbeit erledigt, ist sie sehr langsam.

$ 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

ist fast augenblicklich.

Um eine Liste der aktuell verfolgten Dateien zu erhalten, können Sie verwenden

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

Diese Lösung vermeidet das Aufrufen filezur Ermittlung des Dateityps und verwendet aus Leistungsgründen grep, um die gewünschte Erweiterung zu finden. Wenn alle Dateien enthalten sein sollen, entfernen Sie diese einfach aus der Zeile.

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

Wenn die Dateien Leerzeichen enthalten können, die für Shells schlecht sind, können Sie Folgendes verwenden:

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

Geben Sie eine Liste von Dateien (über eine Pipe) an. Mit xargs können Sie einen Befehl aufrufen und die Argumente verteilen. Befehle, mit denen mehrere Dateien verarbeitet werden können, lassen die -n1. In diesem Fall rufen wir auf git blame --line-porcelainund verwenden für jeden Aufruf genau 1 Argument.

xargs -n1 git blame --line-porcelain

Wir filtern dann die Ausgabe nach Vorkommen von "Autor", sortieren die Liste und zählen doppelte Zeilen nach:

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

Hinweis

Andere Antworten filtern tatsächlich Zeilen heraus, die nur Leerzeichen enthalten.

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

Mit dem obigen Befehl werden Autoren von Zeilen gedruckt, die mindestens ein Nicht-Leerzeichen enthalten. Sie können auch eine Übereinstimmung verwenden, \w*[^\w#]die auch Zeilen ausschließt, in denen das erste Nicht-Leerzeichen kein Zeichen ist #(Kommentar in vielen Skriptsprachen).


2
@nilbus: das kannst du nicht. echo "a\nb\nc"|xargs -n1 cmdwird erweitert aufcmd a; cmd b; cmd d
Alex

2
--line-Porzellan scheint nicht mehr zu funktionieren (git 1.7.5.4) stattdessen --porcelain
isoiphone

4
OSX-Benutzer versuchen Folgendes (funktioniert immer noch nicht bei Dateien mit Zeilenumbrüchen im Namen):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
Wayne

3
Wenn Sie nur alles unter dem aktuellen Pfad bis zu einer beliebigen Tiefe haben möchten, verwenden Sie "./" als Pfadfilter (wobei der Antwortende " / .c" eingibt ).
Ben Dilts

2
Vielleicht besser Code Eigentum zu bekommen verwenden „Schuld -w“ zu , wenn der Code nur umformatiert wurde stackoverflow.com/questions/4112410/...
sleeplessnerd

124

Ich habe ein Juwel namens Git-Fame geschrieben , das nützlich sein könnte.

Installation und Verwendung:

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

Ausgabe:

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 endlich 1, das funktioniert und so aussieht, als ob es vernünftige Zahlen gibt, die restlichen Kommandozeilen funktionieren entweder nicht unter OSX, weil die Utils nicht kompatibel sind, oder geben auf meinem Repo Teeny-Zahlen an. Dies ist auf OSX und Ruby 1.9.3 (Gebräu)
Karthik T

9
Sei nicht albern, @tcaswell. Es ist kein Spam, auf etwas Nützliches hinzuweisen, selbst wenn Sie derjenige waren, der dieses Etwas geschrieben hat.
Wayne

5
Beantwortung meiner eigenen Frage: git Ruhm --exclude = Pfade / zu / Dateien, Pfade / zu / anderen / Dateien
Maciej Swic

2
@Adam: Hast du immer noch Probleme damit? Funktioniert sehr gut für mich unter OS X 10.9.5.
Sam Dutton

2
Für jedes Repo, das größer als ein paar Commits ist, ist die Zeit, die dieses Juwel benötigt, um seine Arbeit zu erledigen, astronomisch
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

Schritt für Schritt Erklärung:

Listen Sie alle Dateien unter Versionskontrolle auf

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

Beschneiden Sie die Liste nur auf Textdateien

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

Git beschuldigt alle Textdateien und ignoriert Änderungen an Leerzeichen

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

Ziehen Sie die Autorennamen heraus

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

Sortieren Sie die Liste der Autoren und lassen Sie die Anzahl der sich nacheinander wiederholenden Zeilen uniq zählen

|sort|uniq -c

Beispielausgabe:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda

1
Scheint, dass ich eine andere sedVersion habe, meine versteht die -rFlagge nicht und hat Probleme mit der Regex (beschwert sich über unausgeglichene Parens, selbst wenn ich den Überschuss entferne ().
Erik Aigner

7
Vergiss es, sudo brew install gnu-sedlöste es. Klappt wunderbar!
Erik Aigner

5
Oder port install gsedfür MacPorts-Benutzer.
Gavin Brock

Ich habe ein sudo brew install gnu-sed(was funktioniert hat) gemacht, aber ich bekomme immer noch Fehler, die sed nicht erkennt -r. :(
Adam Tuttle

1
Unter OSX habe ich nach der Installation von gsed über Macports diesen Befehl ausgeführt, damit es funktioniert (ersetzt durch 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 summaryDas Git-Extras- Paket bietet genau das, was Sie brauchen. Überprüfen Sie die Dokumentation unter git-extras - git-summary :

git summary --line

Gibt eine Ausgabe aus, die folgendermaßen aussieht:

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

1
Schön, scheint aber keinen Pfadfilter oder zumindest ein Unterverzeichnisargument zu unterstützen. Wäre schöner.
Spinkus

1
Schöne und saubere Lösung. @ Alex 'Antwort ergab aus irgendeinem Grund sehr kleine Zeilenzahlen. Dies hat einfach sofort funktioniert. Es dauerte ungefähr 30 Sekunden für ~ 200.000 Zeilen, die auf einige hundert Dateien verteilt waren.
fgblomqvist

6

Eriks Lösung war fantastisch, aber ich hatte einige Probleme mit Diakritika (obwohl meine LC_*Umgebungsvariablen scheinbar richtig eingestellt waren) und Rauschen, das in Codezeilen mit Datumsangaben durchgesickert ist. Mein Sed-Fu ist schlecht, also habe ich dieses Frankenstein-Snippet mit Rubin erhalten, aber es funktioniert für mich auf über 200.000 LOC einwandfrei und sortiert die Ergebnisse:

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

Beachten Sie auch , gsedstatt , seddenn das ist die binäre Homebrew installiert, so dass das System sed intakt.


4

git shortlog -sn

Dies zeigt eine Liste der Commits pro Autor.


17
Dies gibt die Anzahl der Commits pro Autor zurück, nicht die Anzahl der Zeilen.
64

Sehr hilfreich bei der Ermittlung der Hauptverantwortlichen für ein Projekt / Verzeichnis / eine Datei
Ares

4

Hier ist der primäre Ausschnitt aus der Antwort von @Alex, der tatsächlich die Aggregation der Schuldlinien ausführt. Ich habe es gekürzt, um mit einer einzelnen Datei anstatt mit einer Reihe von Dateien zu arbeiten.

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

Ich poste dies hier, weil ich oft auf diese Antwort zurückkomme und den Beitrag erneut lese und die Beispiele neu verdaue, um den Teil zu extrahieren, den ich für anstrengend halte. Es ist auch nicht generisch genug für meinen Anwendungsfall. Der Geltungsbereich gilt für ein ganzes C-Projekt.


Ich mag es, Statistiken pro Datei aufzulisten, die mit einem Bash- forIterator erreicht wurden, anstatt Xargs xargsweniger lesbar und schwer zu verwenden / auswendig zu lernen. Die Vor- und Nachteile von Xargs gegenüber for sollten an anderer Stelle besprochen werden.

Hier ist ein praktischer Ausschnitt, der die Ergebnisse für jede Datei einzeln anzeigt:

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

Und ich habe getestet, dass das Ausführen dieses Strights in einer Bash-Shell Strg + C-sicher ist. Wenn Sie dies in ein Bash-Skript einfügen müssen, müssen Sie möglicherweise SIGINT und SIGTERM einfangen, wenn der Benutzer Ihre for-Schleife unterbrechen soll.


1
git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nrIch habe git blame hier eine leichte Änderung gefunden, die die gesuchten Statistiken genauer wiedergibt. Insbesondere die Optionen -M und -C-C (dies sind absichtlich zwei Cs). -M erkennt Verschiebungen innerhalb einer Datei und -C -C erkennt kopierte Zeilen aus anderen Dateien. Siehe Dokument hier . Der Vollständigkeit halber ignoriert -w Leerzeichen.
John Lee


1

Ich habe diese Lösung, die die beschuldigten Zeilen in allen Textdateien zählt (mit Ausnahme der Binärdateien, auch der versionierten):

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

Dies funktioniert in jedem Verzeichnis der Quellstruktur des Repos, falls Sie ein bestimmtes Quellmodul überprüfen möchten.

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

0

Ich habe die Top-Antwort auf Powershell übernommen:

(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

Es ist optional, ob Sie git blamemit dem -wSwitch arbeiten. Ich habe ihn hinzugefügt, da er Leerzeichenänderungen ignoriert.

Die Leistung auf meinem Computer war zugunsten von Powershell (~ 50s gegenüber ~ 65s für dasselbe Repo), obwohl die Bash-Lösung unter WSL2 lief


-1

Ich habe mein eigenes Skript erstellt, das eine Kombination aus @nilbus und @Alex ist

#!/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

Für mich hat Ihr Ding enter code hereProbleme verursacht ... funktioniert das richtig?
Menios

-1

Bash-Funktion, die auf eine einzelne Quelldatei abzielt, die unter MacOS ausgeführt wird.

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
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.