Statistik Komit Git Blame

198

Bagaimana saya bisa "menyalahgunakan" menyalahkan (atau fungsi yang lebih cocok, dan / atau dalam hubungannya dengan perintah shell) untuk memberi saya statistik tentang berapa banyak baris (kode) saat ini dalam repositori yang berasal dari masing-masing committer?

Contoh Output:

Committer 1: 8046 Lines
Committer 2: 4378 Lines
Erik Aigner
sumber
11
Harus ada perintah bawaan untuk itu ... ada perintah untuk kasus penggunaan yang kurang umum.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
@CiroSantilli tetapi mudah untuk menambahkan shellscript yang tidak dapat diubah dari git.
Alex
kemungkinan duplikat dari Bagaimana cara menghitung total baris yang diubah oleh penulis tertentu dalam repositori Git? karena dapat dengan mudah direduksi menjadi yang itu: hanya melingkari semua penulis
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
1
ini cukup code.google.com/p/gitinspector, terutama jika Anda menilai tugas oleh tim siswa (proyek besar tidak perlu diterapkan ... lambat karena menyalahkan setiap file individu)
lihat

Jawaban:

166

Memperbarui

git ls-tree -r -z --name-only HEAD -- */*.c | xargs -0 -n1 git blame \
--line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

Saya memperbarui beberapa hal dalam perjalanan.

Untuk kenyamanan, Anda juga bisa memasukkan ini ke dalam perintahnya sendiri:

#!/bin/bash

# save as i.e.: git-authors and set the executable flag
git ls-tree -r -z --name-only HEAD -- $1 | xargs -0 -n1 git blame \
 --line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

simpan ini di suatu tempat di jalur Anda atau ubah jalur Anda dan gunakan seperti itu

  • git authors '*/*.c' # look for all files recursively ending in .c
  • git authors '*/*.[ch]' # look for all files recursively ending in .c or .h
  • git authors 'Makefile' # just count lines of authors in the Makefile

Jawaban Asli

Sementara jawaban yang diterima melakukan pekerjaan itu sangat lambat.

$ git ls-tree --name-only -z -r HEAD|egrep -z -Z -E '\.(cc|h|cpp|hpp|c|txt)$' \
  |xargs -0 -n1 git blame --line-porcelain|grep "^author "|sort|uniq -c|sort -nr

hampir seketika.

Untuk mendapatkan daftar file yang saat ini dilacak dapat Anda gunakan

git ls-tree --name-only -r HEAD

Solusi ini menghindari panggilan fileuntuk menentukan tipe file dan menggunakan grep untuk mencocokkan ekstensi yang diinginkan untuk alasan kinerja. Jika semua file harus disertakan, cukup hapus ini dari baris.

grep -E '\.(cc|h|cpp|hpp|c)$' # for C/C++ files
grep -E '\.py$'               # for Python files

jika file dapat berisi spasi, yang buruk untuk shell, Anda dapat menggunakan:

git ls-tree -z --name-only -r HEAD | egrep -Z -z '\.py'|xargs -0 ... # passes newlines as '\0'

Berikan daftar file (melalui pipa) yang dapat digunakan xargs untuk memanggil perintah dan mendistribusikan argumen. Perintah yang memungkinkan banyak file diproses diproses oleh -n1. Dalam hal ini kami memanggil git blame --line-porcelaindan untuk setiap panggilan kami menggunakan tepat 1 argumen.

xargs -n1 git blame --line-porcelain

Kami kemudian memfilter output untuk kejadian "penulis" mengurutkan daftar dan menghitung garis duplikat dengan:

grep "^author "|sort|uniq -c|sort -nr

Catatan

Jawaban lain sebenarnya menyaring garis yang hanya berisi spasi putih.

grep -Pzo "author [^\n]*\n([^\n]*\n){10}[\w]*[^\w]"|grep "author "

