Thống kê cam kết Git Blame


198

Làm cách nào tôi có thể "lạm dụng" đổ lỗi (hoặc một số chức năng phù hợp hơn và / hoặc kết hợp với các lệnh shell) để cung cấp cho tôi một thống kê về số lượng dòng (mã) hiện có trong kho lưu trữ có nguồn gốc từ mỗi committer?

Kết quả ví dụ:

Committer 1: 8046 Lines
Committer 2: 4378 Lines

11
Thực sự cần phải có một lệnh tích hợp cho điều đó ... có những lệnh cho các trường hợp sử dụng ít phổ biến hơn nhiều.
Ciro Santilli 郝海东 冠状 病 事件

@CiroSantilli nhưng thật dễ dàng để thêm một shellscript bất khả xâm phạm từ git.
Alex

có thể trùng lặp Làm thế nào để đếm tổng số dòng được thay đổi bởi một tác giả cụ thể trong kho Git? bởi vì nó có thể dễ dàng giảm xuống cái đó: chỉ cần lặp qua tất cả các tác giả
Ciro Santilli 郝海东 冠状 病 六四

1
này là khá awesome code.google.com/p/gitinspector đặc biệt là nếu bạn đang chấm điểm bài tập của đội sinh viên (dự án lớn không cần phải áp dụng ... đó là chậm vì nó đổ lỗi cho mỗi tập tin cá nhân)
sehe

Câu trả lời:


166

Cập nhật

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

Tôi đã cập nhật một số điều trên đường đi.

Để thuận tiện, bạn cũng có thể đặt lệnh này vào lệnh riêng của nó:

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

lưu trữ này ở đâu đó trong đường dẫn của bạn hoặc sửa đổi đường dẫn của bạn và sử dụng nó như

  • 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

Câu trả lời gốc

Trong khi câu trả lời được chấp nhận thực hiện công việc thì nó rất chậm.

$ 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

là gần như tức thời.

Để có được danh sách các tập tin hiện đang theo dõi, bạn có thể sử dụng

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

Giải pháp này tránh gọi fileđể xác định filetype và sử dụng grep để khớp với phần mở rộng mong muốn vì lý do hiệu suất. Nếu tất cả các tập tin nên được bao gồm, chỉ cần loại bỏ điều này khỏi dòng.

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

nếu các tệp có thể chứa dấu cách, có hại cho shell, bạn có thể sử dụng:

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

Đưa ra một danh sách các tập tin (thông qua một đường ống) người ta có thể sử dụng xargs để gọi một lệnh và phân phối các đối số. Các lệnh cho phép nhiều tệp được xử lý chấp nhận -n1. Trong trường hợp này, chúng tôi gọi git blame --line-porcelainvà cho mỗi cuộc gọi, chúng tôi sử dụng chính xác 1 đối số.

xargs -n1 git blame --line-porcelain

Sau đó, chúng tôi lọc đầu ra cho các lần xuất hiện của "tác giả" sắp xếp danh sách và đếm các dòng trùng lặp theo:

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

Ghi chú

Các câu trả lời khác thực sự lọc ra các dòng chỉ chứa khoảng trắng.

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

