Есть ли команда, которую я могу вызвать, которая будет подсчитывать строки, измененные конкретным автором в репозитории Git? Я знаю, что должны быть способы подсчитать количество коммитов, поскольку Github делает это для своего графика Impact.
Как подсчитать общие строки, измененные конкретным автором в репозитории Git?
Ответ 1
Вывод следующей команды должен быть достаточно прост для отправки на script для добавления итогов:
git log --author="<authorname>" --oneline --shortstat
Это дает статистику для всех фиксаций текущего HEAD. Если вы хотите добавить статистику в другие ветки, вам нужно будет предоставить их в качестве аргументов git log
.
Для перехода к script удаление даже формата "oneline" может быть выполнено с пустым форматом журнала, и, как прокомментировал Якуб Нарбский, --numstat
- еще одна альтернатива. Он генерирует per-file, а не статистику по строке, но еще проще анализировать.
git log --author="<authorname>" --pretty=tformat: --numstat
Ответ 2
Это дает некоторую статистику об авторе, при необходимости изменяйте.
Использование 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 }' -
EDIT (2017)
В github есть новый пакет, который выглядит гладким и использует bash в качестве зависимостей (проверяется на linux). Это больше подходит для прямого использования, а не для скриптов.
Это git -quick-stats (github link).
Скопируйте git-quick-stats
в папку и добавьте папку в путь.
mkdir ~/source
cd ~/source
git clone [email protected]: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
Ответ 3
В случае, если кто-то хочет видеть статистику для каждого пользователя в своей кодовой базе, недавно несколько моих коллег придумали этот ужасный однострочный шрифт:
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 тыс. ком.)
Ответ 4
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.
Ответ 5
Я нашел следующее, чтобы узнать, кто из них больше всего в базе кода:
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 wame (-C -M), чтобы получить более качественные номера, которые учитывают перемещение файлов и перемещение строк между файлами, но если вы это сделаете, команда может работать намного дольше.
Кроме того, если вы ищете строки, измененные во всех коммитах для всех коммиттеров, полезно немного script:
Ответ 6
Чтобы подсчитать количество совершает заданный автор (или все авторы) в данной ветки, вы можете использовать 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
Ответ 7
После просмотра ответа Alex и Gerty3000 я попытался сократить однострочный шрифт:
В основном, используя git log numstat и not, отслеживая количество файлов.
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
Ответ 8
Ответ от 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
на разных компьютерах, а иногда два человека с одинаковыми именами работают в одном и том же git.
Ответ 9
Здесь короткий однострочный шрифт, который создает статистику для всех авторов. Это намного быстрее, чем решение Dan выше на fooobar.com/questions/21541/... (у меня есть временная сложность 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
Ответ 10
@mmrobins @AaronM @ErikZ @JamesMishra предоставили варианты, которые имеют общую проблему: они просят git создать смесь информации, не предназначенной для потребления script, включая содержимое строки из репозитория в той же строке, затем сопоставьте беспорядок с регулярным выражением.
Это проблема, когда некоторые строки недопустимы для текста UTF-8, а также когда некоторые строки соответствуют регулярному выражению (это произошло здесь).
Здесь есть модифицированная строка, которая не имеет этих проблем. Он запрашивает git для вывода данных на отдельных строках, что позволяет легко фильтровать то, что мы хотим надежно:
git ls-files -z | xargs -0n1 git blame -w --line-porcelain | grep -a "^author " | sort -f | uniq -c | sort -n
Вы можете использовать grep для других строк, таких как author-mail, committer и т.д.
Возможно, сначала сделайте export LC_ALL=C
(предполагая bash
) принудительную обработку на уровне байта (это также происходит для ускорения grep чрезвычайно сильно из локалей на основе UTF-8).
Ответ 11
Решение было дано с рубином посередине, 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
Ответ 12
В дополнение к ответу Чарльза Бейли, вы можете добавить параметр -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(-)
По моему мнению, последний дает более реалистичное представление о том, какое влияние оказал человек на проект, потому что переименование файла намного меньше, чем запись файла с нуля.
Ответ 13
Здесь быстрый ruby script, который подкрепляет влияние на пользователя для данного запроса журнала.
Например, для rubinius:
Brian Ford: 4410668
Evan Phoenix: 1906343
Ryan Davis: 855674
Shane Becker: 242904
Alexander Kellett: 167600
Eric Hodel: 132986
Dirkjan Bussink: 113756
...
script:
#!/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
Ответ 14
Вы можете использовать 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 <[email protected]>
585 | somelady <[email protected]>
212 | niceguy <[email protected]>
173 | coolguy <[email protected]>
=====================================================
Ответ 15
это лучший способ, и он также дает вам четкое представление об общем количестве коммитов всем пользователем
git shortlog -s -n
Ответ 16
Я представил модификацию короткого ответа выше, но этого было недостаточно для моих нужд. Мне нужно было иметь возможность классифицировать как совершенные строки, так и строки в конечном коде. Я также хотел разбить файл. Этот код не рекурсирует, он вернет результаты только для одного каталога, но это хороший старт, если кто-то захочет пойти дальше. Скопируйте и вставьте в файл и выполните исполняемый файл или запустите его с помощью 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};
}
Ответ 17
Этот script здесь сделает это. Поместите его в authorhip.sh, chmod + x it, и вы все настроены.
#!/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 ":"
Ответ 18
Сохраните ваши журналы в файл, используя:
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
Ответ 19
Вы хотите Git винить.
Здесь есть опция -show-stats для печати, ну, статистика.
Ответ 20
Вопрос был задан для информации об определенном авторе, но многие ответы были решениями, которые вернули ранжированные списки авторов на основе их строк кода.
Это то, что я искал, но существующие решения были не совсем идеальными. В интересах людей, которые могут найти этот вопрос через Google, я сделал некоторые улучшения на них и сделал их в оболочку script, которую я покажу ниже. Аннотированный (который я продолжу поддерживать) может быть найден на моем 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
Ответ 21
Лучшим инструментом, который я идентифицировал, является 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
Ответ 22
Для пользователей 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