Perintah di atas akan mencetak penulis baris yang mengandung setidaknya satu karakter non-spasi putih. Anda juga dapat menggunakan kecocokan \w*[^\w#]yang juga akan mengecualikan baris di mana karakter non-spasi pertama bukan merupakan #(komentar dalam banyak bahasa scripting).

Alex
sumber
2
@nilbus: Anda tidak bisa. echo "a\nb\nc"|xargs -n1 cmdakan diperluas kecmd a; cmd b; cmd d
Alex
2
--line-porselen sepertinya tidak berfungsi lagi (git 1.7.5.4) sebagai gantinya gunakan --porcelain
isoiphone
4
Pengguna OSX, coba yang berikut ini (masih tidak berfungsi pada file dengan baris baru atas nama mereka):git ls-tree --name-only -r HEAD | grep -E '\.(cc|h|m|hpp|c)$' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr
Wayne
3
Jika Anda hanya ingin semuanya di bawah jalur saat ini, ke kedalaman apa pun, gunakan "./" sebagai filter jalur (tempat penjawab meletakkan " / .c").
Ben Dilts
2
Mungkin menggunakan "salahkan-w" untuk mendapatkan kepemilikan kode yang lebih baik ketika kode hanya diformat ulang stackoverflow.com/questions/4112410/...
sleeplessnerd
124

Saya menulis permata bernama git-fame yang mungkin berguna.

Instalasi dan penggunaan:

  1. $ gem install git_fame
  2. $ cd /path/to/gitdir
  3. $ git fame

Keluaran:

Statistics based on master
Active files: 21
Active lines: 967
Total commits: 109

Note: Files matching MIME type image, binary has been ignored

+----------------+-----+---------+-------+---------------------+
| name           | loc | commits | files | distribution (%)    |
+----------------+-----+---------+-------+---------------------+
| Linus Oleander | 914 | 106     | 21    | 94.5 / 97.2 / 100.0 |
| f1yegor        | 47  | 2       | 7     |  4.9 /  1.8 / 33.3  |
| David Selassie | 6   | 1       | 2     |  0.6 /  0.9 /  9.5  |
+----------------+-----+---------+-------+---------------------+
Linus Oleander
sumber
5
+1 akhirnya 1 yang berfungsi dan terlihat seperti memberikan angka yang masuk akal, yang lain dari baris perintah tidak berfungsi pada OSX karena ketidaksesuaian utilitas atau memberikan angka kecil pada repo saya. Ini pada OSX dan ruby ​​1.9.3 (buatan)
Karthik T
9
Jangan konyol, @tcaswell. Bukan spam untuk menunjuk ke sesuatu yang bermanfaat, bahkan jika Anda adalah orang yang menulis sesuatu.
Wayne
5
Menjawab pertanyaan saya sendiri: git fame --exclude = paths / to / files, paths ke / other / files
Maciej Swic
2
@ Adam: Apakah Anda masih mengalami masalah dengan ini? Bekerja sangat baik untuk saya di OS X 10.9.5.
Sam Dutton
2
Untuk repo apa pun yang lebih besar dari beberapa melakukan saat permata ini perlu melakukan pekerjaannya adalah astronomi
Erik Aigner
48
git ls-tree -r HEAD|sed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c

Penjelasan langkah demi langkah:

Daftar semua file di bawah kontrol versi

git ls-tree -r HEAD|sed -re 's/^.{53}//'

Pangkas daftar hanya ke file teks

|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'

Git menyalahkan semua file teks, mengabaikan perubahan spasi putih

|while read filename; do git blame -w "$filename"; done

Tarik keluar nama penulis

|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'

Urutkan daftar penulis, dan minta uniq menghitung jumlah baris berulang secara berurutan

|sort|uniq -c

Contoh output:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda
nilbus
sumber
1
Sepertinya saya memiliki sedversi yang berbeda , milik saya tidak mengerti -rbendera dan memiliki masalah dengan regex (mengeluh tentang parens tidak seimbang, bahkan ketika saya menghapus kelebihannya ().
Erik Aigner
7
Nevermind, sudo brew install gnu-seddipecahkan itu. Bekerja seperti pesona!
Erik Aigner
5
Atau port install gseduntuk pengguna MacPorts.
Gavin Brock
Saya melakukan sudo brew install gnu-sed(yang berhasil) tetapi saya masih mendapatkan kesalahan yang tidak dikenali -r. :(
Adam Tuttle
1
Pada OSX setelah menginstal gsed melalui macports saya menjalankan perintah ini untuk membuatnya bekerja (diganti dengan gsed):git ls-tree -r HEAD|gsed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|gsed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|gsed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c
nerdherd
38

git summarydisediakan oleh paket git-ekstra adalah persis apa yang Anda butuhkan. Lihat dokumentasi di git-extras - ringkasan git :

git summary --line

Memberikan output yang terlihat seperti ini:

project  : TestProject
lines    : 13397
authors  :
8927 John Doe            66.6%
4447 Jane Smith          33.2%
  23 Not Committed Yet   0.2%
adius
sumber
1
Bagus, tetapi tampaknya tidak mendukung filter jalur, atau setidaknya argumen sub direktori. Akan lebih baik.
spinkus
1
Solusi yang bagus dan bersih. @ Jawaban Alex menghasilkan jumlah baris yang sangat kecil untuk beberapa alasan. Ini baru saja berhasil. Butuh waktu sekitar 30 detik untuk ~ 200 ribu baris yang tersebar di beberapa ratus file.
fgblomqvist
6

Solusi Erik luar biasa, tapi saya punya beberapa masalah dengan diakritik (meskipun LC_*variabel lingkungan saya diatur dengan benar) dan kebisingan bocor pada baris kode yang benar-benar memiliki tanggal di dalamnya. Sed-fu saya buruk, jadi saya berakhir dengan potongan frankenstein ini dengan ruby ​​di dalamnya, tetapi berhasil bagi saya tanpa cacat pada 200.000+ LOC, dan hasilnya seperti:

git ls-tree -r HEAD | gsed -re 's/^.{53}//' | \
while read filename; do file "$filename"; done | \
grep -E ': .*text' | gsed -r -e 's/: .*//' | \
while read filename; do git blame "$filename"; done | \
ruby -ne 'puts $1.strip if $_ =~ /^\w{8} \((.*?)\s*\d{4}-\d{2}-\d{2}/' | \
sort | uniq -c | sort -rg

Juga perhatikan gsedbukan sedkarena itu menginstal biner homebrew, meninggalkan sistem sed utuh.

gtd
sumber
4

git shortlog -sn

Ini akan menampilkan daftar commit per penulis.

moinudin
sumber
17
Ini mengembalikan jumlah komit per penulis, bukan jumlah baris.
v64
Sangat membantu dalam menentukan kontributor utama ke proyek / direktori / file
Ares
4

Berikut ini cuplikan utama dari jawaban @Alex yang sebenarnya melakukan operasi agregasi garis menyalahkan. Saya telah memotongnya untuk beroperasi pada satu file daripada satu set file.

git blame --line-porcelain path/to/file.txt | grep  "^author " | sort | uniq -c | sort -nr

Saya memposting ini di sini karena saya sering kembali ke jawaban ini dan membaca kembali postingan dan mencerna ulang contoh-contoh untuk mengekstraksi bagian yang saya hargai sangat membebani. Juga tidak cukup umum untuk kasus penggunaan saya; ruang lingkupnya adalah untuk keseluruhan proyek C.


Saya suka daftar statistik per file, dicapai melalui dengan bash foriterator bukan xargskarena saya menemukan xargs kurang mudah dibaca dan sulit digunakan / menghafal, Keuntungan / kerugian xargs vs untuk harus dibahas di tempat lain.

Berikut ini cuplikan praktis yang akan menampilkan hasil untuk setiap file secara individual:

for file in $(git ls-files); do \
    echo $file; \
    git blame --line-porcelain $file \
        | grep  "^author " | sort | uniq -c | sort -nr; \
    echo; \
done

Dan saya menguji, menjalankan stright ini dalam bash shell adalah ctrl + c aman, jika Anda harus meletakkan ini di dalam skrip bash Anda mungkin perlu Trap pada SIGINT dan SIGTERM jika Anda ingin pengguna dapat memecahkan loop Anda.

ThorSummoner
sumber
1
git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nrMenemukan sedikit tweak di git blame sini yang lebih akurat menggambarkan statistik yang saya cari. Secara khusus, opsi -M dan -C -C (itu adalah dua C pada tujuan). -M mendeteksi gerakan dalam file, dan -C -C mendeteksi garis yang disalin dari file lain. Lihat dokumen di sini . Demi kelengkapan, -w mengabaikan spasi.
John Lee
1

Saya memiliki solusi ini yang menghitung garis menyalahkan di semua file teks (tidak termasuk file biner, bahkan yang versi):

IFS=$'\n'
for file in $(git ls-files); do
    git blame `git symbolic-ref --short HEAD` --line-porcelain "$file" | \
        grep  "^author " | \
        grep -v "Binary file (standard input) matches" | \
        grep -v "Not Committed Yet" | \
        cut -d " " -f 2-
    done | \
        sort | \
        uniq -c | \
        sort -nr
Gabriel Diego
sumber
1

Ini berfungsi di direktori mana pun dari struktur sumber repo, jika Anda ingin memeriksa modul sumber tertentu.

find . -name '*.c' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr
Martin G
sumber
0

Saya mengadopsi jawaban teratas untuk Powershell:

(git ls-tree -rz --name-only HEAD).Split(0x00) | where {$_ -Match '.*\.py'} |%{git blame -w --line-porcelain HEAD $_} | Select-String -Pattern '^author ' | Group-Object | Select-Object -Property Count, Name | Sort-Object -Property Count -Descending

Ini opsional jika Anda menjalankan git blamedengan -wswitch, saya menambahkannya karena mengabaikan perubahan spasi putih.

Kinerja pada mesin saya mendukung Powershell (~ 50s vs ~ 65s untuk repo yang sama), meskipun solusi Bash berjalan di bawah WSL2

Matt M.
sumber
-1

Membuat skrip saya sendiri yang merupakan kombinasi dari @nilbus dan @Alex

#!/bin/sh

for f in $(git ls-tree -r  --name-only HEAD --);
do
    j=$(file "$f" | grep -E ': .*text'| sed -r -e 's/: .*//');
    if [ "$f" != "$j" ]; then
        continue;
    fi
    git blame -w --line-porcelain HEAD "$f" | grep  "^author " | sed 's/author //'`enter code here`
done | sort | uniq -c | sort -nr
vossman77
sumber
Bagi saya, masalah Anda enter code heremenyebabkan masalah .... apakah ini berfungsi dengan benar?
Menios
-1

Fungsi Bash yang menargetkan file sumber tunggal berjalan di MacOS.

function glac {
    # git_line_author_counts
    git blame -w "$1" |  sed -E "s/.*\((.*) +[0-9]{4}-[0-9]{2}.*/\1/g" | sort | uniq -c | sort -nr
}
jxramos
sumber