¿Cómo contar las líneas totales modificadas por un autor específico en un repositorio de Git?

458

¿Hay un comando que pueda invocar que contará las líneas cambiadas por un autor específico en un repositorio de Git? Sé que debe haber formas de contar el número de confirmaciones, ya que Github hace esto para su gráfico de Impacto.

Gav
fuente
1
Puede considerar una herramienta famosa que recopila estadísticas para el desarrollo del kernel de Linux, por ejemplo, el repositorio está aquí git://git.lwn.net/gitdm.git.
0andriy

Respuestas:

310

El resultado del siguiente comando debería ser razonablemente fácil de enviar al script para sumar los totales:

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

Esto proporciona estadísticas para todos los commits en el HEAD actual. Si desea agregar estadísticas en otras ramas, deberá proporcionarlas como argumentos para git log.

Para pasar a un script, eliminar incluso el formato "en línea" se puede hacer con un formato de registro vacío, y como comentó Jakub Narębski, --numstates otra alternativa. Genera estadísticas por archivo en lugar de por línea, pero es aún más fácil de analizar.

git log --author="<authorname>" --pretty=tformat: --numstat
CB Bailey
fuente
2
Cambié mi respuesta aceptada, ya que esto da el resultado de la manera que esperaba, y será más útil para otros visitantes que buscan lograr esto.
Gav
14
Puede usarlo en --numstatlugar de hacerlo --shortstatsi desea agregar estadísticas un poco más fácilmente.
Jakub Narębski
8
Es posible que desee agregar "--no-merges" allí también.
yoyo
99
perdón por estas preguntas, pero ¿qué me dicen los números? Hay dos filas y no tengo idea de lo que me están diciendo. ¿Líneas reducidas y agregadas?
Informatic0re
2
@ Informatic0re git help logme dice que las primeras son líneas agregadas, las segundas líneas borradas.
ThomasH
599

Esto proporciona algunas estadísticas sobre el autor, modificar según sea necesario.

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

Usando Awk en 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 }' -

EDITAR (2017)

Hay un nuevo paquete en github que se ve elegante y usa bash como dependencias (probado en linux). Es más adecuado para uso directo en lugar de scripts.

Es git-quick-stats (enlace github) .

Copie git-quick-statsa una carpeta y agregue la carpeta a la ruta.

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

Uso:

git-quick-stats

ingrese la descripción de la imagen aquí

Alex
fuente
18
¡Gracias por este encantador palangrero! Este punto de awk absorbió el mazo de todos (preciso, rápido, sin resultados extraños extra). No es sorprendente, considerando que este es el tipo de cosas para las que awk fue diseñado ... Lástima que llegaste tan tarde a la fiesta.
zxq9
44
@ zxq9: Ni siquiera estaba en stackoverflow cuando se hizo la pregunta y las respuestas aquí me inspiraron. esperemos adelantar lentamente a todos aquí, ya que la gente sigue necesitando esto.
Alex
99
Esto funciona de maravilla, pero tuve que cambiar gawkpara awkhacerlo funcionar en el terminal OSX
Zach Lysobey
1
@samthebest, porque mover el archivo no refleja una estadística adecuada. Las líneas no cambian. A Alex: estoy hablando de Git. Por cierto, vea mi comentario a la pregunta original.
0andriy
2
Si la url no funciona para usted, intente esto:git clone https://github.com/arzzen/git-quick-stats.git
Nicolas
226

En caso de que alguien quiera ver las estadísticas de cada usuario en su base de código, un par de mis compañeros de trabajo recientemente inventaron esta horrible frase:

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

(Tarda unos minutos en analizar nuestro repositorio, que tiene alrededor de 10-15k confirmaciones).

