Wie zähle ich die Gesamtzahl der Zeilen, die von einem bestimmten Autor in einem Git-Repository geändert wurden?


458

Gibt es einen Befehl, den ich aufrufen kann, der die von einem bestimmten Autor in einem Git-Repository geänderten Zeilen zählt? Ich weiß, dass es Möglichkeiten geben muss, die Anzahl der Commits zu zählen, da Github dies für das Impact-Diagramm tut.


1
Sie könnten ein berühmtes Tool in Betracht ziehen, das Statistiken für die Linux-Kernel-Entwicklung sammelt. Beispielsweise ist das Repository hier git://git.lwn.net/gitdm.git.
0andriy

Antworten:


310

Die Ausgabe des folgenden Befehls sollte relativ einfach an das Skript zu senden sein, um die Summen zu addieren:

git log --author="<authorname>" --oneline --shortstat

Dies gibt Statistiken für alle Commits auf dem aktuellen HEAD. Wenn Sie Statistiken in anderen Zweigen addieren möchten, müssen Sie diese als Argumente angeben git log.

Für die Übergabe an ein Skript kann sogar das "Online" -Format mit einem leeren Protokollformat entfernt werden. Wie von Jakub Narębski kommentiert, --numstatist dies eine weitere Alternative. Es generiert Statistiken pro Datei und nicht pro Zeile, ist jedoch noch einfacher zu analysieren.

git log --author="<authorname>" --pretty=tformat: --numstat

2
Meine akzeptierte Antwort wurde geändert, da dies die Ausgabe so liefert, wie ich es erwartet hatte, und für andere Besucher, die dies erreichen möchten, hilfreicher ist.
Gav

14
Sie können --numstatstattdessen verwenden, --shortstatwenn Sie Statistiken etwas einfacher addieren möchten.
Jakub Narębski

8
Vielleicht möchten Sie dort auch "--no-merges" hinzufügen.
Jojo

9
Entschuldigung für diese Fragen, aber was sagen mir die Zahlen? Es gibt zwei Reihen und ich habe keine Ahnung, was sie mir sagen. Linien chenged und hinzugefügt?
Informatic0re

2
@ Informatic0re git help logsagt mir, dass die ersten Zeilen hinzugefügt, die zweiten Zeilen gelöscht werden.
ThomasH

599

Dies gibt einige Statistiken über den Autor, ändern Sie nach Bedarf.

Verwenden von 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 }' -

Verwenden von Awk unter Mac OS X:

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 }' -

EDIT (2017)

Es gibt ein neues Paket auf Github, das schick aussieht und Bash als Abhängigkeiten verwendet (unter Linux getestet). Es ist eher für den direkten Gebrauch als für Skripte geeignet.

Es ist Git-Quick-Statistik (Github-Link) .

In git-quick-statseinen Ordner kopieren und den Ordner zum Pfad hinzufügen.

mkdir ~/source
cd ~/source
git clone git@github.com: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

Verwendungszweck:

git-quick-stats

Geben Sie hier die Bildbeschreibung ein


18
Danke für diesen schönen Longliner! Dieser Punkt von awk wischte das Deck aller ab (genau, schnell, keine besonders seltsame Ausgabe). Kein Wunder, wenn man bedenkt, dass awk so etwas entwickelt hat ... Schade, dass du so spät zur Party gekommen bist.
zxq9

4
@ zxq9: Ich war noch nicht einmal bei Stackoverflow, als die Frage gestellt wurde, und ich war von den Antworten hier inspiriert. Hoffen wir, dass ich alle hier langsam überholen werde, da die Leute dies weiterhin brauchen.
Alex

9
Das funktioniert fantastisch, aber ich musste es ändern gawk, awkdamit es im OSX-Terminal
funktioniert

1
@samthebest, da das Verschieben von Dateien keine ordnungsgemäße Statistik widerspiegelt. Die Zeilen werden nicht geändert. Zu Alex: Ich spreche von Git. Übrigens, siehe meinen Kommentar zur ursprünglichen Frage.
0andriy

2
Wenn die URL für Sie nicht funktioniert, versuchen Sie Folgendes:git clone https://github.com/arzzen/git-quick-stats.git
Nicolas

226

Für den Fall, dass jemand die Statistiken für jeden Benutzer in seiner Codebasis sehen möchte, haben sich kürzlich einige meiner Mitarbeiter diesen schrecklichen Einzeiler ausgedacht:

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";}'

