Як підрахувати загальні рядки, змінені певним автором у сховищі 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

2
Я змінив свою прийняту відповідь, оскільки це дає результат таким, як я очікував, і буде кориснішим для інших відвідувачів, які прагнуть цього досягти.
Гав

14
Ви можете використовувати --numstatзамість цього, --shortstatякщо хочете трохи простіше додати статистику.
Якуб Нарбський

8
Можливо, захочете додати і "--no-merges".
yoyo

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

EDIT (2017)

На Github є новий пакет, який виглядає гладким і використовує bash як залежності (тестується на Linux). Він більше підходить для прямого використання, а не сценаріїв.

Це git-quick-stats (github link) .

Скопіюйте 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

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


18
Дякуємо за цей чудовий лонг-лайнер! Це місце awk перебрало колоду всіх (точно, швидко, без зайвих дивних результатів). Не дивно, враховуючи, що це така штука, яка була розроблена для ... Шкода, що ви так пізно пішли на вечірку.
zxq9

4
@ zxq9: Я навіть не був у стаковому потоці, коли було задано питання, і мене надихнули відповіді тут. будемо сподіватися, що я потихеньку наздоганяю всіх тут, оскільки люди в цьому потребують.
Алекс

9
Це працює приголомшливо, але мені довелося змінити, gawkщоб awkвін працював у терміналі OSX
Zach Lysobey

1
@samthebest, оскільки переміщення файлу не відображає належної статистики. Рядки не змінені. Алексу: Я говорю про Гіт. До речі, дивіться мій коментар до оригінального питання.
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
це єдина команда, яка дає загальний результат для сховища і працює без будь-якого плагіна.
Ömer Faruk Almalı

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.


1
Це дивовижно, але так повільно
Джаред Берроуз

1
Добре працював у середині 2015 року в macbook та середньому великому проекті Android (127k LoC 'є). Пару хвилин.
maxweber

2
@Вінцент відсотків тола лока / комітетів / файлів для поточного користувача.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Змініть гілку, час очікування та виключіть папку:git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer

1
@AlexanderMills Я здогадуюсь, це тому, що ти не можеш осмислено рахувати рядки на краплі
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

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


31
Я збирався дати +1, але тоді я зрозумів, що рішення залежить від рубіну ... :(
мак

3
Ви можете змінити його, щоб не використовувати рубін досить легко, оскільки я просто використовую рубін для підстановки рядків. Ви можете використовувати perl, sed, python тощо
mmrobins

21
не працює для мене: -e: 1: у `<main> ': недійсна послідовність байтів у UTF-8 (ArgumentError)
Michał Dębski

1
/^.*\((.*?)\s[\d]{4}/Потрібно /^.*?\((.*?)\s[\d]{4}/запобігати збігу дужок у джерелі як автору.
Тимофій Гу

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

92

Для підрахунку кількості фіксацій даного автора (чи всіх авторів) по даній галузі можна використовувати ГИТ-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". Якщо чесно, більшість людей не виконують цю команду на git repo. Насправді досить великий запас.
Влад Імпала

4
git shortlog -sneабо, якщо ви бажаєте не включати злиттяgit shortlog -sne --no-merges
Марк Свардстром

1
@Swards: -sє --summary, -nє --numberedі [new] -e- --emailпоказувати електронні листи авторів (і рахувати окремо одного автора з різною електронною адресою з урахуванням .mailmapвиправлень). Гарний дзвінок о --no-merges.
Якуб Нарбський

75

Після перегляду Алекса та Герти3000 відповідь «s, я спробував скоротити однострочнікі:

В основному, використовуючи нуместат журналу git і не відслідковуючи кількість файлів змінених .

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

Не
брат

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формати на різних комп’ютерах, а іноді двоє людей з тим самим іменем працюють в одному git.

Ця відповідь за допомогою perl виявилася трохи кращою за рубінову. Рубі захлинався на рядки, які не були фактичним текстом UTF-8, 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

4
Добре, але що означає вихід?
Gary Willoughby

Слід додати --no-show-signature, інакше люди, які підписують свої документи, не зараховуються.
Філіхп Бусбі

2
ins [a] - del [a], ins [a], del [a], a, тож якщо я правий вставкою-видаленням, вставкою, видаленням, ім'ям
MrKekson

Як я можу додати цю команду до моєї конфігурації git, щоб я міг називати її "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

Ви можете привітатись до інших рядків, наприклад, електронної пошти, виконавця тощо.

Можливо, спочатку зробіть export LC_ALL=C(якщо припустити bash) примусову обробку на рівні байтів (це також відбувається, щоб значно прискорити grep з локалів на базі UTF-8).


Приємна лінія там, дуже класна, що ви можете легко змішати її, однак це не вдається виконати те, що просив оригінальний плакат, забезпечити підрахунок автора від git. Звичайно, ви можете запустити його та зробити wc-l тощо, але тоді вам потрібно буде повторити для кожного автора в сховищі.
AaronM

1
@AaronM Я не розумію вашої критики. Цей рядок AFAIK видає ту саму статистику, що і ваша, лише більш надійну. Отже, якщо моя відповідь "не вдається виконати те, що просив оригінальний плакат, надайте підрахунок автора від git", то ваша ще більше. Будь ласка, просвіти мене.
Стефан Гурішон

Вибачте, що я неправильно прочитав, я подумав, що команду потрібно змінити для кожного імені авторів. Ваш коментар про греп для інших рядків привів мене туди, але це було моє непорозуміння.
AaronM

Це так приголомшливо. Дякую!
Тек

16

Рішення було надано з рубіном посередині, 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

5
Оновлений регулярний вираз не має значущого значення, і він порушується, оскільки ви не уникнули першого батька. Однак я можу побачити деякі випадки, коли мій попередній міг би знайти деякі біти в рядку коду, який потрібно зафіксувати. Це працюватиме надійніше: git ls-files -z | xargs -0n1 git винувати -w | perl -n -e '/^.*?\((.*?)\s evid\\\\\\\\\ s; print print $ 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>
=====================================================

Що означає "оцінка"?
користувач11171

@Volte НПЙ я це просто ярлик для НОЙ установки
Міхель

Так, я знаю. Мої -gповинні були прийти перед назвою пакета, на macOS. Просто намагаюся допомогти.
Volte

11

Ось швидкий сценарій рубіну, який підкручує вплив на користувача на заданий запит журналу.

Наприклад, для rubinius :

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

2
Цей сценарій чудовий, але виключає авторів, які мають лише однорядкові коміти! Щоб виправити, змініть так: зміни = / (\ d +) вставлення. * (\ D +) видалення / .match (рядок)
Larry Gritz

9

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

git shortlog -s -n

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

Я отримую цю помилку: Незаконне ділення на нуль на лінії 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

На mac з встановленим варивом

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)


1

Цей сценарій тут зробить це. Помістіть його в avtorhip.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 ":"

1
ні це НЕ БУДЕ !, Ви розмістили це в іншому місці, він створює помилки на Mac і Linux, ви знаєте, тип комп'ютерів git був зроблений на!
Pizzaiola Gorgonzola

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

Ви хочете, щоб Гіт звинувачувався .

Існує варіант - show-stats для друку деяких, ну, статистичних даних.


Я спробував 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

Найкращий на даний момент інструмент, який я визначив, - це гітінспектор. Він дає встановлений звіт на користувача, тиждень тощо. Ви можете встановити, як нижче, з npm

npm встановити -g gitinspector

Посилання для отримання більш детальної інформації

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

https://github.com/ejwa/gitinspector/wiki/Документація

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і ваші можуть не бути.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.