Статистика винних комітетів


198

Як я можу "зловживати" звинуваченням (або якоюсь більш підходящою функцією та / або у поєднанні з командами оболонки), щоб дати мені статистику про те, скільки рядків (коду) наразі знаходиться у сховищі, що походять від кожного комітента?

Приклад Вихід:

Committer 1: 8046 Lines
Committer 2: 4378 Lines

11
Для цього дійсно повинна бути вбудована команда ... Є команди для набагато рідших випадків використання.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

@CiroSantilli, але легко додати оболонку, яку можна викликати з git.
Алекс

можливий дублікат Як підрахувати загальну кількість рядків, змінених певним автором у сховищі Git? тому що його можна легко звести до цього: просто
переведіть

1
це досить дивний code.google.com/p/gitinspector особливо якщо ви сортуючи завдання груп студентів (великі проекти не повинні застосовуватися ... це повільно , тому що він звинувачує кожен окремий файл)
sehe

Відповіді:


166

Оновлення

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

Я оновив деякі речі по дорозі.

Для зручності ви також можете ввести це в свою команду:

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

зберігайте це десь на своєму шляху або модифікуйте свій шлях і використовуйте його як

  • 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

Оригінальний відповідь

Хоча прийнята відповідь робить цю роботу дуже повільно.

$ 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

майже миттєво.

Щоб отримати список файлів, які зараз відстежуються, ви можете використовувати

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

Це рішення дозволяє уникнути виклику, fileщоб визначити тип файлу, і використовує grep, щоб відповідати бажаному розширення з міркувань продуктивності. Якщо всі файли повинні бути включені, просто видаліть це з рядка.

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

якщо файли можуть містити пробіли, які шкідливі для оболонок, ви можете використовувати:

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

Надайте список файлів (через трубу), з допомогою xargs можна викликати команду та розподілити аргументи. Команди, що дозволяють обробляти декілька файлів, передають -n1. У цьому випадку ми дзвонимо, git blame --line-porcelainі для кожного дзвінка ми використовуємо рівно 1 аргумент.

xargs -n1 git blame --line-porcelain

Тоді ми фільтруємо вихід за появою "авторського" сортування списку і підраховуємо повторювані рядки за:

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

Примітка

Інші відповіді фактично фільтрують рядки, які містять лише пробіли.

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

