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

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

Ответ 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:

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

Ответ 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