Come contare le linee totali modificate da un autore specifico in un repository Git?


458

Esiste un comando che posso invocare che conterà le righe modificate da un autore specifico in un repository Git? So che ci devono essere modi per contare il numero di commit mentre Github lo fa per il loro grafico Impact.


1
Potresti considerare il famoso strumento che raccoglie le statistiche per lo sviluppo del kernel Linux, ad esempio Repository è qui git://git.lwn.net/gitdm.git.
0andriy,

Risposte:


310

L'output del comando seguente dovrebbe essere ragionevolmente facile da inviare allo script per sommare i totali:

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

Ciò fornisce statistiche per tutti gli commit sull'attuale HEAD. Se vuoi sommare le statistiche in altri settori dovrai fornirle come argomenti git log.

Per passare a uno script, rimuovere anche il formato "online" può essere fatto con un formato di registro vuoto e, come commentato da Jakub Narębski, --numstatè un'altra alternativa. Genera statistiche per file anziché per riga ma è ancora più facile da analizzare.

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

2
Ho cambiato la mia risposta accettata poiché ciò fornisce l'output nel modo in cui mi aspettavo e sarà più utile per gli altri visitatori che desiderano raggiungere questo obiettivo.
Gav,

14
È possibile utilizzare --numstatinvece di --shortstataggiungere statistiche un po 'più semplici.
Jakub Narębski,

8
Potrebbe voler aggiungere anche "--no-merges".
yoyo

9
scusa per questa domanda, ma cosa mi dicono i numeri? Ci sono due file e non ho idea di cosa mi stiano dicendo. Linee modificate e aggiunte?
Informatic0re

2
@ Informatic0re git help logmi dice che le prime sono le righe aggiunte, le seconde cancellate.
ThomasH,

599

Questo fornisce alcune statistiche sull'autore, modificarle come richiesto.

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

Utilizzando Awk su Mac OSX:

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)

Esiste un nuovo pacchetto su github che sembra elegante e usa bash come dipendenze (testato su Linux). È più adatto per l'uso diretto piuttosto che per gli script.

È git-quick-stats (link github) .

Copia git-quick-statsin una cartella e aggiungi la cartella al percorso.

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

Uso:

git-quick-stats

inserisci qui la descrizione dell'immagine


18
Grazie per questo delizioso long-liner! Questo punto di awk ha spazzato via il mazzo di tutti (preciso, veloce, nessun risultato strano in più). Non sorprende, considerando che questo è il genere di cose per cui Awk è stato progettato ... Peccato che tu fossi in ritardo alla festa.
zxq9,

4
@ zxq9: non ero nemmeno su StackOverflow quando mi è stata posta la domanda e sono stato ispirato dalle risposte qui. speriamo che riuscirò a superare lentamente tutti qui mentre le persone continuano a averne bisogno.
Alex,

9
Funziona benissimo, ma ho dovuto cambiare gawkper awkfarlo funzionare nel terminale OSX
Zach Lysobey,

1
@samthebest, perché lo spostamento del file non riflette una statistica corretta. Le linee non sono cambiate. Ad Alex: sto parlando di Git. A proposito, vedi il mio commento alla domanda originale.
0andriy,

2
Se l'URL non funziona per te, prova questo:git clone https://github.com/arzzen/git-quick-stats.git
Nicolas,

226

Nel caso in cui qualcuno volesse vedere le statistiche per ogni utente nella propria base di codice, un paio dei miei colleghi hanno recentemente inventato questo orribile one-liner:

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

(Ci vogliono alcuni minuti per eseguire il repository sul nostro repository, che ha circa 10-15k di commit.)


12
È fantastico! michael,: 6057 files changed, 854902 insertions(+), 26973 deletions(-), 827929 net
Michael J. Calkins,

1
@EugenKonkov nel codice è definito come inserzioni - eliminazioni.
Dan

