Git 리포지토리에서 특정 작성자가 변경 한 총 줄 수를 계산하는 방법은 무엇입니까?


458

Git 저장소에서 특정 작성자가 변경 한 행을 계산하는 호출 할 수있는 명령이 있습니까? Github이 Impact 그래프에 대해이 작업을 수행함에 따라 커밋 수를 계산하는 방법이 있어야한다는 것을 알고 있습니다.


1
Linux 커널 개발에 대한 통계를 수집하는 유명한 도구를 고려할 수 있습니다 (예 : Repository is here) git://git.lwn.net/gitdm.git.
0andriy

답변:


310

다음 명령의 출력은 총계를 더하기 위해 스크립트로 전송하기가 합리적으로 쉽습니다.

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

현재 HEAD에 대한 모든 커밋에 대한 통계를 제공합니다. 다른 지점에 통계를 추가하려면에 통계를 제공해야합니다 git log.

스크립트에 전달하기 위해 빈 로그 형식으로 "oneline"형식을 제거 할 수도 있으며 Jakub Narębski의 의견에 따르면 --numstat다른 대안입니다. 행당 통계보다는 파일 단위로 생성되지만 구문 분석이 더 쉽습니다.

git log --author="<authorname>" --pretty=tformat: --numstat

2
이것이 내가 예상 한 방식으로 결과를 제공하기 때문에 허용되는 답변을 변경했으며, 이것을 달성하려는 다른 방문자에게 더 도움이 될 것입니다.
Gav

14
통계를 조금 더 쉽게 추가하려는 경우 --numstat대신 사용할 수 있습니다 --shortstat.
Jakub Narębski

8
거기에 "--no-merges"를 추가하고 싶을 수도 있습니다.
yoyo

9
이 질문에 대해 죄송하지만 숫자는 무엇을 말합니까? 두 줄이 있는데 그들이 무엇을 말하고 있는지 전혀 모른다. 줄이 added 고 추가 되었습니까?
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 }' -

Mac OSX에서 Awk 사용 :

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에서 테스트 됨). 스크립트보다는 직접 사용에 더 적합합니다.

그것은의 자식-빠른 통계 (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

여기에 이미지 설명을 입력하십시오


18
이 사랑스러운 긴 라이너에 감사드립니다! 이 어색한 점은 모든 사람의 갑판을 꼼짝 못하게했습니다 (정확하고 빠르며 이상한 출력은 없습니다). 놀랍지 않게, 이것이 awk를 위해 고안된 종류라는 것을 고려하면 ... 파티에 너무 늦어서 너무 나빴습니다.
zxq9

4
@ zxq9 : 질문을 받았을 때 스택 오버 플로우조차 없었으며 여기에 대한 답변에서 영감을 얻었습니다. 사람들이 계속 이것을 필요로 할 때 나는 여기의 모든 사람들을 천천히 추월하기를 바랍니다.
Alex

9
이 멋진 작동하지만 변경했다 gawk할 수 awk는 OSX 터미널에서 작동하도록
자크 Lysobey

1
파일 이동이 올바른 통계를 반영하지 않기 때문에 @samthebest. 줄은 바뀌지 않습니다. Alex에게 : Git에 대해 이야기하고 있습니다. Btw, 원래 질문에 대한 내 의견을 참조하십시오.
0andriy

2
URL이 제대로 작동하지 않으면 다음을 시도하십시오.git clone https://github.com/arzzen/git-quick-stats.git
Nicolas

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-15k 커밋이있는 리포지토리를 통해 몇 분이 소요됩니다.)


12
대단해! michael,: 6057 files changed, 854902 insertions(+), 26973 deletions(-), 827929 net
Michael J. Calkins

1
코드에서 @ EugenKonkov는 삽입-삭제로 정의됩니다.
Dan

13
그것은 저장소에 대한 총 결과를 제공하고 플러그인없이 실행되는 유일한 명령입니다.
Ömer Faruk Almalı 오전

1
많은 수의 사용자가 함께 나열되어 있으며 거의 ​​모든 가능한 개발자 조합이 다시 나타납니다. 내 말이 이상해?
데이먼

2
@BenSewards Linux 용 Windows 서브 시스템을 사용하여 Windows에서 Bash를 사용할 수 있습니다. 자세한 내용은 여기를
mjsr

152

힘내 명성 https://github.com/oleander/git-fame-rb

커밋 및 수정 된 파일 수를 포함하여 모든 작성자의 수를 한 번에 계산할 수있는 유용한 도구입니다.

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

