Git 저장소에서 특정 작성자가 변경 한 총 줄 수를 계산하는 방법은 무엇입니까?
Git 저장소에서 특정 작성자가 변경 한 행을 계산하는 호출 할 수있는 명령이 있습니까? Github이 Impact 그래프에 대해이 작업을 수행함에 따라 커밋 수를 계산하는 방법이 있어야한다는 것을 알고 있습니다.
다음 명령의 출력은 총계를 더하기 위해 스크립트로 전송하기가 합리적으로 쉽습니다.
git log --author="<authorname>" --oneline --shortstat
현재 HEAD에 대한 모든 커밋에 대한 통계를 제공합니다. 다른 지점에 통계를 추가하려면에 통계를 제공해야합니다 git log
.
스크립트에 전달하기 위해 빈 로그 형식으로 "oneline"형식도 제거 할 수 있으며 Jakub Narębski의 의견에 따르면 --numstat
다른 대안입니다. 행당 통계보다는 파일 단위로 생성되지만 구문 분석하기가 더 쉽습니다.
git log --author="<authorname>" --pretty=tformat: --numstat
이것은 저자에 대한 통계를 제공하고 필요에 따라 수정합니다.
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
누구나 자신의 코드베이스에서 모든 사용자 의 통계를보고 싶을 때 최근 두 명의 동료 가이 끔찍한 원 라이너를 생각해 냈습니다.
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 커밋이있는 우리 저장소를 통해 몇 분이 소요됩니다.)
힘내 명성 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 데이터를 처리해야한다는 것을 고려할 때 개선 될 수 있는지 확실하지 않습니다.
다음은 현재 코드베이스에 가장 많은 행을 가진 사람을 보는 데 유용한 것으로 나타났습니다.
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
주어진 브랜치에서 주어진 저자 (또는 모든 저자) 의 커밋 수를 세려면 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
보고 후 알렉스 와 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
쉘 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
다른 컴퓨터에 포맷을하고, 같은 이름을 가진 때로는 두 사람이 같은 자식에서 일하고있다.
다음은 모든 저자에 대한 통계를 생성하는 짧은 하나의 라이너입니다. 위의 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
@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을 엄청나게 가속화합니다).
해결책은 중간에 루비가 주어졌으며, 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
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(-)
내 생각에 후자는 파일 이름을 바꾸는 것이 처음부터 파일을 작성하는 것보다 훨씬 작은 작업이기 때문에 개인이 프로젝트에 얼마나 많은 영향을 미쳤는 지에 대한보다 현실적인 견해를 제공합니다.
다음은 주어진 로그 쿼리에 대한 사용자 별 영향을 비교하는 빠른 루비 스크립트입니다.
예를 들어, 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
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>
=====================================================
이것이 가장 좋은 방법이며 모든 사용자의 총 커밋 수를 명확하게 보여줍니다.
git shortlog -s -n
위의 짧은 답변을 수정했지만 내 요구에 충분하지 않았습니다. 최종 코드에서 커밋 된 라인과 라인을 모두 분류 할 수 있어야했습니다. 또한 파일별로 분류하고 싶었습니다. 이 코드는 되풀이되지 않고 단일 디렉토리에 대한 결과 만 반환하지만 누군가가 더 나아가고 싶다면 좋은 시작입니다. 파일에 복사하여 붙여 넣어 실행 가능하게 만들거나 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};
}
이 스크립트는 여기에 있습니다. 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 ":"
다음을 사용하여 로그를 파일로 저장하십시오.
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
당신은 힘내 책임을 원한다 .
통계를 출력하는 --show-stats 옵션이 있습니다.
이 질문은 특정 저자 에 대한 정보를 요구 했지만 많은 답변은 변경된 코드 라인을 기준으로 순위가 높은 저자 목록을 반환하는 솔루션이었습니다.
이것이 내가 찾던 것이었지만 기존 솔루션은 완벽하지 않았습니다. 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
지금까지 내가 확인한 최고의 도구는 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
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
'Programing' 카테고리의 다른 글
Apple의 Swift 언어에서 난수를 어떻게 생성합니까? (0) | 2020.02.20 |
---|---|
SSH 키-여전히 비밀번호 및 비밀번호 문구 요청 (0) | 2020.02.20 |
Google Finance API 대신 사용 (0) | 2020.02.20 |
디자인 패턴 : 싱글 톤은 언제 사용해야합니까? (0) | 2020.02.20 |
배열에서 무언가의 첫 번째 인덱스를 반환하는 NumPy 함수가 있습니까? (0) | 2020.02.20 |