Lệnh trên sẽ in các tác giả của các dòng chứa ít nhất một ký tự không phải khoảng trắng. Bạn cũng có thể sử dụng kết hợp \w*[^\w#]cũng sẽ loại trừ các dòng trong đó ký tự không phải khoảng trắng đầu tiên không phải là một #(nhận xét bằng nhiều ngôn ngữ kịch bản).


2
@nilbus: bạn không thể. echo "a\nb\nc"|xargs -n1 cmdsẽ mở rộng thànhcmd a; cmd b; cmd d
Alex

2
--line-sứ dường như không còn hoạt động nữa (git 1.7.5.4) thay vào đó sử dụng --por chì
isoiphone

4
Người dùng OSX, hãy thử các cách sau (vẫn không hoạt động trên các tệp có dòng mới trong tên của họ):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
Nếu bạn chỉ muốn mọi thứ trong đường dẫn hiện tại, đến bất kỳ độ sâu nào, hãy sử dụng "./" làm bộ lọc đường dẫn (nơi người trả lời đặt " / .c").
Ben Dilts

2
Có thể sử dụng "đổ lỗi -w" để có quyền sở hữu mã tốt hơn khi mã chỉ được định dạng lại stackoverflow.com/questions/4112410/ trên
ngủ

124

Tôi đã viết một viên ngọc gọi là git-fame có thể hữu ích.

Cài đặt và sử dụng:

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

Đầu ra:

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

5
+1 cuối cùng 1 hoạt động và có vẻ như nó cung cấp các số hợp lý, phần còn lại của dòng lệnh không hoạt động trên OSX do không tương thích hoặc đưa ra các số nhỏ trên repo của tôi. Đây là trên OSX và ruby ​​1.9.3 (bia)
Karthik T

9
Đừng ngớ ngẩn, @tcaswell. Nó không phải là thư rác để chỉ ra một cái gì đó hữu ích, ngay cả khi bạn đã là người viết thứ đó.
Wayne

5
Trả lời câu hỏi của riêng tôi: git fame --exclude = path / to / files, path / to / other / files
Maciej Swic

2
@Adam: Bạn vẫn gặp vấn đề với điều này? Hoạt động rất tốt với tôi trên OS X 10.9.5.
Sam Dutton

2
Đối với bất kỳ repo nào lớn hơn một vài lần cam kết thời gian viên ngọc này cần thực hiện thì đó là công việc thiên văn
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

Từng bước giải thích:

Liệt kê tất cả các tệp dưới sự kiểm soát phiên bản

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

Cắt bớt danh sách xuống chỉ các tệp văn bản

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

Git đổ lỗi cho tất cả các tệp văn bản, bỏ qua các thay đổi khoảng trắng

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

Rút ra tên tác giả

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

Sắp xếp danh sách các tác giả và có uniq đếm số dòng lặp lại liên tiếp

|sort|uniq -c

Ví dụ đầu ra:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda

1
Có vẻ như tôi có một sedphiên bản khác , tôi không hiểu -rcờ và có vấn đề với regex (phàn nàn về các số liệu không cân bằng, ngay cả khi tôi loại bỏ phần dư thừa ().
Erik Aigner

7
Nevermind, sudo brew install gnu-sedgiải quyết nó. Hoạt động như một lá bùa!
Erik Aigner

5
Hoặc port install gsedcho người dùng MacPorts.
Gavin Brock

Tôi đã làm một sudo brew install gnu-sed(hoạt động) nhưng tôi vẫn nhận được lỗi mà sed không nhận ra -r. :(
Adam T Ink

1
Trên OSX sau khi cài đặt gsed qua macports, tôi đã chạy lệnh này để làm cho nó hoạt động (thay thế sed bằng 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 summaryđược cung cấp bởi gói git-extend chính xác là những gì bạn cần. Kiểm tra tài liệu tại git-bổ sung - tóm tắt git :

git summary --line

Cung cấp đầu ra trông như thế này:

project  : TestProject
lines    : 13397
authors  :
8927 John Doe            66.6%
4447 Jane Smith          33.2%
  23 Not Committed Yet   0.2%

1
Đẹp, nhưng dường như không hỗ trợ bộ lọc đường dẫn hoặc ít nhất là một đối số thư mục con. Sẽ đẹp hơn.
spinkus

1
Giải pháp đẹp và sạch sẽ. Câu trả lời của @ Alex mang lại số lượng dòng rất nhỏ vì một số lý do. Điều này chỉ làm việc ra khỏi hộp. Mất khoảng 30 giây cho khoảng 200 nghìn dòng trải rộng trên vài trăm tệp.
fgblomqvist

6

Giải pháp của Erik thật tuyệt vời, nhưng tôi đã gặp một số vấn đề với dấu phụ (mặc dù LC_*các biến môi trường của tôi được đặt chính xác) và tiếng ồn rò rỉ trên các dòng mã thực sự có ngày tháng trong đó. Sed-fu của tôi rất kém, vì vậy tôi đã kết thúc với đoạn trích frankenstein này với viên ruby ​​trong đó, nhưng nó hoạt động hoàn hảo với tôi trên 200.000 LỘC và nó sắp xếp kết quả:

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

Cũng lưu ý gsedthay sedvì đó là cài đặt homebrew nhị phân, giữ nguyên hệ thống sed.


4

git shortlog -sn

Điều này sẽ hiển thị một danh sách các cam kết cho mỗi tác giả.


17
Điều này trả về số lượng cam kết trên mỗi tác giả, không phải số lượng dòng.
v64

Rất hữu ích trong việc xác định những người đóng góp chính cho một dự án / thư mục / tệp
Ares

4

Đây là đoạn trích chính từ câu trả lời của @Alex thực sự hoạt động tổng hợp các dòng đổ lỗi. Tôi đã cắt nó xuống để hoạt động trên một tệp chứ không phải là một tập hợp các tệp.

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

Tôi đăng bài này ở đây vì tôi thường xuyên quay lại câu trả lời này và đọc lại bài đăng và tiêu hóa lại các ví dụ để trích xuất phần tôi đánh giá nó đang đánh thuế. Nó cũng không đủ chung cho trường hợp sử dụng của tôi; phạm vi của nó là cho toàn bộ dự án C.


Tôi muốn liệt kê các số liệu thống kê cho mỗi tệp, đạt được thông qua một fortrình lặp bash thay vì xargstôi thấy xargs ít đọc và khó sử dụng / ghi nhớ, Ưu điểm / nhược điểm xargs so với nên được thảo luận ở nơi khác.

Đây là một đoạn thực tế sẽ hiển thị kết quả cho từng tệp riêng lẻ:

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

Và tôi đã thử nghiệm, việc chạy ổn định này trong shell bash là ctrl + c an toàn, nếu bạn cần đặt đoạn mã này trong tập lệnh bash, bạn có thể cần Bẫy trên SIGINT và SIGTERM nếu bạn muốn người dùng có thể phá vỡ vòng lặp của bạn.


1
git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nrTìm thấy một điều chỉnh nhỏ git blame ở đây mô tả chính xác hơn các số liệu tôi đang tìm kiếm. Cụ thể, tùy chọn -M và -C -C (đó là hai mục đích của C). -M phát hiện di chuyển trong tệp và -C -C phát hiện các dòng được sao chép từ các tệp khác. Xem tài liệu ở đây . Vì lợi ích hoàn toàn, -w bỏ qua khoảng trắng.
John Lee


1

Tôi có giải pháp này là đếm các dòng đổ lỗi trong tất cả các tệp văn bản (không bao gồm các tệp nhị phân, ngay cả các tệp được phiên bản):

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

1

Điều này hoạt động trong bất kỳ thư mục cấu trúc nguồn của repo, trong trường hợp bạn muốn kiểm tra một mô-đun nguồn nhất định.

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

0

Tôi đã thông qua câu trả lời hàng đầu cho 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

Đó là tùy chọn cho dù bạn chạy git blamevới-w tắc, tôi đã thêm nó vì nó bỏ qua các thay đổi khoảng trắng.

Hiệu suất trên máy của tôi nghiêng về Powershell (~ 50s so với ~ 65s cho cùng một repo), mặc dù giải pháp Bash đang chạy trong WSL2


-1

Tạo kịch bản của riêng tôi, đó là sự kết hợp của @nilbus và @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

Đối với tôi, điều của bạn enter code heređã gây ra vấn đề .... điều này có hoạt động chính xác không?
Menios

-1

Hàm Bash nhắm mục tiêu một tệp nguồn duy nhất chạy trên 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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.