Как подсчитать общее количество строк, измененных конкретным автором в репозитории Git?

458

Есть ли команда, которую я могу вызвать, которая будет подсчитывать количество строк, измененных конкретным автором в репозитории Git? Я знаю, что должны быть способы подсчета количества коммитов, как это делает Github для своего графика воздействия.

Гав
источник
1
Вы могли бы рассмотреть известный инструмент, который собирает статистику для разработки ядра Linux, например, Репозиторий здесь git://git.lwn.net/gitdm.git.
0

Ответы:

310

Вывод следующей команды должен быть достаточно простым для отправки в скрипт для суммирования итогов:

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

Это дает статистику для всех коммитов на текущем заголовке. Если вы хотите добавить статистику в другие ветки, вам нужно будет предоставить их в качестве аргументов git log.

Для перехода к сценарию удаление даже формата «oneline» может быть сделано с пустым форматом журнала, и, как прокомментировал Якуб Наребски, --numstatэто еще одна альтернатива. Он генерирует для каждого файла, а не для каждой строки статистику, но его еще проще анализировать.

git log --author="<authorname>" --pretty=tformat: --numstat
CB Bailey
источник
2
Изменил мой принятый ответ, так как это дает результат, как я ожидал, и будет более полезным для других посетителей, желающих достичь этого.
Гав
14
Вы можете использовать --numstatвместо, --shortstatесли вы хотите добавить статистику немного проще.
Якуб Наребски
8
Возможно, вы захотите добавить туда также «--no-merges».
Йо
9
извините за эти вопросы, но какие цифры говорят мне? Есть два ряда, и я понятия не имею, что они говорят мне. Линии изменены и добавлены?
Informatic0re
2
@ Informatic0re git help logговорит мне, что первые строки добавлены, вторые строки удалены.
ThomasH
599

Это дает некоторую статистику об авторе, изменяя при необходимости.

Используя 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 }' -

Использование Awk на 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 }' -

РЕДАКТИРОВАТЬ (2017)

На github есть новый пакет, который выглядит гладко и использует bash в качестве зависимостей (протестировано на linux). Это больше подходит для непосредственного использования, чем сценарии.

Это git-quick-stats (ссылка на github) .

Скопируйте git-quick-statsв папку и добавьте папку в путь.

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

Применение:

git-quick-stats

введите описание изображения здесь

Alex
источник
18
Спасибо за этот прекрасный лайнер! Это пятно awk зачистило колоду каждого (точное, быстрое, без лишних странных выводов). Не удивительно, учитывая, что это было то, для чего был разработан awk ... Жаль, что вы так опоздали на вечеринку.
zxq9
4
@ zxq9: я не был даже в stackoverflow, когда задавался вопрос, и я был вдохновлен ответами здесь. будем надеяться, что я буду медленно обгонять всех здесь, так как люди продолжают нуждаться в этом.
Алекс
9
Это работает потрясающе, но я должен был изменить gawkего, awkчтобы заставить его работать в терминале OSX
Zach Lysobey
1
@samthebest, потому что перемещение файла не отражает правильную статистику. Линии не изменены. Алексу: я говорю о Git. Кстати, смотрите мой комментарий к первоначальному вопросу.
0
2
Если URL не работает для вас, попробуйте это:git clone https://github.com/arzzen/git-quick-stats.git
Николас
226

На случай, если кто-то захочет увидеть статистику по каждому пользователю в своей кодовой базе, пара моих коллег недавно придумали эту ужасную строку:

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

(Занимает несколько минут, чтобы пройти через наш репо, который имеет около 10-15 тыс. Коммитов.)

