Como contar o total de linhas alteradas por um autor específico em um repositório Git?


458

Existe um comando que eu possa chamar que contará as linhas alteradas por um autor específico em um repositório Git? Eu sei que deve haver maneiras de contar o número de confirmações, pois o Github faz isso para o gráfico de impacto.


1
Você pode considerar uma ferramenta famosa que reúne estatísticas para o desenvolvimento do kernel do Linux, por exemplo, o Repositório está aqui git://git.lwn.net/gitdm.git.
precisa saber é o seguinte

Respostas:


310

A saída do comando a seguir deve ser razoavelmente fácil de enviar ao script para adicionar os totais:

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

Isso fornece estatísticas para todos os commits no HEAD atual. Se você quiser adicionar estatísticas em outras ramificações, precisará fornecê-las como argumentos git log.

Para passar para um script, remover até o formato "on-line" pode ser feito com um formato de log vazio e, como comentado por Jakub Narębski, --numstaté outra alternativa. Ele gera estatísticas por arquivo em vez de estatísticas por linha, mas é ainda mais fácil de analisar.

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

2
Alterei minha resposta aceita, pois isso fornece a saída da maneira esperada e será mais útil para outros visitantes que desejam obter isso.
Gav

14
Você poderia usar --numstat vez de, --shortstatse quiser adicionar estatísticas um pouco mais fácil.
Jakub Narębski 12/08/09

8
Pode querer adicionar "--no-mescla" lá também.
Yoyo 12/05

9
desculpe por essas perguntas, mas quais são os números que estão me dizendo? Existem duas linhas e eu não tenho ideia do que elas estão me dizendo. Linhas chenged e adicionadas?
Informatic0re

2
@ Informatic0re git help logdiz que as primeiras são linhas adicionadas e as segundas excluídas.
ThomasH

599

Isso fornece algumas estatísticas sobre o autor, modifique conforme necessário.

Usando o 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 o Awk no 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)

Existe um novo pacote no github que parece liso e usa o bash como dependências (testado no linux). É mais adequado para uso direto, em vez de scripts.

É git-quick-stats (link do github) .

cópia de git-quick-stats para uma pasta e adicione a pasta ao caminho.

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

insira a descrição da imagem aqui


18
Obrigado por este lindo palangreiro! Esse ponto do awk varreu o convés de todos (preciso, rápido, sem saída extra estranha). Não é surpresa, considerando que esse é o tipo de coisa que o awk foi projetado para ... Pena que você estava tão atrasado para a festa.
Zxq9 15/10/12

4
@ zxq9: Eu nem estava no stackoverflow quando a pergunta foi feita e fui inspirado pelas respostas aqui. esperamos que eu supere lentamente todos aqui, pois as pessoas continuam precisando disso.
Alex

9
Isso funciona incrível, mas eu tive que mudar gawkpara awkfazê-lo funcionar no terminal OSX
Zach Lysobey

1
@samthebest, porque mover arquivo não reflete uma estatística adequada. As linhas não são alteradas. Para Alex: estou falando do Git. Btw, veja o meu comentário para a pergunta original.
0andriy

2
Se o URL não funcionar para você, tente o seguinte:git clone https://github.com/arzzen/git-quick-stats.git
Nicolas

226

Caso alguém queira ver as estatísticas de todos os usuários em sua base de código, alguns de meus colegas de trabalho recentemente criaram essa horrível 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";}'

(Demora alguns minutos para analisar nosso repo, que tem cerca de 10 a 15 mil confirmações.)


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

1
@EugenKonkov no código é definido como inserções - exclusões.
Dan

13
esse é o único comando que fornece resultado total para um repositório e é executado sem nenhum plug-in.
Ömer Faruk Almalı

1
Estou recebendo um monte de usuários listados juntos, quase todas as combinações possíveis de desenvolvedores voltando. estranheza do meu lado?
Damon

2
@ BenSewards você pode usar o Bash no Windows usando o Windows Subsystem para Linux, mais informações aqui
mjsr

152

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

é uma boa ferramenta para obter a contagem de todos os autores de uma só vez, incluindo a contagem de arquivos modificados e confirmados:

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

Também há a versão do Python em https://github.com/casperdcl/git-fame (mencionada por @fracz):

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

Saída de amostra:

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

Mas esteja avisado: como mencionado por Jared no comentário, fazê-lo em um repositório muito grande levará horas. Não tenho certeza se isso pode ser melhorado, considerando que ele deve processar tantos dados do Git.


