Reputation: 10917
I want to list every contributors for each file in the repository.
Here is currently what I do:
find . | xargs -L 1 git blame -f | cut -d' ' -f 2-4 | sort | uniq
This is very slow. Is there a better solution ?
Upvotes: 8
Views: 2963
Reputation: 60255
Don't use --stat
if you don't need the stats, why ask it to rerun all the diffs, then scrape all the results off? Just use --name-only
.
git log --all --pretty=%x09%cN --name-only | awk -F$'\t' '
NF==2 { name=$2 }
NF==1 { contribs[ $0 ][ name ] = 1 }
END {
n = asorti(contribs,sorted)
for ( i=0 ; ++i < n ; ) {
file = sorted[i]
print file
for ( name in contribs[file] ) print "\t"name
}
}
'
Upvotes: 0
Reputation: 450
git log --pretty=format:"%cn" <filename> | sort | uniq -c
You can also do more with git log
, Ex: committers to each file after certain date (Ex: after 2018-10-1):
git log --after="2018-10-1" --pretty=format:"%cn" <filename> | sort | uniq -c
Ref: https://www.atlassian.com/git/tutorials/git-log
Upvotes: 0
Reputation: 2100
I would write a small script that analyzes the output of git log --stat --pretty=format:'%cN'
; something along the lines of:
#!/usr/bin/env perl
my %file;
my $contributor = q();
while (<>) {
chomp;
if (/^\S/) {
$contributor = $_;
}
elsif (/^\s*(.*?)\s*\|\s*\d+\s*[+-]+/) {
$file{$1}{$contributor} = 1;
}
}
for my $filename (sort keys %file) {
print "$filename:\n";
for my $contributor (sort keys %{$file{$filename}}) {
print " * $contributor\n";
}
}
(Written just quickly; does not cover cases like binary files.)
If you stored this script, e.g., as ~/git-contrib.pl
, you could call it with:
git log --stat=1000,1000 --pretty=format:'%cN' | perl ~/git-contrib.pl
Advantage: call git
only once, which implies that it is reasonably fast. Disadvantage: it’s a separate script.
Upvotes: 6
Reputation: 90286
Taking ДМИТРИЙ's answer as a base, I'd say the following :
git ls-tree -r --name-only master ./ | while read file ; do
echo "=== $file"
git log --follow --pretty=format:%an -- $file | sort | uniq
done
Enhancement is that it follows file's rename in its history, and behaves correctly if files contain spaces (| while read file
)
Upvotes: 8
Reputation: 21972
tldr:
for file in `git ls-tree -r --name-only master ./`; do
echo $file
git shortlog -s -- $file | sed -e 's/^\s*[0-9]*\s*//'
done
You can get all tracked files in repository with git ls-tree
. Find
is really bad choice.
For example, get list of tracked file in branch master
in current dir (./
):
git ls-tree -r --name-only master ./
You can get list of file editors with get shortlog
(git blame
is overkill):
git shortlog -s -- $file
So, for each file from ls-tree
response you should call shortlog
and modify its output however you want.
Upvotes: 3