Git deposunda belirli bir yazar tarafından değiştirilen toplam satırları nasıl sayabilirim?


458

Bir Git deposunda belirli bir yazar tarafından değiştirilen satırları sayacak olan çağırabileceğim bir komut var mı? Github'un Etki grafiği için bunu yaptığı gibi taahhütlerin sayısını saymanın yolları olduğunu biliyorum.


1
Linux çekirdek gelişimi için istatistik toplayan ünlü bir araç düşünebilirsiniz, örneğin, Depo burada git://git.lwn.net/gitdm.git.
0andriy

Yanıtlar:


310

Toplamları toplamak için aşağıdaki komutun çıktısının komut dosyasına gönderilmesi oldukça kolay olmalıdır:

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

Bu, geçerli HEAD'deki tüm taahhütlerin istatistiklerini verir. Diğer branşlara istatistik eklemek istiyorsanız, bunları bağımsız değişken olarak sağlamanız gerekir git log.

Bir betiğe geçmek için, "oneline" biçimini bile kaldırmak boş bir günlük biçimiyle yapılabilir ve Jakub Narębski tarafından yorumlandığı gibi --numstatbaşka bir alternatiftir. Satır başına istatistiklerden ziyade dosya başına oluşturur, ancak ayrıştırılması daha da kolaydır.

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

14
İstatistikleri biraz daha kolay eklemek istiyorsanız --numstatyerine kullanabilirsiniz --shortstat.
Jakub Narębski

Farkı bulabilirsiniz @Huey burada sen tformat için ama temelde onun tam aynı ancak her bir satır sonunda tformat koyar bir sonlandırıcı karakter (genellikle bir satır) ararsanız
aug

8
Orada da "--no-merges" eklemek isteyebilir.
yoyo

9
bu sorular için özür dilerim, ama rakamlar bana ne anlatıyor? İki sıra var ve bana ne söylediklerini bilmiyorum. Satırlar chenged ve eklendi?
Informatic0re

2
@ Informatic0re git help logbana birincisinin satır eklendiğini, ikinci satırların silindiğini söyledi.
ThomasH

600

Bu, yazar hakkında bazı istatistikler verir, gerektiği gibi değiştirin.

Gawk kullanma:

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

Mac OSX'te Awk kullanma:

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

DÜZENLE (2017)

Github'da kaygan görünen ve bağımlılık olarak bash kullanan yeni bir paket var (linux üzerinde test edildi). Komut dosyalarından ziyade doğrudan kullanım için daha uygundur.

It adlı git-hızlı-istatistik (github bağlantı) .

Kopya git-quick-statsbir klasöre ve yoluna klasör eklemek.

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

Kullanımı:

git-quick-stats

resim açıklamasını buraya girin


18
Bu güzel uzun astar için teşekkürler! Bu garip nokta herkesin güvertesini temizledi (doğru, hızlı, ekstra garip çıktı yok). Şaşırtıcı değil, bu awk için tasarlanmış bir şey olduğunu düşünüyor ... Çok kötü partiye çok geç kaldın.
zxq9

4
@ zxq9: Soru sorulduğunda stackoverflow'da bile değildim ve buradaki cevaplardan ilham aldım. umarım insanlar yavaş yavaş buna ihtiyaç duyarlar.
Alex

9
Bu harika çalışıyor, ancak ben değiştirmek zorunda gawkiçin awko OSX terminalde çalışması için
Zach Lysobey

1
@samthebest, çünkü dosya taşıma uygun istatistikleri yansıtmıyor. Çizgiler değişmez. Alex'e: Git'ten bahsediyorum. Btw, orijinal soru hakkındaki yorumuma bakın.
0andriy

2
URL sizin için çalışmazsa, şunu deneyin:git clone https://github.com/arzzen/git-quick-stats.git
Nicolas

226

Herkesin kod tabanındaki her kullanıcının istatistiklerini görmek istemesi durumunda, birkaç iş arkadaşım kısa bir süre önce bu korkunç tek astarla geldi:

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

(Yaklaşık 10-15 bin komisyonu olan repolarımızla uğraşmak birkaç dakika sürüyor.)


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

1
@EugenKonkov kod olarak ekleme - silme olarak tanımlanır.
Dan