1
Isto é incrível, mas tão lento
Jared Burrows

1
Funcionou bem no macbook de meados de 2015 e no projeto Android de médio e grande porte (127k LoC 'is). Alguns minutos.
maxweber

2
@ Percentual percentual de toal loc / confirma / arquivos para o usuário atual.
Ciro Santilli resolveu

1
Altere branch, timeout e exclua uma pasta:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer 12/07/16

1
@AlexanderMills eu estou supondo que é porque você não pode significativamente contar linhas em blobs
Ciro Santilli郝海东冠状病六四事件法轮功

103

Eu achei o seguinte útil para ver quem tinha mais linhas que estavam atualmente na base de 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

As outras respostas se concentraram principalmente nas linhas alteradas nos commits, mas se os commits não sobreviverem e forem sobrescritos, eles podem ter sido apenas rotativos. O encantamento acima também fornece a todos os committers classificados por linhas, em vez de apenas um de cada vez. Você pode adicionar algumas opções para culpar git (-C -M) para obter números melhores que consideram a movimentação de arquivos e a linha entre arquivos, mas o comando pode demorar muito mais se você o fizer.

Além disso, se você estiver procurando linhas alteradas em todas as confirmações para todos os confirmadores, o pequeno script a seguir é útil:

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


31
Eu estava prestes a dar um +1, mas então percebi que a solução depende do ruby ​​... :(
mac

3
Você pode modificá-lo para não usar ruby ​​com muita facilidade, já que eu apenas uso ruby ​​para a substituição de cadeias. Você pode usar perl, sed, python, etc
mmrobins

21
não funciona para mim: -e: 1: em `<main> ': sequência de bytes inválida em UTF-8 (ArgumentError)
Michał Dębski

1
/^.*\((.*?)\s[\d]{4}/deve ser /^.*?\((.*?)\s[\d]{4}/para evitar parênteses correspondentes na fonte como autor.
Timothy Gu

1
mmm minhas execuções mostraram muitos usuários que nem existem, devido à má análise. Eu acho que não é uma resposta confiável.
mjsr

92

Para contar o número de confirmações de um determinado autor (ou todos os autores) em um determinado ramo, você pode usar o git-shortlog ; veja especialmente its --numberede --summaryoptions, por exemplo, quando executado no repositório 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
Observe que v1.6.4está aqui neste exemplo para tornar a saída determinística: será o mesmo, não importa quando você clonou e / ou buscou no repositório git.
Jakub Narębski

inclusive v1.6.4me dá:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Vlad the Impala

5
Ah, não, eu perdi "quando executado no repositório git". Para ser justo, a maioria das pessoas não executa esse comando no repositório git. Por uma margem bastante grande, na verdade.
Vlad the Impala

4
git shortlog -sneou, se você preferir não incluir mesclagensgit shortlog -sne --no-merges
Mark Swardstrom 11/11/2013

1
@Swards: -sé --summary, -né --numberede [novo] -eé --emailpara mostrar emails de autores (e contar separadamente o mesmo autor com endereço de email diferente, levando em consideração as .mailmapcorreções). Boa ligação --no-merges.
Jakub Narębski

75

Depois de olhar para a resposta de Alex e Gerty3000 , tentei encurtar a frase :

Basicamente, usando o git log numstat e não mantendo o controle do número de arquivos alterados.

Git versão 2.1.0 no 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

Exemplo:

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

Não pode fazer um apelido para ele :-(
pirralho

33

A resposta do AaronM usando o one-liner do shell é boa, mas, na verdade, existe outro bug, em que os espaços corrompem os nomes de usuário se houver quantidades diferentes de espaços em branco entre o nome do usuário e a data. Os nomes de usuário corrompidos fornecerão várias linhas para a contagem de usuários e você deverá resumir você mesmo.

Essa pequena alteração corrigiu o problema para mim:

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 os + após \ s que consumirão todos os espaços em branco do nome até a data.

Na verdade, adicionar esta resposta tanto para minha lembrança quanto para ajudar outras pessoas, já que esta é pelo menos a segunda vez que pesquiso no assunto :)

  • Editar 2019-01-23 Adicionado --show-emailpara git blame -wagregar no email, pois algumas pessoas usam Nameformatos diferentes em computadores diferentes e, às vezes, duas pessoas com o mesmo nome estão trabalhando no mesmo git.

Esta resposta usando perl pareceu se sair um pouco melhor que as baseadas em ruby. Ruby engasgou com linhas que não eram texto UTF-8 real, o perl não reclamou. Mas perl fez a coisa certa? Eu não sei.
Stéphane Gourichon 18/03/16

Os submódulos resultam em, unsupported file typemas, caso contrário, parece funcionar bem mesmo com eles (os ignora).
Vladimír Čunát

24

Aqui está uma pequena lista que produz estatísticas para todos os autores. É muito mais rápido que a solução de Dan acima em https://stackoverflow.com/a/20414465/1102119 (a mina possui complexidade de tempo O (N) em vez de O (NM) onde N é o número de confirmações e M o 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

4
Bom, mas o que significa a saída?
Gary Willoughby

Você deve adicionar --no-show-signature, caso contrário, as pessoas que assinam pgp seus commits não serão contadas.
Philihp Busby

2
ins [a] - del [a], ins [a], del [a], a, por isso, se eu estiver certo inserção-exclusão, inserção, exclusão, nome #
MrKekson

Como posso adicionar este comando à minha configuração do git para que eu possa chamá-lo com "linhas de contagem do git"?
takanuva15

Nunca mente, eu percebi isso: 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". (Note que eu estou no Windows, você pode precisar usar diferentes tipos de citações)
takanuva15

21

O @mmrobins @AaronM @ErikZ O @JamesMishra forneceu variantes que todos têm um problema em comum: pedem ao git que produza uma mistura de informações não destinadas ao consumo de scripts, incluindo conteúdo de linha do repositório na mesma linha e, em seguida, combine a bagunça com um regexp .

Esse é um problema quando algumas linhas não são válidas para texto UTF-8 e também quando algumas linhas coincidem com o regexp (isso aconteceu aqui).

Aqui está uma linha modificada que não apresenta esses problemas. Ele solicita ao git que produza dados de maneira limpa em linhas separadas, o que facilita a filtragem do que queremos de maneira robusta:

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

Você pode grep para outras strings, como autor-mail, committer, etc.

Talvez o primeiro faça export LC_ALL=C(supondo bash) forçar o processamento no nível de bytes (isso também acelera tremendamente o grep a partir das localidades baseadas em UTF-8).


É uma frase legal, muito legal, que você pode facilmente misturar, mas isso não faz o que o pôster original solicitou, fornece uma contagem por autor do git. Claro que você pode executá-lo e fazer um wc-l, etc, mas precisará repetir para cada autor no repositório.
AaronM 8/16

1
@AaronM Eu não entendo suas críticas. Esta linha AFAIK produz as mesmas estatísticas que a sua, apenas mais robustas. Portanto, se minha resposta "falhar em fazer o que o pôster original solicitou, forneça uma contagem por autor do git", então a sua ainda mais. Por favor me esclareça.
Stéphane Gourichon

desculpe por ter lido errado, pensei que o comando tivesse que ser modificado para cada nome de autor diferente. Seu comentário sobre grep para outras strings me levou até lá, mas foi meu mal-entendido.
AaronM

Isso é tão incrível. Obrigado!
Tek

16

Uma solução foi fornecida com o ruby ​​no meio, sendo o perl um pouco mais disponível por padrão aqui é uma alternativa usando o perl para linhas atuais 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

5
O regex atualizado não faz uma diferença significativa e está quebrado porque você não escapou do primeiro parêntese. No entanto, posso ver alguns casos em que o anterior pode encontrar alguns bits na linha de código nos quais se prender. Isso funcionaria de maneira mais confiável: git ls-files -z | xargs -0n1 culpa do git -w | perl -n -e '/^.*?\((.*?)\s[\d}{4}/; imprime $ 1, "\ n"' | sort -f | uniq -c | sort -n
AaronM

obrigado por tentar criar uma regexp mais confiável. Veja a minha resposta para uma variante mais robusta stackoverflow.com/a/36090245/1429390
Stéphane Gourichon

13

Além da resposta de Charles Bailey , você pode adicionar o -Cparâmetro aos comandos. Caso contrário, as renomeações de arquivos contam como muitas adições e remoções (tantas quanto o arquivo tiver linhas), mesmo que o conteúdo do arquivo não tenha sido modificado.

Para ilustrar, aqui está um commit com muitos arquivos sendo movidos de um dos meus projetos, ao usar o git log --oneline --shortstatcomando:

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

E aqui o mesmo commit usando o git log --oneline --shortstat -Ccomando que detecta cópias de arquivos e renomeia:

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

Na minha opinião, o último fornece uma visão mais realista do impacto que uma pessoa teve no projeto, porque renomear um arquivo é uma operação muito menor do que gravá-lo do zero.


2
Quando executo "git log --oneline --shortstat", não obtenho seu resultado. Eu tenho uma lista de confirmação com o número de edições, mas não o número total. Como posso obter o número total de linhas editadas em todo o repositório git?
Mehdi

12

você pode usar o 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

ou apenas digite

$ whodid

então você pode ver resultados como este

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

O que significa 'score'?
user11171

@Volte NPM i é apenas um atalho para npm instalar
Michiel

Sim, eu estou ciente. Eu -gtive que vir antes do nome do pacote macOS. Simplesmente tentando ajudar.
Volte

11

Aqui está um script ruby ​​rápido que aumenta o impacto por usuário em relação a uma determinada consulta de log.

Por exemplo, para rubinius :

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

o script:

#!/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
Esse script é ótimo, mas exclui autores que possuem apenas confirmações de linha única! Para corrigir, altere da seguinte maneira: alterações = / (\ d +) inserção. * (\ D +) exclusão / .match (linha)
Larry Gritz

9

esta é a melhor maneira e também fornece uma imagem clara do número total de confirmações por todos os usuários

git shortlog -s -n

2
Útil, mas que do número de não commits linhas de código totais
Diolor

5

Forneci uma modificação de uma resposta curta acima, mas ela não foi suficiente para minhas necessidades. Eu precisava ser capaz de categorizar linhas confirmadas e linhas no código final. Eu também queria uma divisão por arquivo. Esse código não é recorrente, retornará apenas os resultados para um único diretório, mas é um bom começo se alguém quiser ir além. Copie e cole em um arquivo e torne o executável ou execute-o com 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};
}

Estou recebendo este erro: Divisão ilegal por zero na linha x.pl 71.
Vivek Jha

Dirigiu-se à divisão ilegal por zero na linha 71. Acho que ocorre se não houver edições, mas foi há um tempo atrás que escrevi isso.
AaronM 28/09

2

Para usuários do Windows, você pode usar o seguinte script em lote que conta linhas adicionadas / removidas para o 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


2

Aqui está um ótimo repositório que facilita sua vida

git-quick-stats

Em um mac com o brew instalado

brew install git-quick-stats

Corre

git-quick-stats

Basta escolher a opção desejada nesta lista, digitando o número listado e pressionando 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)


1

Este script aqui fará isso. Coloque-o em authorship.sh, chmod + x it, e está tudo 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
você NÃO publicou isso em outro lugar, ele gera erros em macs e linux, você sabe, o tipo de computador em que o git foi criado!
Pizzaiola Gorgonzola 28/09/2013

1

Salve seus logs no arquivo usando:

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

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

Suas saídas seriam como:

225        files changed
6751       insertions
1379       deletions

0

Você quer culpa do Git .

Existe uma opção --show-stats para imprimir algumas estatísticas.


Eu tentei blame, mas realmente não deu as estatísticas que eu pensei que o OP precisaria?
CB Bailey

Obrigado, isso também me ajudou com .mailmap também!
Gav

0

A pergunta pedia informações sobre um autor específico , mas muitas das respostas eram soluções que retornavam listas classificadas de autores com base em suas linhas de código alteradas.

Era isso que eu estava procurando, mas as soluções existentes não eram perfeitas. No interesse das pessoas que podem encontrar essa pergunta pelo Google, eu fiz algumas melhorias e as transformei em um shell script, que mostro abaixo. Uma anotada (que continuarei mantendo) pode ser encontrada no meu Github .

Não dependências no Perl ou no Ruby. Além disso, espaços em branco, renomeações e movimentos de linha são levados em consideração na contagem de alterações de linha. Basta colocar isso em um arquivo e passar seu repositório Git como o primeiro 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


0

Eu escrevi esse script Perl para realizar essa tarefa.

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

Eu o nomeei git-line-changes-by-authore coloquei /usr/local/bin. Como ele está salvo no meu caminho, posso emitir o comando git line-changes-by-author --before 2018-12-31 --after 2020-01-01para obter o relatório para o ano de 2019. Como um exemplo. E se eu escrever incorretamente, o nome git sugerirá a grafia correta.

Convém ajustar o _get_repo_slugsub para incluir apenas a última parte do remote.origin.urlarquivo, pois meus repositórios são salvos project/repoe o seu pode não ser.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.