Дэн
источник
12
Это потрясающе! michael,: 6057 files changed, 854902 insertions(+), 26973 deletions(-), 827929 net
Майкл Дж. Калкинс
1
@EugenKonkov в коде он определяется как вставки - удаления.
Дан
13
это единственная команда, которая дает общий результат для хранилища и запускается без какого-либо плагина.
Омер Фарук Алмали
1
Я получаю кучу пользователей, перечисленных вместе, почти все возможные комбинации разработчиков возвращаются. странность на моем конце?
Деймон
2
@BenSewards, вы можете использовать Bash в Windows, используя подсистему Windows для Linux, более подробную информацию здесь
mjsr
152

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

хороший инструмент для подсчета всех авторов сразу, включая фиксацию и изменение файлов:

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

Также есть версия Python по адресу https://github.com/casperdcl/git-fame (упомянутая @fracz):

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

Пример вывода:

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

Но будьте осторожны: как упомянул Джаред в комментарии, выполнение этого в очень большом хранилище займет часы. Не уверен, что это можно улучшить, учитывая, что он должен обрабатывать так много данных Git.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
источник
1
Это круто, но так медленно
Джаред Берроуз,
1
Хорошо работали на MacBook середины 2015 года и на среднем крупном Android-проекте (127k LoC 'есть). Пару минут.
Максвебер
2
@ Vincent процент от лок / коммитов / файлов для текущего пользователя.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
1
Измените ветку, время ожидания и исключите папку:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer
1
@AlexanderMills Я предполагаю, что это потому, что вы не можете осмысленно считать строки на BLOB-
объектах
103

Мне показалось полезным следующее, чтобы узнать, у кого больше всего строк в базе кода:

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

Другие ответы в основном касались строк, измененных в коммитах, но если коммиты не сохранились и были перезаписаны, они могли быть просто оттоками. Вышеупомянутое заклинание также позволяет отсортировать всех коммиттеров по строкам, а не по одному за раз. Вы можете добавить некоторые параметры в git blame (-C -M), чтобы получить более точные числа, которые учитывают перемещение файлов и перемещение строк между файлами, но команда может выполняться намного дольше, если вы это сделаете.

Кроме того, если вы ищете строки, измененные во всех коммитах для всех коммиттеров, вам пригодится следующий небольшой скрипт:

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

mmrobins
источник
31
Я собирался дать +1, но потом я понял, что решение зависит от ruby ​​... :(
mac
3
Вы можете изменить его так, чтобы он не использовал ruby ​​довольно легко, поскольку я просто использую ruby ​​для подстановки строк. Вы можете использовать Perl, Sed, Python и т. Д.
mmrobins
21
у меня не работает: -e: 1: в `<main> ': неверная последовательность байтов в UTF-8 (ArgumentError)
Михал Дембски
1
/^.*\((.*?)\s[\d]{4}/должно быть, /^.*?\((.*?)\s[\d]{4}/чтобы предотвратить совпадение скобок в источнике, как автор.
Тимоти Гу
1
ммм мои казни показали много пользователей, которых даже не существует, из-за плохого разбора. Я думаю, что это не надежный ответ.
mjsr
92

Для подсчета количества коммитов данного автора (или всех авторов) в данной ветке вы можете использовать git-shortlog ; особенно посмотрите его --numberedи его --summaryпараметры, например, при запуске в 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
Обратите внимание, что v1.6.4здесь, в этом примере, чтобы сделать вывод детерминированным: он будет одинаковым независимо от того, когда вы клонировали и / или выбирали из репозитория git.
Якуб Наребски
в том числе v1.6.4дает мне:fatal: ambiguous argument 'v1.6.4': unknown revision or path not in the working tree.
Влад Импала
5
Ах, нет, я пропустил "при запуске на git репозиторий". Чтобы быть справедливыми, большинство людей обыкновения запускать эту команду на мерзавец репо. На самом деле, с довольно большим отрывом.
Влад Импала
4
git shortlog -sneили, если вы не хотите включать слиянияgit shortlog -sne --no-merges
Марк Swardstrom
1
@Swards: -sесть --summary, -nесть --numbered, и [новый] -eявляется , --emailчтобы показать электронные письма авторов (и подсчитывать отдельно того же автор с другим адресом электронной почты, с учетом .mailmapпоправок). Хороший звонок --no-merges.
Якуб Наребски
75

Посмотрев на ответ Алекса и Gerty3000 , я попытался укоротить одну строку :

В основном, используя git log numstat и не отслеживая количество измененных файлов .

Git версии 2.1.0 на 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

Пример:

Jared Burrows   added lines: 6826, removed lines: 2825, total lines: 4001
Джаред Барроуз
источник
Cant сделать псевдоним его :-(
отродье
33

Ответ от AaronM с помощью оболочки Однострочника хорошо, но на самом деле, есть еще одна ошибка, где пробела испортят имена пользователей , если есть различные количества пробелов между именем пользователя и датой. Поврежденные имена пользователей приведут к нескольким строкам для подсчета пользователей, и вы должны суммировать их самостоятельно.

Это небольшое изменение исправило проблему для меня:

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

Обратите внимание на знак + после \ s, который будет использовать все пробелы от имени до даты.

На самом деле, добавив этот ответ так же, как для моей памяти, так и для помощи кому-либо еще, так как это по крайней мере второй раз, когда я гуглю тему :)

  • Редактировать 2019-01-23 Добавлено --show-emailв git blame -wагрегировать по электронной почте вместо этого, так как некоторые люди используют различные Nameформаты на разных компьютерах, а иногда и два человека с одинаковым именем работают в одной и той же мерзавцем.
Эрик Живкович
источник
Этот ответ, использующий Perl, оказался немного лучше, чем у рубинов. Руби захлебнулся строками, которые не являлись реальным текстом UTF-8, perl не жаловался. Но Perl поступил правильно? Я не знаю.
Стефан Гурихон
Подмодули приводят к результату, unsupported file typeно в остальном он работает нормально даже с ними (он их пропускает).
Владимир Чунат,
24

Вот короткая строка, которая производит статистику для всех авторов. Это намного быстрее, чем приведенное выше решение Дэна на https://stackoverflow.com/a/20414465/1102119 (у меня сложность по времени O (N) вместо O (NM), где N - количество коммитов, а M - количество авторов). ).

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
kccqzy
источник
4
Хорошо, но что означает выход?
Гэри Уиллоуби
Вы должны добавить --no-show-signature, иначе люди, которые подписывают свои коммиты pgp, не будут засчитаны.
Филип Басби
2
ins [a] - del [a], ins [a], del [a], a, поэтому, если я прав: вставка - удаление, вставка, удаление, имя
MrKekson
Как я могу добавить эту команду в мой git config, чтобы я мог вызывать ее с помощью «git count-lines»?
takanuva15
Неважно, я понял это 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". (Обратите внимание, я нахожусь на Windows; возможно, вам придется использовать различные виды цитат)
takanuva15
21

@mmrobins @AaronM @ErikZ @JamesMishra предоставил варианты, которые имеют общую проблему: они просят git выдать смесь информации, не предназначенной для использования скриптами, включая содержимое строки из хранилища в одной строке, а затем сопоставляют беспорядок с регулярным выражением. ,

Это проблема, когда некоторые строки не являются допустимым текстом UTF-8, а также когда некоторые строки соответствуют регулярному выражению (это произошло здесь).

Вот модифицированная строка, которая не имеет этих проблем. Он запрашивает git для чистого вывода данных в отдельных строках, что позволяет легко фильтровать то, что нам нужно:

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

Вы можете использовать grep для других строк, таких как почта автора, коммиттер и т. Д.

Возможно, сначала сделайте export LC_ALL=C(предполагая bash) форсировку обработки на уровне байтов (это также очень сильно ускоряет grep из локалей на основе UTF-8).

Стефан Гурихон
источник
Хорошая линия, очень крутая, что вы можете легко смешать ее, однако это не в состоянии сделать то, что просил оригинальный постер, предоставить счет по автору из git. Конечно, вы можете запустить его и сделать wc-l и т. Д., Но тогда вам нужно будет повторить это для каждого автора в хранилище.
AaronM
1
@AaronM Я не понимаю твоей критики. Эта строка AFAIK выводит ту же статистику, что и ваша, только более надежная. Так что, если мой ответ «не в состоянии выполнить то, о чем просил оригинальный постер, указать количество авторов по git», то ваш еще больше. Пожалуйста, просветите меня.
Стефан Гурихон
извините, я неправильно прочитал, я думал, что команда должна быть изменена для каждого имени другого автора. Ваш комментарий о grep для других строк привел меня туда, но это было мое недоразумение.
AaronM
Это так круто. Спасибо!
Tek
16

Решение было дано с ruby ​​посередине, поскольку perl немного более доступен по умолчанию, это альтернатива использованию perl для текущих строк автора.

git ls-files -z | xargs -0n1 git blame -w | perl -n -e '/^.*\((.*?)\s*[\d]{4}/; print $1,"\n"' | sort -f | uniq -c | sort -n
AaronM
источник
5
Обновленное регулярное выражение не имеет существенного значения, и оно сломано, поскольку вы не избежали первого парена. Тем не менее, я могу видеть некоторые случаи, когда мой предыдущий мог найти некоторые биты в строке кода для фиксации. Это будет работать более надежно: git ls-files -z | xargs -0n1 git blame -w | perl -n -e '/^.*?\((.*?)\s[\d]]width4casts/; выведите $ 1, "\ n"' | sort -f | uniq -c | sort -n
AaronM
спасибо за попытку сделать более надежное регулярное выражение. Смотрите мой ответ для более надежного варианта stackoverflow.com/a/36090245/1429390
Стефан Гурихон
13

В дополнение к ответу Чарльза Бейли , вы можете добавить-C параметр в команды. В противном случае переименования файлов считаются множеством добавлений и удалений (столько, сколько в файле есть строки), даже если содержимое файла не было изменено.

Для иллюстрации приведем коммит с множеством файлов, перемещаемых из одного из моих проектов при использовании git log --oneline --shortstatкоманды:

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

И здесь тот же коммит, используя git log --oneline --shortstat -Cкоманду, которая обнаруживает копии файлов и переименовывает:

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

По моему мнению, последний дает более реалистичное представление о том, какое влияние оказал человек на проект, потому что переименование файла - это гораздо меньшая операция, чем запись файла с нуля.

Эско Луонтола
источник
2
Когда я выполняю «git log --oneline --shortstat», я не получаю ваш результат. У меня есть список коммитов с количеством выпусков, но не с общим количеством. Как я могу получить общее количество строк, отредактированных во всем git-репозитории?
Мехди
12

Вы можете использовать whodid ( https://www.npmjs.com/package/whodid )

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

а также

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

или просто введите

$ whodid

тогда вы можете увидеть результат, как это

Contribution state
=====================================================
 score  | author
-----------------------------------------------------
 3059   | someguy <someguy@tensorflow.org>
 585    | somelady <somelady@tensorflow.org>
 212    | niceguy <nice@google.com>
 173    | coolguy <coolgay@google.com>
=====================================================
victor.cheval
источник
Что означает «оценка»?
user11171
@Volte npm, я просто ярлык для установки npm
Michiel
Да, я в курсе. Мой -gдолжен был прийти перед именем пакета, на macOS. Просто пытаюсь помочь.
Volte
11

Вот быстрый скрипт ruby, который сопоставляет воздействие на пользователя с данным запросом журнала.

Например, для рубиния :

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

сценарий:

#!/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
Nevir
источник
2
Этот скрипт великолепен, но исключает авторов, которые имеют только однострочные коммиты! Чтобы исправить, измените следующим образом: изменения = / (\ d +) вставка. * (\ D +) удаление / .match (строка)
Ларри Гритц
9

это лучший способ, и он также дает вам четкое представление об общем количестве коммитов всеми пользователями

git shortlog -s -n
edrich13
источник
2
Полезно, но это число
коммитов
5

Я предоставил модификацию короткого ответа выше, но этого было недостаточно для моих нужд. Мне нужно было иметь возможность классифицировать как зафиксированные строки, так и строки в конечном коде. Я также хотел разбить файл. Этот код не повторяется, он будет возвращать результаты только для одного каталога, но это хорошее начало, если кто-то хочет пойти дальше. Скопируйте и вставьте в файл и сделайте исполняемым или запустите его с 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};
}
AaronM
источник
Я получаю эту ошибку: незаконное деление на ноль в строке x.pl 71.
Vivek Jha
Обращалось к нелегальному делению на ноль в строке 71. Подумайте, это происходит, если нет правок, но это было недавно, когда я написал это.
AaronM
2

Для пользователей Windows вы можете использовать следующий пакетный скрипт, который считает добавленные / удаленные строки для указанного автора

@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

Вот отличный репо, который делает вашу жизнь проще

git-quick-stats

На макинтоше с установленным напитком

brew install git-quick-stats

Запустить

git-quick-stats

Просто выберите, какой вариант вы хотите из этого списка, набрав номер в списке и нажав 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)

jasonleonhard
источник
1

Этот скрипт здесь сделает это. Поместите его в authorhip.sh, chmod + x, и все готово.

#!/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
нет, это НЕ БУДЕТ!, вы опубликовали это в другом месте, оно генерирует ошибки на Mac и Linux, вы знаете, тип компьютеров, на которых был сделан git!
Пиццайола Горгонзола
1

Сохраните ваши журналы в файл, используя:

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

Для любителей 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')

Ваши результаты будут такими:

225        files changed
6751       insertions
1379       deletions
Аминь Аяч
источник
0

Вы хотите, чтобы Git вину .

Есть опция --show-stats для печати некоторой статистики.

gbjbaanb
источник
Я пытался blame, но это не давало статистику, которая, как я думал, понадобится ОП?
CB Bailey
Спасибо, это также помогло мне с .mailmap тоже!
Гав
0

В вопросе запрашивалась информация о конкретном авторе, но многие из ответов были решениями, которые возвращали ранжированные списки авторов на основе измененных строк кода.

Это было то, что я искал, но существующие решения были не совсем идеальными. В интересах людей, которые могут найти этот вопрос через Google, я внес в них некоторые улучшения и превратил их в сценарий оболочки, который я отображаю ниже. Аннотированный (который я буду продолжать поддерживать) можно найти на моем Github .

Нет никаких зависимостей ни от Perl, ни от Ruby. Кроме того, пробел, переименования и движения строк учитываются при подсчете изменений строк. Просто поместите это в файл и передайте Git-репозиторий в качестве первого параметра.

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

Лучший инструмент, который я до сих пор опознал, это gitinspector. Он дает установленный отчет для каждого пользователя, за неделю и т. Д. Вы можете установить, как показано ниже, с помощью npm.

npm install -g gitinspector

Ссылки, чтобы получить более подробную информацию

https://www.npmjs.com/package/gitinspector

https://github.com/ejwa/gitinspector/wiki/Documentation

https://github.com/ejwa/gitinspector

примеры команд

gitinspector -lmrTw 
gitinspector --since=1-1-2017 etc
Равикиран Редди Котапати
источник
0

Я написал этот скрипт на Perl для выполнения этой задачи.

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

Я назвал это git-line-changes-by-authorи положил в /usr/local/bin. Поскольку он сохраняется на моем пути, я могу выполнить команду, git line-changes-by-author --before 2018-12-31 --after 2020-01-01чтобы получить отчет за 2019 год. Например. И если бы я ошибся, название git предложит правильное написание.

Вы можете настроить _get_repo_slugсабвуфер так, чтобы он включал только последнюю часть, так remote.origin.urlкак мои репозитории сохраняются, а project/repoваши нет.

joehep
источник