13
depo için toplam sonuç veren ve herhangi bir eklenti olmadan çalışan tek komut budur.
Ömer Faruk Almalı

1
Bir grup kullanıcıyı bir araya getiriyorum, neredeyse her olası geliştirici kombinasyonu geri geliyor. ucumdaki gariplik?
Damon

2
@BenSewards Eğer Linux, Windows Subsystem kullanarak Windows üzerinde daha fazla bilgi Bash kullanabilirsiniz burada
mjsr

152

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

taahhüt ve değiştirilmiş dosya sayısı da dahil olmak üzere tüm yazarların sayısını bir kerede almak için güzel bir araçtır:

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

Https://github.com/casperdcl/git-fame adresinde (@fracz tarafından belirtilen) Python sürümü de vardır :

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

Örnek çıktı:

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

Ancak uyarılmalıdır: yorumda Jared tarafından belirtildiği gibi, çok büyük bir depoda yapılması saatler alacaktır. Git verilerini çok fazla işlemesi gerektiğini düşünerek bunun geliştirilip geliştirilemeyeceğinden emin değilim.


1
Bu harika ama çok yavaş
Jared Burrows

1
2015 ortalarında macbook ve orta büyük Android projesinde iyi çalıştı (127k LoC 'is). Birkaç dakika.
maxweber

2
@ Mevcut kullanıcı için toal loc / commits / dosyalarının yüzde yüzde'si.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

1
Şube, zaman aşımı ve klasörü hariç tutma:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer

1
@AlexanderMills Sanırım çünkü lekelerdeki satırları anlamlı bir şekilde
sayamazsınız

103

Ben şu anda kod üssünde kim en çok satır görmek için yararlı buldum:

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

Diğer cevaplar çoğunlukla taahhütlerde değişen satırlara odaklanmıştır, ancak taahhütler hayatta kalmaz ve üzerine yazılırsa, sadece çalkalanmış olabilir. Yukarıdaki büyütme ayrıca tüm komisyoncuları teker teker değil, satırlara göre sıralar. Dosyalar arasında dosya hareketini ve satır hareketini dikkate alan daha iyi sayılar elde etmek için git blame (-C -M) öğesine bazı seçenekler ekleyebilirsiniz, ancak bunu yaparsanız komut çok daha uzun sürebilir.

Ayrıca, tüm komisyoncular için tüm taahhütlerde değiştirilen satırlar arıyorsanız, aşağıdaki küçük komut dosyası yararlıdır:

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


31
+1 vermek üzereydim, ama sonra çözümün yakuttan geldiğini fark ettim ... :(
mac

3
Ben sadece dize değiştirme için sadece ruby ​​kullandığım için yakut kullanmak için kolayca değiştirebilirsiniz. Perl, sed, python, vb.
Kullanabilirsiniz

21
benim için çalışmıyor: -e: 1: `` <main> '': UTF-8'de geçersiz bayt dizisi (ArgumentError)
Michał Dębski

1
/^.*\((.*?)\s[\d]{4}//^.*?\((.*?)\s[\d]{4}/kaynak olarak parantezin yazar olarak eşleşmesini önlemek olmalıdır .
Timothy Gu

1
mmm infazlarım kötü ayrıştırma nedeniyle var olmayan birçok kullanıcı gösterdi. Bence bu güvenilir bir cevap değil.
mjsr

92

Belirli bir daldaki belirli bir yazarın (veya tüm yazarların) taahhüt sayısını saymak için git-shortlog'u kullanabilirsiniz ; özellikle onun --numberedve --summaryseçeneklerine bakın, örneğin git deposunda çalıştırıldığında:

$ 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
v1.6.4Bu örnekte çıktıyı deterministik yapmak için burada olduğuna dikkat edin: git deposundan ne zaman klonladıysanız ve / veya aldığınız önemli değil.
Jakub Narębski

dahil v1.6.4bana verir:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Vlad the Impala

5
Ah, hayır, "git deposunda çalıştırıldığında" özledim. Adil olmak gerekirse, çoğu insan alışkanlık git repo bu komutunu çalıştırın. Aslında oldukça büyük bir farkla.
Vlad the Impala

4
git shortlog -sneveya birleştirme eklemek istemiyorsanızgit shortlog -sne --no-merges
Mark Swardstrom

1
@Swards: -sise --summary, -nolduğu --numberedve [yeni] -eolduğu --email(hesap içine alarak, ayrı ayrı farklı e-posta adresi ile aynı yazar saymak yazarların e-postaları göstermek için .mailmapdüzeltmeler). Hakkında iyi bir çağrı --no-merges.
Jakub Narębski

75

Alex ve Gerty3000'in cevabına baktıktan sonra , tek astarı kısaltmaya çalıştım:

Temelde, git günlüğü numstat kullanarak ve değil sayısının takip dosyaları değişti.

Mac OSX'te Git sürüm 2.1.0:

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

Misal:

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

Cant bir takma ad yapmak :-(
velet

33

Cevap den AaronM kabuk havasında kullanarak iyidir, ama aslında, bir başka hata olduğu yerde boşluk olacak bozuk kullanıcı adı ve tarihi arasındaki boşluklardan farklı miktarlarda varsa kullanıcı adları. Bozuk kullanıcı adları, kullanıcı sayıları için birden çok satır verir ve bunları kendiniz toplamanız gerekir.

Bu küçük değişiklik benim için sorunu düzeltti:

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

Addan tarihe kadar tüm boşlukları tüketecek + after \ s öğesine dikkat edin.

Aslında bu yanıtı başkalarına yardım etmem kadar kendi hatırlamam için ekliyorum, çünkü bu en azından konuyu Google'a ikinci kez taktığımda :)

  • Düzenleme 2019/01/23 eklendi --show-emailiçin git blame -wbazı insanlar farklı kullandıkları için, bunun yerine e-postayı toplamak için Namefarklı bilgisayarlarda biçimleri ve aynı adla bazen iki kişi aynı GIT'de çalışıyoruz.

Perl kullanan bu cevabın yakut bazlı olanlardan biraz daha iyi olduğu ortaya çıktı. Ruby gerçek UTF-8 metni olmayan satırlarda boğuldu, perl şikayet etmedi. Peki perl doğru olanı yaptı mı? Bilmiyorum.
Stéphane Gourichon

Submodüller ortaya çıkar, unsupported file typeancak aksi takdirde onlarla bile iyi çalışır gibi görünüyor (onları atlıyor).
Vladimír Čunát

24

İşte tüm yazarlar için istatistik üreten kısa bir satırlık. Dan'ın https://stackoverflow.com/a/20414465/1102119 adresindeki yukarıdaki çözümünden çok daha hızlı (benim N'nin taahhüt sayısı olduğu O (NM) yerine O (N) zaman karmaşıklığı ve M yazar sayısı ).

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
Güzel ama çıktı ne anlama geliyor?
Gary Willoughby

Sen eklemek gerekir --no-show-signatureaksi takdirde kaydedilmesini pgp-imzalamak insanlar sayılır almak için gidiş değildir.
Philihp Busby

2
ins [a] - del [a], ins [a], del [a], a, öyleyse sağ ekleme-silme, ekleme, silme, ad
MrKekson 15:01 '

Bu komutu git git komutuma nasıl ekleyebilirim ki "git count-lines" ile çağırabilirim?
takanuva15

Aldırma, ben bunu anladım: 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". (Not Windows'dayım; farklı türde alıntılar kullanmanız gerekebilir)
takanuva15

21

@mmrobins @AaronM @ErikZ @JamesMishra, hepsinin ortak bir sorunu olan varyantlar sağladı: git'ten, aynı satırdaki depodan satır içeriği de dahil olmak üzere komut dosyası tüketimi için tasarlanmamış bir bilgi karışımı üretmesini ve ardından karışıklığı bir regexp ile eşleştirmelerini istiyorlar. .

Bu, bazı satırlar geçerli UTF-8 metni olmadığında ve bazı satırlar normal ifadeyle eşleştiğinde (bu burada oldu) bir sorundur.

İşte bu sorunları olmayan değiştirilmiş bir satır. Git'in ayrı satırlarda temiz bir şekilde çıktı vermesini ister, bu da istediğimizi sağlam bir şekilde filtrelemeyi kolaylaştırır:

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

Yazar-posta, iletici, vb. Diğer dizeler için grep yapabilirsiniz.

Belki de ilk olarak bayt seviyesi işlemeyi zorlamak export LC_ALL=C(varsayalım bash) (bu aynı zamanda UTF-8 tabanlı yerel ayarlardan büyük ölçüde grep'i hızlandırmak için de geçerlidir).


Güzel çizgi, çok serin, kolayca karıştırabilirsiniz, ancak bu orijinal posterin talep ettiği şeyi yapamaz, git yazarından bir sayı sağlar. Elbette çalıştırabilir ve wc-l vb. Yapabilirsin, ancak daha sonra depodaki her yazar için tekrarlamanız gerekir.
AaronM

1
@AaronM Eleştirmeni anlamıyorum. Bu satır AFAIK, sizinkiyle aynı istatistikleri çıkarır, yalnızca daha sağlamdır. Yani, cevabım "asıl posterin talep ettiği şeyi yapamazsa, git'ten yazar tarafından bir sayım sağlayın", o zaman sizinkinden daha fazlası. Lütfen beni aydınlat.
Stéphane Gourichon

üzgünüm yanlış okudum, komutun her farklı yazar adı için değiştirilmesi gerektiğini düşündüm. Diğer dizeler için grep hakkındaki yorumunuz beni oraya götürdü ama bu benim yanlış anlama oldu.
AaronM

Bu çok harika. Teşekkürler!
Tek

16

Ortada yakut ile bir çözüm verildi, burada perl varsayılan olarak biraz daha kullanılabilir, mevcut satırlar için yazar tarafından perl kullanan bir alternatif.

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
Güncellenmiş normal ifade anlamlı bir fark yaratmaz ve ilk parenden kaçmadığınız için bozulur. Ancak, önceki durumumun üzerine kilitlenecek kod satırında bazı bitler bulabileceği bazı durumlar görebilirsiniz. Bu daha güvenilir bir şekilde çalışır: git ls-files -z | xargs -0n1 git suçlama -w | perl -n -e '/^.*?\
AaronM

daha güvenilir bir normal ifade yapmaya çalıştığınız için teşekkür ederiz. Daha sağlam bir değişken için cevabımı görün stackoverflow.com/a/36090245/1429390
Stéphane Gourichon

13

Charles Bailey'nin cevabına ek olarak , -Cparametreyi komutlara eklemek isteyebilirsiniz . Aksi takdirde, dosya içeriği değiştirilmemiş olsa bile, dosya adları çok fazla ekleme ve kaldırma (dosyada satır olduğu kadar) sayılır.

Örnek olarak, komutu kullanırken, projelerimden birinden çok sayıda dosyanın taşınmasıyla ilgili bir taahhütgit log --oneline --shortstat :

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

Ve burada aynı taahhüt, git log --oneline --shortstat -Cdosya kopyalarını ve yeniden adlarını tespit eden komutu kullanarak :

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

Kanımca ikincisi, bir kişinin proje üzerinde ne kadar etkisi olduğuna dair daha gerçekçi bir görünüm verir, çünkü bir dosyayı yeniden adlandırmak dosyayı sıfırdan yazmaktan çok daha küçük bir işlemdir.


2
"Git log --oneline --shortstat" komutunu çalıştırdığımda sonucunuzu elde edemiyorum. Sürüm sayısı ile bir taahhüt listem var, ancak toplam sayı değil. Tüm git deposunda düzenlenen toplam satır sayısını nasıl alabilirim?
Mehdi

12

whodid kullanabilirsiniz ( https://www.npmjs.com/package/whodid )

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

ve

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

veya sadece yazın

$ whodid

o zaman sonucu böyle görebilirsiniz

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

'Puan' ne demektir?
user11171

@Nolte npm i npm kurulumu için sadece bir kısayoldur
Michiel

Evet, farkındayım. Benim -gpaket adından önce gelmek zorundaydım macOS. Sadece yardım etmeye çalışıyorum.
Volte

11

Aşağıda, belirli bir günlük sorgusuna karşı kullanıcı başına etkiyi artıran hızlı bir yakut komut dosyası verilmiştir.

Örneğin, rubinius için :

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

senaryo:

#!/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
Bu senaryo harika, ancak sadece tek satır taahhütleri olan yazarları hariç tutuyor! Düzeltmek için aşağıdaki şekilde değiştirin: change = / (\ d +) ekleme. * (\ D +) silme / .match (satır)
Larry Gritz

9

bu en iyi yoldur ve ayrıca tüm kullanıcı tarafından yapılan toplam taahhüt sayısının net bir resmini verir.

git shortlog -s -n

2
Yararlı, ancak toplam kod satırı değil taahhüt sayısı
Diolor

5

Yukarıda kısa bir cevapta bir değişiklik sağladım, ancak ihtiyaçlarım için yeterli değildi. Son koddaki hem taahhütlü satırları hem de satırları kategorize edebilmem gerekiyordu. Ayrıca dosyaya göre bir döküm istedim. Bu kod geri çekilmez, yalnızca tek bir dizin için sonuçları döndürür, ancak birileri daha ileri gitmek isterse iyi bir başlangıçtır. Bir dosyaya kopyalayıp yapıştırın ve yürütülebilir yapın veya Perl ile çalıştırın.

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

Bu hatayı alıyorum: x.pl satır 71'de sıfıra göre yasadışı bölünme.
Vivek Jha

71 numaralı satırdaki yasadışı bölünme sorunu giderildi. Düzenleme yoksa, ancak bir süre önce bunu yazdım.
AaronM

2

Windows kullanıcıları için, belirtilen yazar için eklenen / kaldırılan satırları sayan aşağıdaki toplu komut dosyasını kullanabilirsiniz

@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

İşte hayatınızı kolaylaştıran harika bir repo

git-quick-stats

Demleme yüklü bir mac'ta

brew install git-quick-stats

Çalıştırmak

git-quick-stats

Listelenen numarayı yazıp enter tuşuna basarak bu listeden istediğiniz seçeneği seçin.

 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

Buradaki komut dosyası bunu yapacak. Bunu authorship'e koyun. Sh, chmod + x ve hepsi hazır.

#!/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
hayır o WONT!, başka bir yere bu yayınlanmıştır, macs ve linux hataları üretir, bilirsiniz, git tür bilgisayarların yapıldı!
Pizzaiola Gorgonzola

1

Günlüklerinizi aşağıdakileri kullanarak dosyaya kaydedin:

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

Python sevenler için:

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

Çıktılarınız şöyle olacaktır:

225        files changed
6751       insertions
1379       deletions

0

İstiyorsun Git suçu .

Bazı, iyi istatistikleri yazdırmak için --show-stats seçeneği vardır.


Denedim blame, ama OP'nin ihtiyaç duyacağını düşündüğüm istatistikleri gerçekten vermedi mi?
CB Bailey

Teşekkürler, bu da .mailmap ile bana yardımcı oldu!
Gav

0

Soru , belirli bir yazar hakkında bilgi istedi , ancak cevapların çoğu, kod satırlarına göre sıralanmış yazar listelerini döndüren çözümlerdi.

Aradığım şey buydu, ancak mevcut çözümler tam olarak mükemmel değildi. Bu soruyu Google aracılığıyla bulabilecek kişilerin yararına, bunlarda bazı iyileştirmeler yaptım ve aşağıda görüntülediğim bir kabuk komut dosyasına dönüştürdüm. Ek açıklamalı olanı (korumaya devam edeceğim) Github'ımda bulunabilir .

Orada hiçbir Perl veya Ruby ya bağımlılıklan. Ayrıca satır değiştirme sayısında boşluk, yeniden adlandırma ve satır hareketleri dikkate alınır. Bunu bir dosyaya koyun ve Git deponuzu ilk parametre olarak iletin.

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

Bu görevi yerine getirmek için bu Perl betiğini yazdım.

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

Adını verdim git-line-changes-by-authorve içine koydum /usr/local/bin. Yoluma kaydedildiği git line-changes-by-author --before 2018-12-31 --after 2020-01-01için, 2019 yılı için raporu alma komutunu verebilirim. Örnek olarak. Ve ben yanlış yazacak olsaydı git adı doğru yazım önerecektir.

Depolarım olarak kaydedildiği ve olmayabileceği için _get_repo_slugalt öğeyi yalnızca son bölümünü içerecek şekilde ayarlamak isteyebilirsiniz.remote.origin.urlproject/repo

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.