(Es dauert ein paar Minuten, bis wir unser Repo mit ca. 10-15.000 Commits durchgearbeitet haben.)


12
Das ist großartig! michael,: 6057 files changed, 854902 insertions(+), 26973 deletions(-), 827929 net
Michael J. Calkins

1
@EugenKonkov im Code ist es als Einfügungen - Löschungen definiert.
Dan

13
Dies ist der einzige Befehl, der das Gesamtergebnis für ein Repository liefert und ohne Plugin ausgeführt wird.
Ömer Faruk Almalı

1
Ich bekomme eine Reihe von Benutzern zusammen aufgelistet, fast jede mögliche Kombination von Entwicklern kommt zurück. Verrücktheit an meinem Ende?
Damon

2
@ BenSewards Sie könnten Bash unter Windows mit dem Windows-Subsystem für Linux verwenden, weitere Informationen hier
mjsr

152

Git Ruhm https://github.com/oleander/git-fame-rb

ist ein nützliches Tool, um die Anzahl aller Autoren gleichzeitig zu ermitteln, einschließlich der Anzahl der festgeschriebenen und geänderten Dateien:

sudo apt-get install ruby-dev
sudo gem install git_fame
cd /path/to/gitdir && git fame

Es gibt auch eine Python-Version unter https://github.com/casperdcl/git-fame (erwähnt von @fracz):

sudo apt-get install python-pip python-dev build-essential 
pip install --user git-fame
cd /path/to/gitdir && git fame

Beispielausgabe:

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    |
+------------------------+--------+---------+-------+--------------------+

Aber seien Sie gewarnt: Wie von Jared im Kommentar erwähnt, dauert es Stunden, dies in einem sehr großen Repository zu tun. Ich bin mir nicht sicher, ob das verbessert werden könnte, wenn man bedenkt, dass so viele Git-Daten verarbeitet werden müssen.


1
Das ist großartig, aber so langsam
Jared Burrows