Команда вище буде друкувати авторів рядків, що містять щонайменше один непробільний символ. Ви також можете використовувати сірник, \w*[^\w#]який також буде виключати рядки, де перший символ, який не є пробілом, не є #(коментар у багатьох мовах сценаріїв).


2
@nilbus: не можна. echo "a\nb\nc"|xargs -n1 cmdрозшириться доcmd a; cmd b; cmd d
Алекс

2
- line-porcelain, здається, не працює більше (git 1.7.5.4), замість цього використовуйте --porcelain
isoiphone

4
Користувачі OSX, спробуйте наступне (досі не працює файли з новими рядками на їх ім’я):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
Якщо ви просто хочете, щоб усе під поточним контуром, на будь-яку глибину, використовуйте "./" як фільтр контуру (куди відповів ставить " / .c").
Бен Ділтс

2
Можливо, використовуйте "blame -w" для кращого володіння кодом, коли код переформатувався лише stackoverflow.com/questions/4112410/…
sleeplessnerd

124

Я написав дорогоцінний камінь під назвою git-fame, який може бути корисним.

Встановлення та використання:

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

Вихід:

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, який працює і виглядає так, що він дає розумні номери, решта командного рядка або не працюють на OSX через несумісність утилітів, або дають маленькі номери на моєму репо. Це на OSX та рубіні 1.9.3 (варити)
Karthik T

9
Не будь дурним, @tcaswell. Це не спам, щоб вказувати на щось корисне, навіть якщо вам трапилось щось написати.
Уейн

5
Відповідаючи на власне запитання: git fame --exclude = шляхи / до / файлів, шляхи / до / інших / файлів
Maciej Swic

2
@Adam: Ви все ще маєте проблеми з цим? Для мене працює дуже добре на OS X 10.9.5.
Сем Даттон

2
Для будь-якого репо, що перевищує декілька забирає час, який цей дорогоцінний камінь повинен виконати, це робота астрономічна
Ерік Ейнер

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

Покрокове пояснення:

Список усіх файлів під контролем версій

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

Обріжте список лише до текстових файлів

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

Git звинувачує всі текстові файли, ігноруючи зміни пробілів

|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/ +$//'

Сортуйте список авторів і підрахуйте uniq кількість рядків, що послідовно повторюються

|sort|uniq -c

Приклад виводу:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda

1
Здається, що у мене інша sedверсія, моя не розуміє -rпрапор і має проблеми з регулярним виразом (скаржиться на незбалансовані паролі, навіть коли я видаляю надлишки ().
Ерік Айгнер

7
Не забудьте, sudo brew install gnu-sedвирішили. Працює як шарм!
Ерік Егнер

5
Або port install gsedдля користувачів MacPorts.
Гевін Брок

Я зробив sudo brew install gnu-sed(який працював), але я все одно отримую помилки, які sed не розпізнає -r. :(
Адам Таттл

1
На OSX після встановлення gsed через macports я запустив цю команду, щоб вона працювала (замінила sed на 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надається пакетом git-extras - саме те, що вам потрібно. Ознайомтеся з документацією на git-extras - git-rezime :

git summary --line

Виводить такий вигляд:

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

1
Добре, але, здається, не підтримується фільтр шляху або принаймні аргумент підкаталогу. Було б приємніше.
шпигун

1
Приємне і чисте рішення. @ Відповідь Алекса чомусь дала дуже малі підрахунки рядків. Це щойно вийшло з коробки. Витратили щось на кшталт 30 секунд для ~ 200k рядків, поширюваних на кілька сотень файлів.
fgblomqvist

6

Рішення Еріка було приголомшливим, але у мене виникли деякі проблеми з діакритикою (не дивлячись на те, що LC_*мінливі середовища були встановлені нібито правильно) і шум протікав по рядках коду, які насправді мали в них дати. Мій сед-фу поганий, тому я закінчив цей франкенштейнський фрагмент з рубіном, але він працює для мене бездоганно на 200 000+ LOC, і він сортує результати:

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

Також gsedзамість цього зверніть увагу на sedте, що це встановлено двійкові домородіння, залишаючи систему sed непошкодженою.


4

git shortlog -sn

Це покаже список комітетів на кожного автора.


17
Це повертає кількість комітетів на автора, а не кількість рядків.
v64

Дуже корисно для визначення основних учасників проекту / каталогу / файлу
Арес

4

Ось основний фрагмент відповіді @Alex, який насправді виконує операцію з агрегування винних ліній. Я скоротив його для роботи з одним файлом, а не з набором файлів.

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

Я публікую це тут, тому що часто повертаюся до цієї відповіді і перечитую пост та повторно перетравлюю приклади, щоб витягти ту частину, яку я ціную, - це оподаткування. Також це не є загальним для мого використання; його сфера застосування стосується цілого проекту C.


Мені подобається перераховувати статистику по файлу, досягнуту за допомогою forітератора bash замість того, xargsяк я вважаю xargs менш читабельними і важкими у використанні / запам'ятовуванні. Перевага / недоліки xargs vs for повинні обговорюватися в інших місцях.

Ось практичний фрагмент, який відображатиме результати для кожного файлу окремо:

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

І я тестував, запускаючи цю стрічку в оболонці bash, це ctrl + c безпечно, якщо вам потрібно помістити це всередині скрипту bash, можливо, вам знадобиться захопити SIGINT і SIGTERM, якщо ви хочете, щоб користувач міг зламати ваш цикл.


1
git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nrЗнайдений невелике підстроювання до git blame тут , що більш точно зображує статистику я шукав. Зокрема, параметр -M та -C -C (цілі є двома C). -M виявляє переміщення у файлі, а -C -C виявляє скопійовані рядки з інших файлів. Дивіться док. Тут . Для повноти, -w ігнорує пробіл.
Джон Лі


1

У мене є таке рішення, яке підраховує звинувачені рядки у всіх текстових файлах (за винятком двійкових файлів, навіть версій):

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

Це працює в будь-якому каталозі вихідної структури репо, якщо ви хочете перевірити певний модуль джерела.

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

0

Я прийняв головну відповідь до 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

Необов’язково, чи будете ви працювати git blameз -wкомутатором, я додав його, оскільки він ігнорує зміни пробілів.

Продуктивність на моїй машині була на користь Powershell (~ 50s проти ~ 65s для того ж репо), хоча рішення Bash працювало під WSL2


-1

Створив власний сценарій, який поєднує @nilbus та @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

Для мене твоя річ enter code hereспричиняла проблеми .... чи правильно це працює?
Меніос

-1

Функція Bash, яка орієнтована на один вихідний файл, запущений на 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.