Dan
fuente
12
¡Eso es genial! michael,: 6057 files changed, 854902 insertions(+), 26973 deletions(-), 827929 net
Michael J. Calkins
1
@EugenKonkov en el código se define como inserciones - eliminaciones.
Dan
13
ese es el único comando que da un resultado total para un repositorio y se ejecuta sin ningún complemento.
Ömer Faruk Almalı
1
Tengo un grupo de usuarios en la lista, casi todas las combinaciones posibles de desarrolladores que regresan. rareza de mi parte?
Damon
2
@BenSewards podría usar Bash en Windows usando el Subsistema de Windows para Linux, más información aquí
mjsr
152

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

es una buena herramienta para obtener el recuento de todos los autores a la vez, incluido el recuento de confirmación y archivos modificados:

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

También hay una versión de Python en https://github.com/casperdcl/git-fame (mencionado por @fracz):

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

Salida de muestra:

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

Pero ten cuidado: como lo mencionó Jared en el comentario, hacerlo en un repositorio muy grande llevará horas. Sin embargo, no estoy seguro de si eso podría mejorarse, teniendo en cuenta que debe procesar tantos datos de Git.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Esto es increíble pero muy lento
Jared Burrows
1
Funcionó bien en macbook de mediados de 2015 y un proyecto de Android mediano grande (127k LoC 'es). Un par de minutos.
maxweber
2
@Vincent porcentaje de todo loc / commits / files para el usuario actual.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Cambiar rama, tiempo de espera y excluir una carpeta:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer
1
@AlexanderMills Supongo que es porque no puedes contar de manera significativa las líneas en las gotas
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
103

Encontré lo siguiente útil para ver quién tenía la mayoría de las líneas que estaban actualmente en la base del código:

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

Las otras respuestas se han centrado principalmente en las líneas cambiadas en las confirmaciones, pero si las confirmaciones no sobreviven y se sobrescriben, es posible que hayan sido abandonadas. El encantamiento anterior también te permite ordenar todos los confirmadores por líneas en lugar de solo uno a la vez. Puede agregar algunas opciones a git blame (-C -M) para obtener mejores números que tengan en cuenta el movimiento de archivos y el movimiento de línea entre archivos, pero el comando podría ejecutarse mucho más si lo hace.

Además, si está buscando líneas cambiadas en todas las confirmaciones para todos los confirmadores, el siguiente pequeño script es útil:

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

mmrobins
fuente
31
Estaba a punto de dar un +1, pero luego me di cuenta de que la solución depende de ruby ​​... :(
mac
3
Puede modificarlo para que no use ruby ​​con bastante facilidad, ya que solo uso ruby ​​para la sustitución de cadenas. Podrías usar perl, sed, python, etc.
mmrobins
21
no funciona para mí: -e: 1: en `<main> ': secuencia de bytes no válida en UTF-8 (ArgumentError)
Michał Dębski
1
/^.*\((.*?)\s[\d]{4}/debe ser /^.*?\((.*?)\s[\d]{4}/para evitar paréntesis coincidentes en la fuente como autor.
Timothy Gu
1
mmm mis ejecuciones mostraron muchos usuarios que ni siquiera existen, debido al mal análisis. Creo que no es una respuesta confiable.
mjsr
92

Para contar el número de confirmaciones de un autor determinado (o de todos los autores) en una rama determinada, puede usar git-shortlog ; vea especialmente sus --numberedy --summaryopciones, por ejemplo, cuando se ejecuta en el repositorio de 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
Jakub Narębski
fuente
2
Tenga en cuenta que v1.6.4está aquí en este ejemplo para hacer que la salida sea determinista: será lo mismo sin importar cuándo clone y / o recupere del repositorio de git.
Jakub Narębski
incluyendo v1.6.4me da:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Vlad el Impala
55
Ah, no, me perdí "cuando se ejecuta en el repositorio de git". Para ser justos, la mayoría de las personas no ejecutarán este comando en el repositorio de git. Por un margen bastante grande, en realidad.
Vlad the Impala
44
git shortlog -sneo, si prefiere no incluir fusionesgit shortlog -sne --no-merges
Mark Swardstrom
1
@Swards: -ses --summary, -nes --numberedy [nuevo] -ees --emailmostrar correos electrónicos de autores (y contar por separado el mismo autor con diferentes direcciones de correo electrónico, teniendo en cuenta las .mailmapcorrecciones). Buena llamada sobre --no-merges.
Jakub Narębski
75

Después de mirar a Alex y la respuesta de Gerty3000 , he intentado acortar la frase :

Básicamente, usar git log numstat y no realizar un seguimiento de la cantidad de archivos modificados.

Git versión 2.1.0 en 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

Ejemplo:

Jared Burrows   added lines: 6826, removed lines: 2825, total lines: 4001
Jared Burrows
fuente
No puedo hacer un alias :-(
mocoso
33

La respuesta de AaronM usando el shell one-liner es buena, pero en realidad, hay otro error, donde los espacios corromperán los nombres de usuario si hay diferentes cantidades de espacios en blanco entre el nombre de usuario y la fecha. Los nombres de usuario corruptos darán varias filas para los recuentos de usuarios y usted debe sumarlos usted mismo.

Este pequeño cambio solucionó el problema para mí:

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

Observe el + after \ s que consumirá todos los espacios en blanco desde el nombre hasta la fecha.

En realidad, agrego esta respuesta tanto para mi propio recuerdo como para ayudar a alguien más, ya que esta es al menos la segunda vez que busco en Google el tema :)

  • Editar 2019-01-23 Agregado --show-emaila git blame -wagregado en el correo electrónico, ya que algunas personas usan diferentes Nameformatos en diferentes computadoras, y a veces dos personas con el mismo nombre están trabajando en el mismo git.
Erik Zivkovic
fuente
Esta respuesta usando perl pareció funcionar un poco mejor que las de rubí. Ruby se atragantó con líneas que no eran texto UTF-8 real, Perl no se quejó. ¿Pero Perl hizo lo correcto? No lo sé.
Stéphane Gourichon
Los submódulos resultan unsupported file typepero, de lo contrario, parece funcionar bien incluso con ellos (los omite).
Vladimír Čunát
24

Aquí hay un breve resumen que genera estadísticas para todos los autores. Es mucho más rápido que la solución anterior de Dan en https://stackoverflow.com/a/20414465/1102119 (la mía tiene una complejidad de tiempo O (N) en lugar de O (NM) donde N es el número de confirmaciones y M el número de autores )

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
kccqzy
fuente
44
Bonito, pero ¿qué significa la salida?
Gary Willoughby
Debería agregar --no-show-signature, de lo contrario, las personas que firman sus compromisos no serán contadas.
Philihp Busby
2
ins [a] - del [a], ins [a], del [a], a, así que si tengo razón inserción-eliminación, inserción, eliminación, nombre
MrKekson
¿Cómo puedo agregar este comando a mi configuración de git para poder llamarlo con "git count-lines"?
takanuva15
No importa, lo he descubierto: 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". (Tenga en cuenta que estoy en Windows; puede que necesite usar diferentes tipos de citas)
takanuva15
21

@mmrobins @AaronM @ErikZ @JamesMishra proporcionaron variantes que tienen un problema en común: le piden a git que produzca una mezcla de información no destinada al consumo de scripts, incluido el contenido de la línea del repositorio en la misma línea, luego combina el desorden con una expresión regular .

Este es un problema cuando algunas líneas no son texto UTF-8 válido, y también cuando algunas líneas coinciden con la expresión regular (esto sucedió aquí).

Aquí hay una línea modificada que no tiene estos problemas. Solicita a git que genere datos de forma limpia en líneas separadas, lo que facilita el filtrado de lo que queremos de manera sólida:

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

Puede buscar otras cadenas, como correo de autor, committer, etc.

Quizás primero export LC_ALL=C(suponiendo bash) forzar el procesamiento a nivel de bytes (esto también acelera enormemente el grep de las configuraciones regionales basadas en UTF-8).

Stéphane Gourichon
fuente
Bonita línea allí, muy genial, que puedes mezclar fácilmente, sin embargo, esto no puede hacer lo que el póster original solicitó, proporcionar un recuento por autor de git. Claro que podría ejecutarlo y hacer un wc-l, etc., pero luego necesitaría repetir para cada autor en el repositorio.
AaronM
1
@ AaronM No entiendo tu crítica. Esta línea AFAIK genera las mismas estadísticas que la suya, solo que más robusta. Entonces, si mi respuesta "no cumple con lo que solicitó el póster original, proporcione un recuento por autor de git", entonces la suya aún más. Por favor iluminame.
Stéphane Gourichon
lo siento, leí mal, pensé que el comando tenía que modificarse para cada nombre de autor diferente. Su comentario sobre grep para otras cadenas me llevó allí, pero fue mi malentendido.
AaronM
Esto es genial ¡Gracias!
Tek
16

Se dio una solución con ruby ​​en el medio, perl está un poco más disponible por defecto aquí es una alternativa usando perl para las líneas actuales por autor.

git ls-files -z | xargs -0n1 git blame -w | perl -n -e '/^.*\((.*?)\s*[\d]{4}/; print $1,"\n"' | sort -f | uniq -c | sort -n
AaronM
fuente
55
La expresión regular actualizada no hace una diferencia significativa, y se rompe ya que no escapaste del primer par. Sin embargo, puedo ver algunos casos en los que mi anterior podría encontrar algunos bits en la línea de código para engancharse. Esto funcionaría de manera más confiable: git ls-files -z | xargs -0n1 culpa git -w | perl -n -e '/^.*?\((.*?)\s[\dfont>{4}/; print $ 1, "\ n"' | sort -f | uniq -c | sort -n
AaronM
gracias por intentar hacer una expresión regular más confiable. Vea mi respuesta para una variante más robusta stackoverflow.com/a/36090245/1429390
Stéphane Gourichon
13

Además de la respuesta de Charles Bailey , es posible que desee agregar el -Cparámetro a los comandos. De lo contrario, los cambios de nombre de archivo cuentan como muchas adiciones y eliminaciones (tantas como el archivo tenga líneas), incluso si el contenido del archivo no se modificó.

Para ilustrar, aquí hay un commit con muchos archivos que se mueven de uno de mis proyectos, cuando uso el git log --oneline --shortstatcomando:

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

Y aquí el mismo commit usando el git log --oneline --shortstat -Ccomando que detecta copias de archivos y renombra:

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

En mi opinión, este último da una visión más realista de cuánto impacto ha tenido una persona en el proyecto, porque renombrar un archivo es una operación mucho más pequeña que escribir el archivo desde cero.

Esko Luontola
fuente
2
Cuando ejecuto "git log --oneline --shortstat", no obtengo el resultado. Tengo una lista de commit con el número de ediciones pero no el número total. ¿Cómo puedo obtener el número total de líneas editadas en todo el repositorio de git?
Mehdi
12

puedes usar whodid ( https://www.npmjs.com/package/whodid )

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

y

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

o simplemente escriba

$ whodid

entonces puedes ver un resultado como este

Contribution state
=====================================================
 score  | author
-----------------------------------------------------
 3059   | someguy <[email protected]>
 585    | somelady <[email protected]>
 212    | niceguy <[email protected]>
 173    | coolguy <[email protected]>
=====================================================
victor.cheval
fuente
¿Qué significa "puntaje"?
user11171
@Volte npm i es solo un atajo para la instalación de npm
Michiel
Si, estoy enterado. Mi -gtenía que llegar antes de que el nombre del paquete, en macOS. Simplemente tratando de ayudar.
Volte
11

Aquí hay un script rápido de ruby ​​que acota el impacto por usuario en una consulta de registro dada.

Por ejemplo, para rubinius :

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

la secuencia de comandos:

#!/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
Nevir
fuente
2
¡Este script es excelente, pero excluye a los autores que solo tienen confirmaciones de una sola línea! Para solucionarlo, cambie de la siguiente manera: cambios = / (\ d +) inserción. * (\ D +) eliminación / .match (línea)
Larry Gritz
9

esta es la mejor manera y también le da una idea clara del número total de confirmaciones de todos los usuarios

git shortlog -s -n
edrich13
fuente
2
Útil, pero esa es la cantidad de confirmaciones, no líneas de código totales
Diolor
5

Proporcioné una modificación de una respuesta breve anterior, pero no fue suficiente para mis necesidades. Necesitaba poder clasificar tanto las líneas confirmadas como las líneas en el código final. También quería un desglose por archivo. Este código no se repite, solo devolverá los resultados para un solo directorio, pero es un buen comienzo si alguien quiere ir más allá. Copie y pegue en un archivo y haga ejecutable o ejecútelo 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};
}
AaronM
fuente
Recibo este error: División ilegal por cero en x.pl línea 71.
Vivek Jha
Abordó la división ilegal por cero en la línea 71. Creo que ocurre si no hay ediciones, pero hace un tiempo escribí esto.
AaronM
2

Para usuarios de Windows, puede usar el siguiente script por lotes que cuenta las líneas agregadas / eliminadas para el autor especificado

@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

Volodymyr Baydalka
fuente
2

Aquí hay un gran repositorio que te hace la vida más fácil

git-quick-stats

En un mac con brew instalado

brew install git-quick-stats

correr

git-quick-stats

Simplemente elija la opción que desea de esta lista escribiendo el número que aparece y presionando enter.

 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)

jasonleonhard
fuente
1

Este script aquí lo hará. Póngalo en authorhip.sh, chmod + x it, y ya está todo listo.

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

fuente
1
¡no, NO!, lo publicaste en otro lugar, genera errores en Mac y Linux, ya sabes, el tipo de computadoras en las que se hizo git.
Pizzaiola Gorgonzola
1

Guarde sus registros en el archivo usando:

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

Para los amantes de 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')

Sus resultados serían como:

225        files changed
6751       insertions
1379       deletions
Amén Ayach
fuente
0

Quieres culpar a Git .

Hay una opción --show-stats para imprimir algunas, bueno, estadísticas.

gbjbaanb
fuente
Lo intenté blame, pero ¿realmente no dio las estadísticas que pensé que necesitaría el OP?
CB Bailey
¡Gracias, esto también me ayudó con .mailmap también!
Gav
0

La pregunta para obtener información sobre un determinado autor , pero muchas de las respuestas fueron soluciones que arrojaron listas clasificadas de autores en función de sus líneas de código cambiadas.

Esto era lo que estaba buscando, pero las soluciones existentes no eran del todo perfectas. En interés de las personas que pueden encontrar esta pregunta a través de Google, he realizado algunas mejoras en ellos y los he convertido en un script de shell, que se muestra a continuación. Puede encontrar uno anotado (que continuaré manteniendo) en mi Github .

No hay dependencias ni en Perl ni en Ruby. Además, los espacios en blanco, los cambios de nombre y los movimientos de línea se tienen en cuenta en el recuento de cambio de línea. Simplemente ponga esto en un archivo y pase su repositorio Git como primer parámetro.

#!/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
James Mishra
fuente
0

Escribí este script de Perl para lograr esa tarea.

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

Lo nombré git-line-changes-by-authory lo puse /usr/local/bin. Debido a que está guardado en mi camino, puedo emitir el comando git line-changes-by-author --before 2018-12-31 --after 2020-01-01para obtener el informe para el año 2019. Como ejemplo. Y si tuviera que escribir mal el nombre git sugeriría la ortografía correcta.

Es posible que desee ajustar el _get_repo_slugsub para que solo incluya la última parte del remote.origin.urlarchivo ya que mis repositorios se guardan como project/repoy es posible que no lo sea.

joehep
fuente