1
Funktionierte gut bei MacBook und mittelgroßem Android-Projekt Mitte 2015 (127.000 LoC '). Ein paar Minuten.
Maxweber

2
@Vincent Prozent von toal loc / commits / files für den aktuellen Benutzer.
Ciro Santilli 法轮功 冠状 病 六四 事件 8

1
Ändern Sie Zweig, Timeout und schließen Sie einen Ordner aus:git fame --branch=dev --timeout=-1 --exclude=Pods/*
Jonmecer

1
@ AlexanderMills Ich vermute, es liegt daran, dass Sie Linien auf Blobs nicht sinnvoll zählen können
Ciro Santilli 法轮功 冠状 病 六四 事件 16

103

Ich fand Folgendes nützlich, um zu sehen, wer die meisten Zeilen in der Codebasis hatte:

git ls-files -z | xargs -0n1 git blame -w | ruby -n -e '$_ =~ /^.*\((.*?)\s[\d]{4}/; puts $1.strip' | sort -f | uniq -c | sort -n

Die anderen Antworten haben sich hauptsächlich auf Zeilen konzentriert, die in Commits geändert wurden. Wenn Commits jedoch nicht überleben und überschrieben werden, wurden sie möglicherweise nur abgewickelt. Mit der obigen Beschwörung erhalten Sie auch alle Committer nach Zeilen sortiert und nicht nur nacheinander. Sie können git tad (-C -M) einige Optionen hinzufügen, um bessere Zahlen zu erhalten, die die Dateibewegung und die Zeilenverschiebung zwischen Dateien berücksichtigen. In diesem Fall wird der Befehl jedoch möglicherweise viel länger ausgeführt.

Wenn Sie nach Zeilen suchen, die in allen Commits für alle Committer geändert wurden, ist das folgende kleine Skript hilfreich:

http://git-wt-commit.rubyforge.org/#git-rank-contributors


31
Ich wollte gerade eine +1 geben, aber dann wurde mir klar, dass die Lösung von Rubin abhängt ... :(
mac

3
Sie können es so ändern, dass es nicht ganz einfach Ruby verwendet, da ich nur Ruby für die String-Ersetzung verwende. Sie könnten Perl, Sed, Python usw. verwenden
mmrobins

21
funktioniert bei mir nicht: -e: 1: in `<main> ': ungültige Bytesequenz in UTF-8 (ArgumentError)
Michał Dębski

1
/^.*\((.*?)\s[\d]{4}/sollte sein /^.*?\((.*?)\s[\d]{4}/, um zu verhindern, dass Klammern in der Quelle als Autor übereinstimmen.
Timothy Gu

1
mmm meine Ausführungen zeigten viele Benutzer, die aufgrund einer schlechten Analyse nicht einmal existieren. Ich denke, es ist keine verlässliche Antwort.
mjsr

92

Um die Anzahl der Commits eines bestimmten Autors (oder aller Autoren) in einem bestimmten Zweig zu zählen, können Sie git-shortlog verwenden . Siehe insbesondere seine --numberedund --summaryOptionen, z. B. wenn sie im Git-Repository ausgeführt werden:

$ git shortlog v1.6.4 --numbered --summary
  6904  Junio C Hamano
  1320  Shawn O. Pearce
  1065  Linus Torvalds
    692  Johannes Schindelin
    443  Eric Wong

2
Beachten Sie, dass dies v1.6.4hier in diesem Beispiel der Fall ist, um die Ausgabe deterministisch zu gestalten: Es ist unabhängig davon, wann Sie das Git-Repository geklont und / oder abgerufen haben, dasselbe.
Jakub Narębski

einschließlich v1.6.4gibt mir:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Vlad der Impala

5
Ah, nein, ich habe "beim Ausführen im Git-Repository" verpasst. Um fair zu sein, die meisten Menschen würden nicht diesen Befehl auf dem git Repo laufen. Eigentlich mit ziemlich großem Abstand.
Vlad der Impala

4
git shortlog -sneoder, wenn Sie lieber keine Zusammenschlüsse einschließen git shortlog -sne --no-merges
möchten

1
@Swards: -sis --summary, -nis --numberedund [new] -esoll --emailE-Mails von Autoren anzeigen (und denselben Autor mit unterschiedlicher E-Mail-Adresse unter Berücksichtigung von .mailmapKorrekturen separat zählen ). Guter Anruf über --no-merges.
Jakub Narębski

75

Nachdem ich mir die Antwort von Alex und Gerty3000 angesehen habe , habe ich versucht, den Einzeiler zu verkürzen:

Grundsätzlich verwenden Sie git log numstat und verfolgen nicht die Anzahl der geänderten Dateien .

Git Version 2.1.0 unter Mac OSX:

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

Beispiel:

Jared Burrows   added lines: 6826, removed lines: 2825, total lines: 4001

Ich kann keinen Alias ​​daraus machen :-(
brat

33

Die Antwort von AaronM mit dem Shell- Einzeiler ist gut, aber tatsächlich gibt es noch einen weiteren Fehler, bei dem Leerzeichen die Benutzernamen beschädigen, wenn zwischen dem Benutzernamen und dem Datum unterschiedliche Leerzeichen vorhanden sind. Die beschädigten Benutzernamen geben mehrere Zeilen für die Anzahl der Benutzer an, und Sie müssen sie selbst zusammenfassen.

Diese kleine Änderung hat das Problem für mich behoben:

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

Beachten Sie das + nach \ s, das alle Leerzeichen vom Namen bis zum Datum belegt.

Eigentlich füge ich diese Antwort sowohl für meine eigene Erinnerung als auch für die Hilfe für andere hinzu, da dies mindestens das zweite Mal ist, dass ich das Thema google :)

  • Bearbeiten 2019-01-23 Wurde hinzugefügt --show-email, git blame -wum stattdessen E-Mails zu aggregieren, da einige Benutzer unterschiedliche NameFormate auf unterschiedlichen Computern verwenden und manchmal zwei Personen mit demselben Namen im selben Git arbeiten.

Diese Antwort mit Perl schien etwas besser zu sein als die auf Rubin basierenden. Ruby verschluckte sich an Zeilen, die kein tatsächlicher UTF-8-Text waren, Perl beschwerte sich nicht. Aber hat Perl das Richtige getan? Ich weiß es nicht.
Stéphane Gourichon

Submodule ergeben, unsupported file typeaber ansonsten scheint es auch mit ihnen in Ordnung zu funktionieren (es überspringt sie).
Vladimír Čunát

24

Hier ist ein kurzer Einzeiler, der Statistiken für alle Autoren erstellt. Es ist viel schneller als die oben beschriebene Lösung von Dan unter https://stackoverflow.com/a/20414465/1102119 (meine hat die Zeitkomplexität O (N) anstelle von O (NM), wobei N die Anzahl der Commits und M die Anzahl der Autoren ist ).

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

4
Schön, aber was bedeutet die Ausgabe?
Gary Willoughby

Sie sollten hinzufügen --no-show-signature, sonst werden Personen, die ihre Commits pgp-signieren, nicht gezählt.
Philihp Busby

2
ins [a] - del [a], ins [a], del [a], a, also wenn ich richtig bin Einfügung-Löschung, Einfügung, Löschung, Name
MrKekson

Wie kann ich diesen Befehl zu meiner Git-Konfiguration hinzufügen, damit ich ihn mit "Git-Zählzeilen" aufrufen kann?
Takanuva15

Egal, ich habe es herausgefunden : count-lines = "!f() { 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; }; f". (Beachten Sie, dass ich unter Windows bin; möglicherweise müssen Sie verschiedene Arten von Anführungszeichen verwenden)
takanuva15

21

@mmrobins @AaronM @ErikZ @JamesMishra lieferte Varianten, die alle ein gemeinsames Problem haben: Sie fordern git auf, eine Mischung von Informationen zu erstellen, die nicht für den Skriptverbrauch bestimmt sind, einschließlich des Zeileninhalts aus dem Repository in derselben Zeile, und ordnen das Durcheinander dann einem regulären Ausdruck zu .

Dies ist ein Problem, wenn einige Zeilen keinen gültigen UTF-8-Text enthalten und wenn einige Zeilen mit dem regulären Ausdruck übereinstimmen (dies ist hier geschehen).

Hier ist eine modifizierte Zeile, die diese Probleme nicht hat. Es fordert git auf, Daten sauber in separaten Zeilen auszugeben, was es einfach macht, das, was wir wollen, robust zu filtern:

git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n

Sie können nach anderen Zeichenfolgen wie Author-Mail, Committer usw. suchen.

Vielleicht zuerst export LC_ALL=C(vorausgesetzt bash), um die Verarbeitung auf Byte-Ebene zu erzwingen (dies beschleunigt auch grep von den UTF-8-basierten Gebietsschemas enorm).


Schöne Zeile dort, sehr cool, dass man es leicht verwechseln kann, dies jedoch nicht das tut, was das Originalplakat verlangt, eine Zählung des Autors von git. Sicher, Sie könnten es ausführen und ein wc-l usw. ausführen, aber dann müssten Sie es für jeden Autor im Repository wiederholen.
AaronM

1
@ AaronM Ich verstehe deine Kritik nicht. Diese Zeile AFAIK gibt die gleichen Statistiken wie Ihre aus, nur robuster. Wenn meine Antwort "nicht das tut, was das Originalplakat verlangt, geben Sie eine Zählung nach Autor von git an", dann Ihre noch mehr. Bitte erleuchte mich.
Stéphane Gourichon

Entschuldigung, ich habe falsch verstanden. Ich dachte, der Befehl muss für jeden Namen des jeweiligen Autors geändert werden. Ihr Kommentar zu grep für andere Saiten führte mich dorthin, aber es war mein Missverständnis.
AaronM

Das ist so toll. Vielen Dank!
Tek

16

Es wurde eine Lösung mit Ruby in der Mitte angegeben, wobei Perl standardmäßig etwas verfügbarer ist. Hier ist eine Alternative, bei der Perl für aktuelle Zeilen nach Autor verwendet wird.

git ls-files -z | xargs -0n1 git blame -w | perl -n -e '/^.*\((.*?)\s*[\d]{4}/; print $1,"\n"' | sort -f | uniq -c | sort -n

5
Der aktualisierte reguläre Ausdruck macht keinen bedeutenden Unterschied und ist fehlerhaft, da Sie dem ersten Paren nicht entkommen sind. Ich kann jedoch einige Fälle sehen, in denen mein vorheriger möglicherweise einige Bits in der Codezeile findet, an die er sich binden kann. Dies würde zuverlässiger funktionieren: git ls-files -z | xargs -0n1 git schuld -w | perl -n- '/^.*?\((.*?)\s[\d]{4}/; $ 1, "\ n" print' | sort -f | uniq -c | sort -n
AaronM

Vielen Dank, dass Sie versucht haben, einen zuverlässigeren regulären Ausdruck zu erstellen. Siehe meine Antwort für eine robustere Variante stackoverflow.com/a/36090245/1429390
Stéphane Gourichon

13

Zusätzlich zu Charles Baileys Antwort möchten Sie möglicherweise den -CParameter zu den Befehlen hinzufügen . Andernfalls zählen Umbenennungen von Dateien als viele Hinzufügungen und Entfernungen (so viele wie die Datei Zeilen enthält), selbst wenn der Dateiinhalt nicht geändert wurde.

Zur Veranschaulichung hier ein Commit mit vielen Dateien, die mit dem folgenden git log --oneline --shortstatBefehl aus einem meiner Projekte verschoben werden :

9052459 Reorganized project structure
 43 files changed, 1049 insertions(+), 1000 deletions(-)

Und hier das gleiche Commit mit dem git log --oneline --shortstat -CBefehl, der Dateikopien erkennt und umbenennt:

9052459 Reorganized project structure
 27 files changed, 134 insertions(+), 85 deletions(-)

Meiner Meinung nach gibt letzteres einen realistischeren Überblick darüber, wie viel Einfluss eine Person auf das Projekt hatte, da das Umbenennen einer Datei viel kleiner ist als das Schreiben der Datei von Grund auf.


2
Wenn ich "git log --oneline --shortstat" ausführe, erhalte ich Ihr Ergebnis nicht. Ich habe eine Liste von Commits mit der Anzahl der Ausgaben, aber nicht der Gesamtzahl. Wie kann ich die Gesamtzahl der Zeilen im gesamten Git-Repository bearbeiten lassen?
Mehdi

12

Sie können whodid verwenden ( https://www.npmjs.com/package/whodid )

$ npm install whodid -g
$ cd your-project-dir

und

$ whodid author --include-merge=false --path=./ --valid-threshold=1000 --since=1.week

oder einfach tippen

$ whodid

dann können Sie das Ergebnis so sehen

Contribution state
=====================================================
 score  | author
-----------------------------------------------------
 3059   | someguy <someguy@tensorflow.org>
 585    | somelady <somelady@tensorflow.org>
 212    | niceguy <nice@google.com>
 173    | coolguy <coolgay@google.com>
=====================================================

Was bedeutet "Punktzahl"?
user11171

@ Volte npm Ich bin nur eine Abkürzung für npm Installation
Michiel

Ja, ich bin mir bewusst. Mein -gmusste vor dem Paketnamen kommen, auf macOS. Einfach versuchen zu helfen.
Volte

11

Hier ist ein kurzes Ruby-Skript, das die Auswirkungen pro Benutzer auf eine bestimmte Protokollabfrage vergleicht.

Zum Beispiel für Rubinius :

Brian Ford: 4410668
Evan Phoenix: 1906343
Ryan Davis: 855674
Shane Becker: 242904
Alexander Kellett: 167600
Eric Hodel: 132986
Dirkjan Bussink: 113756
...

das Skript:

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

2
Dieses Skript ist großartig, schließt jedoch Autoren aus, die nur einzeilige Commits haben! Um dies zu beheben, ändern Sie Folgendes: Änderungen = / (\ d +) Einfügen. * (\ D +) Löschen / .match (Zeile)
Larry Gritz

9

Dies ist der beste Weg und gibt Ihnen auch ein klares Bild der Gesamtzahl der Commits aller Benutzer

git shortlog -s -n

2
Nützlich, aber das ist die Anzahl der Commits, nicht die Gesamtzahl der Codezeilen
Diolor

5

Ich habe oben eine Modifikation einer kurzen Antwort angegeben, die jedoch für meine Bedürfnisse nicht ausreichte. Ich musste in der Lage sein, sowohl festgeschriebene Zeilen als auch Zeilen im endgültigen Code zu kategorisieren. Ich wollte auch eine Aufschlüsselung nach Dateien. Dieser Code wird nicht wiederholt, sondern gibt nur die Ergebnisse für ein einzelnes Verzeichnis zurück. Es ist jedoch ein guter Anfang, wenn jemand weiter gehen möchte. Kopieren Sie eine Datei, fügen Sie sie in eine Datei ein und machen Sie sie ausführbar oder führen Sie sie mit Perl aus.

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

Ich erhalte diesen Fehler: Illegale Division durch Null in x.pl Zeile 71.
Vivek Jha

Adressierte die illegale Division durch Null in Zeile 71. Ich denke, es tritt auf, wenn es keine Änderungen gibt, aber es ist eine Weile her, dass ich dies geschrieben habe.
AaronM

2

Für Windows-Benutzer können Sie das folgende Batch-Skript verwenden, das die hinzugefügten / entfernten Zeilen für den angegebenen Autor zählt

@echo off

set added=0
set removed=0

for /f "tokens=1-3 delims= " %%A in ('git log --pretty^=tformat: --numstat --author^=%1') do call :Count %%A %%B %%C

@echo added=%added%
@echo removed=%removed%
goto :eof

:Count
  if NOT "%1" == "-" set /a added=%added% + %1
  if NOT "%2" == "-" set /a removed=%removed% + %2
goto :eof

https://gist.github.com/zVolodymyr/62e78a744d99d414d56646a5e8a1ff4f


2

Hier ist ein großartiges Repo, das dir das Leben leichter macht

git-quick-stats

Auf einem Mac mit installiertem Gebräu

brew install git-quick-stats

Lauf

git-quick-stats

Wählen Sie einfach die gewünschte Option aus dieser Liste aus, indem Sie die angegebene Nummer eingeben und die Eingabetaste drücken.

 Generate:
    1) Contribution stats (by author)
    2) Contribution stats (by author) on a specific branch
    3) Git changelogs (last 10 days)
    4) Git changelogs by author
    5) My daily status
    6) Save git log output in JSON format

 List:
    7) Branch tree view (last 10)
    8) All branches (sorted by most recent commit)
    9) All contributors (sorted by name)
   10) Git commits per author
   11) Git commits per date
   12) Git commits per month
   13) Git commits per weekday
   14) Git commits per hour
   15) Git commits by author per hour

 Suggest:
   16) Code reviewers (based on git history)


1

Dieses Skript hier wird es tun. Setzen Sie es in autorship.sh, chmod + x it ein und Sie sind fertig.

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

1
nein, es wird nicht!, du hast dies an anderer Stelle gepostet, es erzeugt Fehler auf Macs und Linux, weißt du, die Art von Computern, auf denen Git gemacht wurde!
Pizzaiola Gorgonzola

1

Speichern Sie Ihre Protokolle in einer Datei mit:

git log --author="<authorname>" --oneline --shortstat > logs.txt

Für Python-Liebhaber:

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')

Ihre Ausgaben wären wie folgt:

225        files changed
6751       insertions
1379       deletions

0

Du willst Git die Schuld geben .

Es gibt eine --show-stats-Option, um einige Statistiken zu drucken.


Ich habe es versucht blame, aber es gab nicht wirklich die Statistiken, von denen ich dachte, dass das OP sie brauchen würde?
CB Bailey

Danke, das hat mir auch bei .mailmap geholfen!
Gav

0

Die Frage fragte nach Informationen zu einem bestimmten Autor, aber viele der Antworten waren Lösungen, die Ranglisten von Autoren basierend auf ihren geänderten Codezeilen zurückgaben.

Das war es, wonach ich gesucht habe, aber die vorhandenen Lösungen waren nicht ganz perfekt. Im Interesse von Personen, die diese Frage möglicherweise über Google finden, habe ich einige Verbesserungen vorgenommen und sie in ein Shell-Skript umgewandelt, das ich unten anzeige. Eine kommentierte (die ich weiterhin pflegen werde) befindet sich auf meinem Github .

Es gibt keine Abhängigkeiten von Perl oder Ruby. Darüber hinaus werden Leerzeichen, Umbenennungen und Zeilenbewegungen bei der Anzahl der Zeilenänderungen berücksichtigt. Fügen Sie dies einfach in eine Datei ein und übergeben Sie Ihr Git-Repository als ersten Parameter.

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


0

Ich habe dieses Perl-Skript geschrieben, um diese Aufgabe zu erfüllen.

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

Ich habe es benannt git-line-changes-by-authorund hineingesteckt /usr/local/bin. Da es in meinem Pfad gespeichert ist, kann ich den Befehl ausgebengit line-changes-by-author --before 2018-12-31 --after 2020-01-01 zum Abrufen des Berichts für das Jahr 2019 . Als Beispiel. Und wenn ich falsch schreiben würde, würde der Name git die richtige Schreibweise vorschlagen.

Möglicherweise möchten Sie das _get_repo_slugSub so anpassen , dass es nur den letzten Teil der remote.origin.urlRepos enthält, unter denen meine Repos gespeichert sind, project/repound Ihre möglicherweise nicht.

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.