https://github.com/casperdcl/git-fame(@fracz 에서 언급 )에도 Python 버전이 있습니다 .

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

그러나 Jared의 의견에서 언급했듯이 매우 큰 저장소에서 처리하는 데 몇 시간이 걸립니다. 그것이 너무 많은 Git 데이터를 처리해야한다는 것을 고려할 때 그것이 향상 될 수 있는지 확실하지 않습니다.


1
이것은 훌륭하지만 너무 느리다
Jared Burrows

1
2015 년 중반 맥북과 중간 규모의 Android 프로젝트 (127k LoC 'is)에서 잘 작동했습니다. 몇 분 동안.
maxweber 2016 년

2
현재 사용자에 대한 toal loc / commits / files의 @Vincent 퍼센트.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
분기, 시간 초과 변경 및 폴더 제외 :git fame --branch=dev --timeout=-1 --exclude=Pods/*
jonmecer

1
@AlexanderMills 나는 당신이 의미 모양에 라인을 셀 수 없다 때문입니다 같은데요
치로 틸리郝海东冠状病六四事件法轮功

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
문자열 대체에 루비를 사용하기 때문에 루비를 쉽게 사용하지 않도록 수정할 수 있습니다. 당신은 펄, 나오지도, 파이썬, 등 사용할 수 있습니다
mmrobins

21
나를 위해 작동하지 않습니다 : -e : 1 :
in`

1
/^.*\((.*?)\s[\d]{4}//^.*?\((.*?)\s[\d]{4}/저자로서 소스에서 일치하는 괄호를 방지 해야합니다 .
Timothy Gu

1
음, 내 실행은 구문 분석이 잘못되어 존재하지 않는 많은 사용자를 보여주었습니다. 나는 그것이 신뢰할만한 대답이 아니라고 생각합니다.
mjsr

92

주어진 브랜치에서 주어진 저자 (또는 모든 저자) 의 커밋 수를 세려면 git-shortlog를 사용할 수 있습니다 . git 저장소에서 실행될 때 특히 해당 옵션 --numbered--summary옵션을 참조하십시오 .

$ 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당신이 및 복제 / 또는 자식 저장소에서 가져 오지 않은 때에 상관없이 같은 수 없습니다 : 메이크업 출력 결정이 예에서는 여기에있다.
Jakub Narębski

포함 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 : -sis --summary, -nis --numbered, [new] -e--email저자의 이메일을 보여주는 것입니다 (그리고 .mailmap수정 사항 을 고려하여 다른 이메일 주소를 가진 동일한 저자를 별도로 계산합니다 ). 에 대한 좋은 전화 --no-merges.
Jakub Narębski

75

보고 후 알렉스Gerty3000 의 대답, 나는 한 줄을 단축하는 것을 시도했다 :

기본적으로 git log numstat를 사용하고 변경된 파일 수를 추적 하지 않습니다 .

Mac OSX에서 Git 버전 2.1.0 :

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

캔트 그것의 별칭을 만들 :-(
brat

33

쉘 one-liner를 사용하는 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

이름에서 날짜까지 모든 공백을 사용하는 + after \ s에 주목하십시오.

사실 나는이 주제를 google에 두 번째로 기록하기 때문에 다른 사람을 돕는 것만 큼 내 자신의 기억을 위해이 답변을 많이 추가합니다. :)

  • 편집 2019년 1월 23일는 추가 --show-email하는 git blame -w어떤 사람들은 다른 사용하기 때문에, 대신 이메일에 통합 할 Name다른 컴퓨터에 포맷을하고, 같은 이름을 가진 때로는 두 사람이 같은 자식에서 일하고있다.

펄을 사용한이 답변은 루비 기반의 답변보다 조금 더 나은 것으로 보입니다. 루비는 실제 UTF-8 텍스트가 아닌 라인을 질식 시켰으며 펄은 불평하지 않았다. 그러나 펄은 옳은 일을 했습니까? 모르겠어요
Stéphane Gourichon

서브 모듈은 결과적으로 발생 unsupported file type하지만 그렇지 않은 경우에도 제대로 작동하는 것 같습니다 (건너 뜁니다).
Vladimír Čunát

24

다음은 모든 저자에 대한 통계를 생성하는 짧은 하나의 라이너입니다. 위의 Dan 솔루션보다 https://stackoverflow.com/a/20414465/1102119 보다 훨씬 빠릅니다 (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그렇지 않으면 자신의 커밋 PGP 서명 할 사람이 계산 얻을하지 않을 수 있습니다.
Philihp Busby

2
ins [a]-del [a], ins [a], del [a], a이므로 삽입 삽입, 삭제, 삭제, 이름이 올바른 경우
MrKekson

"git count-lines"로 호출 할 수 있도록 git 설정에이 명령을 어떻게 추가 할 수 있습니까?
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) (UTF-8 기반 로케일에서 grep을 엄청나게 가속화합니다).


멋진 라인, 매우 멋진, 쉽게 믹스 할 수 있지만 원래 포스터가 요청한 것을 수행하지 못하고 git의 저자가 계산합니다. 물론 그것을 실행하고 wc-l 등을 수행 할 수는 있지만 저장소의 모든 작성자에 대해 반복해야합니다.
AaronM

1
@AaronM 나는 당신의 비판을 이해하지 못한다. 이 라인 AFAIK는 귀하와 동일한 통계를 출력하며 더욱 강력합니다. 따라서 제 대답이 "원래 포스터가 요청한 것을 수행하지 못하면, git의 저자에 의해 카운트를 제공하십시오". 제발 깨달아 줘
Stéphane Gourichon

죄송합니다. 잘못 읽었습니다. 각 저자 이름마다 명령을 수정해야한다고 생각했습니다. 다른 줄에 대한 grep에 대한 당신의 의견은 저를 이끌었습니다. 그러나 그것은 나의 오해였습니다.
AaronM

정말 대단합니다. 감사!
Tek

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
업데이트 된 정규 표현식은 의미있는 차이를 만들지 않으며 첫 번째 paren을 탈출하지 않아 깨졌습니다. 그러나 이전 코드에서 코드 줄에서 비트를 찾을 수있는 경우를 볼 수 있습니다. 이것은보다 안정적으로 작동합니다 : git ls-files -z | xargs -0n1 자식 비난 -w | perl -n -e '/^.*?\((.*?)\s[\d]{4}/; print $ 1, "\ n"'| sort -f | uniq -c | sort -n
AaronM

보다 안정적인 정규 표현식을 작성해 주셔서 감사합니다. 보다 강력한 변형에 대한 내 대답을 참조하십시오 stackoverflow.com/a/36090245/1429390
스테판 구리 콘

13

Charles Bailey의 답변 외에도 -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"를 실행할 때 결과를 얻지 못합니다. 에디션 수는 커밋 목록이 있지만 총 수는 없습니다. 모든 자식 저장소에서 편집 된 총 줄 수를 어떻게 얻을 수 있습니까?
Mehdi

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

'점수'란 무엇입니까?
user11171

@Volte npm i는 npm 설치를위한 바로 가기입니다
Michiel

예, 알고 있습니다 내가 -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
이 스크립트는 훌륭하지만 한 줄 커밋 만있는 저자는 제외합니다! 수정하려면 다음과 같이 변경하십시오. changes = / (\ d +) insertion. * (\ d +) deleted / .match (line)
Larry Gritz

9

이것이 가장 좋은 방법이며 모든 사용자의 총 커밋 수를 명확하게 보여줍니다.

git shortlog -s -n

2
유용하지만 전체 코드 라인이 아닌 커밋 수
Diolor

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에서 0으로 잘못 나누기
Vivek Jha

71 번째 줄에서 불법 부서를 0으로 해결했습니다. 수정 사항이 없지만 얼마 전에 작성했다고 생각합니다.
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

이 스크립트는 여기에 있습니다. authorship.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
아니, 그것은 WONT !, 당신은 다른 곳에 이것을 게시, 그것은 맥과 리눅스에서 오류를 생성, 당신은 알다시피, git가 만들어진 컴퓨터의 유형!
Pizzaiola Gorgonzola

1

다음을 사용하여 로그를 파일로 저장하십시오.

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

파이썬 애호가들에게 :

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했지만 OP가 필요하다고 생각한 통계를 실제로 제공하지는 않았습니까?
CB Bailey

감사합니다. .mailmap도 도움이되었습니다.
Gav

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

이 작업을 수행하기 위해이 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-012019 년 동안 보고서를 가져 오도록 명령 을 실행할 수 있습니다 . 예로서. 그리고 철자가 틀리면 git이라는 이름이 올바른 철자를 제안합니다.

내 repos가 저장되고 그렇지 않을 수도 있으므로 _get_repo_slug마지막 부분 만 포함 하도록 하위 를 조정할 수 있습니다.remote.origin.urlproject/repo

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.