13
questo è l'unico comando che fornisce il risultato totale per un repository e viene eseguito senza alcun plug-in.
Ömer Faruk Almalı,

1
Sto elencando un gruppo di utenti, quasi tutte le possibili combinazioni di sviluppatori che tornano. stranezza da parte mia?
Damon,

2
@BenSewards potresti usare Bash su Windows usando il sottosistema Windows per Linux, maggiori informazioni qui
mjsr

152

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

è uno strumento utile per ottenere il conteggio di tutti gli autori contemporaneamente, inclusi il conteggio dei file di commit e modificati:

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

Esiste anche la versione di Python su https://github.com/casperdcl/git-fame (menzionata da @fracz):

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

Uscita campione:

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

Ma attenzione: come menzionato da Jared nel commento, per farlo su un archivio molto grande ci vorranno ore. Non sono sicuro se ciò potrebbe essere migliorato, considerando che deve elaborare così tanti dati Git.


1
Questo è fantastico ma così lento
Jared Burrows,

1
Ha funzionato bene a metà 2015 MacBook e progetto Android di medie dimensioni (127k LoC 'è). Un paio di minuti.
maxweber,

2
@Vincent percent of toal loc / commit / files per l'utente corrente.
Ciro Santilli 8 冠状 病 六四 事件 法轮功

1
Cambia ramo, timeout ed escludi una cartella:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer

1
@AlexanderMills Suppongo sia perché non puoi contare in modo significativo le righe sui
BLOB

103

Ho trovato quanto segue utile per vedere chi aveva più righe che erano attualmente nella base di codice:

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

Le altre risposte si sono concentrate principalmente sulle linee modificate nei commit, ma se i commit non sopravvivono e vengono sovrascritti, potrebbero semplicemente essere sfocati. L'incantesimo di cui sopra ti fa anche ordinare tutti i committer ordinati per linee anziché solo uno alla volta. Puoi aggiungere alcune opzioni a git blame (-C -M) per ottenere numeri migliori che tengano conto dello spostamento dei file e dello spostamento della linea tra i file, ma il comando potrebbe essere eseguito molto più a lungo se lo fai.

Inoltre, se stai cercando le righe modificate in tutti i commit per tutti i commit, il seguente piccolo script è utile:

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


31
Stavo per dare un +1, ma poi ho capito che la soluzione dipende dal rubino ... :(
mac

3
Potresti modificarlo per non usare ruby ​​abbastanza facilmente dato che uso solo ruby ​​per la sostituzione della stringa. Puoi usare perl, sed, python, ecc.
mmrobins il

21
non funziona per me: -e: 1: in `<main> ': sequenza di byte non valida in UTF-8 (ArgumentError)
Michał Dębski

1
/^.*\((.*?)\s[\d]{4}/dovrebbe essere /^.*?\((.*?)\s[\d]{4}/per impedire l'abbinamento delle parentesi nella fonte come autore.
Timothy Gu,

1
mmm le mie esecuzioni hanno mostrato molti utenti che non esistono nemmeno, a causa di un cattivo analisi. Penso che non sia una risposta affidabile.
mjsr

92

Per contare il numero di commit di un determinato autore (o di tutti gli autori) su un determinato ramo puoi usare git-shortlog ; vedere soprattutto le sue --numberede le --summaryopzioni, ad es. quando eseguito sul repository 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

2
Nota che v1.6.4è qui in questo esempio per rendere deterministico l'output: sarà lo stesso indipendentemente da quando hai clonato e / o recuperato dal repository git.
Jakub Narębski,

tra cui v1.6.4mi dà:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Vlad l'Impala il

5
Ah, no, mi sono perso "quando eseguito sul repository git". Per essere onesti, la maggior parte delle persone non eseguirà questo comando sul repository git. Con un margine abbastanza grande, in realtà.
Vlad l'Impala,

4
git shortlog -sneoppure, se preferisci non includere le fusionigit shortlog -sne --no-merges
Mark Swardstrom

1
@Swards: -sè --summary, -nè --numberede [nuovo] -edeve --emailmostrare le e-mail degli autori (e contare separatamente lo stesso autore con un indirizzo e-mail diverso, tenendo conto delle .mailmapcorrezioni). Buona telefonata --no-merges.
Jakub Narębski,

75

Dopo aver esaminato la risposta di Alex e Gerty3000 , ho cercato di abbreviare il one-liner:

Fondamentalmente, usando git log numstat e non tenere traccia del numero di file modificati.

Git versione 2.1.0 su 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

Esempio:

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

Non posso farne un alias :-(
marmocchio

33

La risposta di AaronM che utilizza la shell one-liner è buona, ma in realtà c'è ancora un altro bug, in cui gli spazi danneggeranno i nomi degli utenti se ci sono diverse quantità di spazi bianchi tra il nome dell'utente e la data. I nomi utente danneggiati forniranno più righe per il conteggio degli utenti e dovrai sommarli da soli.

Questa piccola modifica ha risolto il problema per me:

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

Notare il segno + dopo che consumerà tutti gli spazi bianchi dal nome alla data.

In realtà aggiungendo questa risposta tanto per il mio ricordo quanto per aiutare chiunque altro, poiché questa è almeno la seconda volta che google l'argomento :)

  • Modifica 23/01/2019 Aggiunta --show-emaila git blame -wper aggregare via e-mail, poiché alcune persone usano Nameformati diversi su computer diversi, e talvolta due persone con lo stesso nome lavorano nello stesso git.

Questa risposta usando il perl sembra essere leggermente migliore di quella basata sul rubino. Ruby si strozzò con linee che non erano un vero testo UTF-8, perl non si lamentò. Ma perl ha fatto la cosa giusta? Non lo so.
Stéphane Gourichon,

I sottomoduli risultano in, unsupported file typema per il resto sembra funzionare anche con loro (li salta).
Vladimír Čunát,

24

Ecco un breve one-liner che produce statistiche per tutti gli autori. È molto più veloce della soluzione di Dan sopra su https://stackoverflow.com/a/20414465/1102119 (la mia ha una complessità temporale O (N) invece di O (NM) dove N è il numero di commit e M il numero di autori ).

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
Bello ma cosa significa l'uscita?
Gary Willoughby,

Dovresti aggiungere --no-show-signature, altrimenti le persone che firmano pgp i loro commit non verranno conteggiate.
Philihp Busby,

2
ins [a] - del [a], ins [a], del [a], a, quindi se ho ragione inserimento-cancellazione, inserimento, cancellazione, nome
MrKekson

Come posso aggiungere questo comando al mio git config in modo da poterlo chiamare con "git count-lines"?
takanuva15,

Non importa, ho capito: 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". (Nota che sono su Windows; potrebbe essere necessario utilizzare diversi tipi di virgolette)
takanuva15

21

@mmrobins @AaronM @ErikZ @JamesMishra ha fornito varianti che hanno tutti un problema in comune: chiedono a git di produrre una miscela di informazioni non destinate al consumo di script, inclusi i contenuti di linea dal repository sulla stessa linea, quindi abbinano il pasticcio con un regexp .

Questo è un problema quando alcune righe non sono valide per il testo UTF-8 e anche quando alcune righe corrispondono al regexp (questo è successo qui).

Ecco una riga modificata che non presenta questi problemi. Richiede a git di inviare i dati in modo pulito su linee separate, il che semplifica il filtraggio di ciò che vogliamo in modo affidabile:

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

È possibile eseguire il grep per altre stringhe, come la posta autore, il committer, ecc.

Forse prima fai export LC_ALL=C(supponendo bash) per forzare l'elaborazione a livello di byte (questo succede anche per accelerare enormemente grep dalle localizzazioni basate su UTF-8).


Bella linea lì, molto bella, che puoi facilmente confonderla, tuttavia questo non riesce a fare ciò che il poster originale ha richiesto, fornire un conteggio dell'autore da Git. Sicuro che potresti eseguirlo e fare un wc-l, ecc., Ma allora dovresti ripetere per ogni autore nel repository.
AaronM,

1
@AaronM Non capisco le tue critiche. Questa linea AFAIK produce le stesse statistiche della tua, solo più robuste. Quindi, se la mia risposta "non riesce a fare ciò che il poster originale ha richiesto, fornire un conteggio dell'autore di Git", allora il tuo ancora di più. Per favore, illuminami.
Stéphane Gourichon,

scusate ho letto male, ho pensato che il comando dovesse essere modificato per ogni diverso nome dell'autore. Il tuo commento su grep per altre stringhe mi ha portato lì, ma è stato il mio malinteso.
AaronM,

Questo è fantastico. Grazie!
Tek

16

Una soluzione è stata data con ruby ​​nel mezzo, perl essendo un po 'più disponibile di default qui è un'alternativa che utilizza perl per le righe correnti dell'autore.

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
Il regex aggiornato non fa una differenza significativa ed è rotto poiché non sei sfuggito al primo paren. Tuttavia, posso vedere alcuni casi in cui il mio precedente potrebbe trovare alcuni bit nella riga di codice su cui agganciarsi. Funzionerebbe in modo più affidabile: git ls-files -z | xargs -0n1 git biasimo -w | perl -n -e '/^.*?\((.*?)\s[\d[{4}/; print $ 1, "\ n"' | sort -f | uniq -c | sort -n
AaronM,

grazie per aver provato a creare una regexp più affidabile. Vedere la mia risposta per una più robusta variante stackoverflow.com/a/36090245/1429390
Stéphane Gourichon

13

Oltre alla risposta di Charles Bailey , potresti voler aggiungere il -Cparametro ai comandi. In caso contrario, i nomi dei file vengono conteggiati come molte aggiunte e rimozioni (quante sono le righe del file), anche se il contenuto del file non è stato modificato.

Per illustrare, ecco un commit con molti file che vengono spostati da uno dei miei progetti, quando si utilizza il git log --oneline --shortstatcomando:

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

E qui lo stesso commit utilizzando il git log --oneline --shortstat -Ccomando che rileva le copie e le ridenominazioni dei file:

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

A mio avviso, quest'ultimo offre una visione più realistica dell'impatto che una persona ha avuto sul progetto, perché rinominare un file è un'operazione molto più piccola rispetto alla scrittura del file da zero.


2
Quando eseguo "git log --oneline --shortstat", non ottengo il risultato. Ho un elenco di commit con il numero di edizioni ma non il numero totale. Come posso ottenere il numero totale di righe modificate in tutto il repository git?
Mehdi,

12

puoi usare whodid ( https://www.npmjs.com/package/whodid )

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

e

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

o semplicemente digitare

$ whodid

allora puoi vedere il risultato in questo modo

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

Cosa significa "punteggio"?
user11171

@Volte npm i è solo una scorciatoia per l'installazione di npm
Michiel

Sì, ne sono consapevole. Il mio -gdoveva venire prima del nome del pacchetto, su macOS. Sto semplicemente cercando di aiutare.
Volte

11

Ecco uno script ruby ​​rapido che corregge l'impatto per utente rispetto a una determinata query di registro.

Ad esempio, per rubinius :

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

il copione:

#!/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
Questa sceneggiatura è fantastica, ma esclude gli autori che hanno solo commit a riga singola! Per risolvere, modifica come segue: modifiche = / (\ d +) inserimento. * (\ D +) cancellazione / .match (linea)
Larry Gritz,

9

questo è il modo migliore e ti dà anche una chiara immagine del numero totale di commit da parte di tutti gli utenti

git shortlog -s -n

2
Utile, ma questo è il numero di commit non delle linee di codice totali
Diolor,

5

Ho fornito una modifica di una breve risposta sopra, ma non era sufficiente per le mie esigenze. Avevo bisogno di essere in grado di classificare sia le righe impegnate sia le righe nel codice finale. Volevo anche una suddivisione per file. Questo codice non viene utilizzato, restituirà solo i risultati per una singola directory, ma è un buon inizio se qualcuno volesse andare oltre. Copia e incolla in un file e rendilo eseguibile o eseguilo con 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};
}

Ricevo questo errore: Divisione illegale per zero alla linea 71 x.pl.
Vivek Jha,

Risolto il problema con la divisione illegale a zero sulla linea 71. Pensa che si verifichi se non ci sono modifiche ma è stato qualche tempo fa che l'ho scritto.
AaronM,

2

Per gli utenti di Windows è possibile utilizzare il seguente script batch che conta le righe aggiunte / rimosse per l'autore specificato

@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

Ecco un ottimo repository che ti semplifica la vita

git-quick-stats

Su un mac con brew installato

brew install git-quick-stats

Correre

git-quick-stats

Basta scegliere quale opzione si desidera da questo elenco digitando il numero elencato e premendo invio.

 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

Questo script qui lo farà. Inseriscilo in authorship.sh, chmod + x it e sei pronto.

#!/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
no WONT !, lo hai pubblicato altrove, genera errori su Mac e Linux, sai, il tipo di computer su cui è stato creato git!
Pizzaiola Gorgonzola

1

Salva i tuoi log in file usando:

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

Per gli amanti di 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')

Le tue uscite sarebbero come:

225        files changed
6751       insertions
1379       deletions

0

Vuoi colpa di Git .

C'è un'opzione --show-stats per stampare alcune, beh, statistiche.


Ci ho provato blame, ma in realtà non ha dato le statistiche che pensavo fossero necessarie all'OP?
CB Bailey,

Grazie, anche questo mi ha aiutato con .mailmap!
Gav,

0

La domanda richiedeva informazioni su un autore specifico , ma molte delle risposte erano soluzioni che restituivano elenchi classificati di autori in base alle loro linee di codice modificate.

Era quello che cercavo, ma le soluzioni esistenti non erano del tutto perfette. Nell'interesse delle persone che potrebbero trovare questa domanda tramite Google, ho apportato alcuni miglioramenti e li ho trasformati in uno script di shell, che visualizzo di seguito. Una annotata (che continuerò a mantenere) può essere trovata sul mio Github .

Non ci sono alcun dipendenze su entrambi Perl o Ruby. Inoltre, nel conteggio dei cambi di linea vengono presi in considerazione spazi bianchi, rinominazioni e movimenti di linea. Basta inserirlo in un file e passare il repository Git come primo parametro.

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

Lo strumento migliore che ho identificato finora è gitinspector. Fornisce il rapporto impostato per utente, per settimana ecc. È possibile installare come di seguito con npm

npm install -g gitinspector

I collegamenti per ottenere maggiori dettagli

https://www.npmjs.com/package/gitinspector

https://github.com/ejwa/gitinspector/wiki/Documentation

https://github.com/ejwa/gitinspector

comandi di esempio sono

gitinspector -lmrTw 
gitinspector --since=1-1-2017 etc

0

Ho scritto questo script Perl per compiere quel compito.

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

L'ho chiamato git-line-changes-by-authore inserito /usr/local/bin. Poiché è stato salvato nel mio percorso, posso inviare il comando git line-changes-by-author --before 2018-12-31 --after 2020-01-01per ottenere il rapporto per l'anno 2019. Come esempio. E se dovessi sbagliare, il nome git suggerirà l'ortografia corretta.

Potresti voler regolare il _get_repo_slugsottotitolo per includere solo l'ultima porzione di remote.origin.urlcome i miei repository vengono salvati come project/repoe il tuo potrebbe non esserlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.