218

How can I "abuse" blame (or some better suited function, and/or in conjunction with shell commands) to give me a statistic of how much lines (of code) are currently in the repository originating from each committer?

Example Output:

Committer 1: 8046 Lines
Committer 2: 4378 Lines
  • 13
    There really should be a built-in command for that... there are commands for much less common use cases. – Ciro Santilli OurBigBook.com Feb 15 '14 at 09:04
  • @CiroSantilli but it's easy to add a shellscript that is invocable from git. – Alexander Oh Jun 11 '14 at 13:03
  • 1
    this is quite awesome http://code.google.com/p/gitinspector/ especially if you're grading assignments by teams of students (large projects need not apply... it's slow because it blames each individual file) – sehe Jan 10 '15 at 11:28
  • 1
    @CiroSantilli新疆棉花TRUMPBANBAD this question here asks about the current code base and its origin, not how much lines an author comitted. Imagine someone adding a huge file and removing it with the next commit: `git log` counts all those lines as add & remove, `git blame` not – inetphantom May 04 '21 at 14:30
  • related: https://stackoverflow.com/questions/1265040/how-to-count-total-lines-changed-by-a-specific-author-in-a-git-repository – Ciro Santilli OurBigBook.com May 04 '21 at 14:53

13 Answers13

186

Update

git ls-tree -r -z --name-only HEAD -- */*.c  | sed 's/^/.\//' | xargs -0 -n1 git blame \
--line-porcelain HEAD |grep -ae "^author "|sort|uniq -c|sort -nr

I updated some things on the way.

For convenience, you can also put this into its own command:

#!/bin/bash

# save as i.e.: git-authors and set the executable flag
git ls-tree -r -z --name-only HEAD -- $1 | sed 's/^/.\//' | xargs -0 -n1 git blame \
 --line-porcelain HEAD |grep -ae "^author "|sort|uniq -c|sort -nr

store this somewhere in your path or modify your path and use it like

  • git authors '*/*.c' # look for all files recursively ending in .c
  • git authors '*/*.[ch]' # look for all files recursively ending in .c or .h
  • git authors 'Makefile' # just count lines of authors in the Makefile

Original Answer

While the accepted answer does the job it's very slow.

$ git ls-tree --name-only -z -r HEAD|egrep -z -Z -E '\.(cc|h|cpp|hpp|c|txt)$' \
  |xargs -0 -n1 git blame --line-porcelain|grep "^author "|sort|uniq -c|sort -nr

is almost instantaneous.

To get a list of files currently tracked you can use

git ls-tree --name-only -r HEAD

This solution avoids calling file to determine the filetype and uses grep to match the wanted extension for performance reasons. If all files should be included, just remove this from the line.

grep -E '\.(cc|h|cpp|hpp|c)$' # for C/C++ files
grep -E '\.py$'               # for Python files

if the files can contain spaces, which are bad for shells you can use:

git ls-tree -z --name-only -r HEAD | egrep -Z -z '\.py'|xargs -0 ... # passes newlines as '\0'

Give a list of files (through a pipe) one can use xargs to call a command and distribute the arguments. Commands that allow multiple files to be processed obmit the -n1. In this case we call git blame --line-porcelain and for every call we use exactly 1 argument.

xargs -n1 git blame --line-porcelain

We then filter the output for occurences of "author " sort the list and count duplicate lines by:

grep "^author "|sort|uniq -c|sort -nr

Note

Other answers actually filter out lines that contain only whitespaces.

grep -Pzo "author [^\n]*\n([^\n]*\n){10}[\w]*[^\w]"|grep "author "

The command above will print authors of lines containing at least one non-whitespace character. You can also use match \w*[^\w#] which will also exclude lines where the first non-whitespace character isn't a # (comment in many scripting languages).

inetphantom
  • 2,498
  • 4
  • 38
  • 61
Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
  • 1
    Nice improvements! I didn't even realize at the time I wrote this that you could send git blame multiple file arguments – Edward Anderson Dec 04 '12 at 00:51
  • 2
    @nilbus: you can't. `echo "a\nb\nc"|xargs -n1 cmd` will expand to `cmd a; cmd b; cmd d` – Alexander Oh Dec 04 '12 at 06:58
  • 3
    --line-porcelain doesn't seem to work anymore (git 1.7.5.4) instead use --porcelain – isoiphone Feb 06 '13 at 20:44
  • @isoiphone I currently can't check but as soon as I get 1.7.5.4 somewhere I will verify and update. thanks for the info – Alexander Oh Feb 08 '13 at 09:34
  • this doesn't seem to work for me: "grep: : No such file or directory usage: git blame [options] [rev-opts] [rev] [--] file" – marktani May 27 '13 at 23:21
  • @isoiphone: I just tried (git 1.8.1) and it works fine. `--porcelain` seems to be different to `--line-porcelain` – Alexander Oh Jul 04 '13 at 16:20
  • @mcwise: most likely you haven't grepped for the right source file extensions in your sources. the first grep -E selects the valid extensions... – Alexander Oh Jul 18 '13 at 10:37
  • thanks to @Daniel Watkins for detecting a bug. and I added support for files that contain spaces. – Alexander Oh Aug 01 '13 at 12:02
  • `egrep: invalid option -- z` – Wayne Sep 27 '13 at 01:35
  • @lwburk: if you want me to fix the little script. it would be nice to know what egrep you are actually using. it works fine with linux. perhaps a freebsd variant? please add version perhaps operating system to understand whats going on. – Alexander Oh Sep 27 '13 at 09:26
  • Yep, sorry, I realize that wasn't very helpful, just wanted anyone who got the same error to know that it's not just them. Should have included the version, so here you go: `$ egrep --version` => `egrep (BSD grep) 2.5.1-FreeBSD` – Wayne Sep 27 '13 at 15:16
  • This is still slow for the giant repository I have (i.e. WebKit). I believe this is due to git ls-tree printing all files known. I am only interested in the changes made by the last 100 commits or so. It is possible to make it list the stats only for the filenames changed since some given base revision? – Frederick Nord Mar 06 '14 at 09:51
  • @FrederickNord: if thats the case I'm sure ls-tree allows filtering based on sub directories. otherwise try to generate a file list from git log see also: http://stackoverflow.com/questions/1265040/how-to-count-total-lines-changed-by-a-specific-author-in-a-git-repository?lq=1 – Alexander Oh Mar 06 '14 at 09:59
  • 4
    OSX users, try the following (still doesn't work on files with newlines in their name): `git ls-tree --name-only -r HEAD | grep -E '\.(cc|h|m|hpp|c)$' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr` – Wayne Mar 19 '14 at 23:29
  • Important to mention that the git blame part should also mention HEAD: `...xargs -0 -n1 git blame HEAD --line-porcelain...`. Otherwise you can get "Not yet committed" authors on Windows – Vic Jun 11 '14 at 12:28
  • 3
    If you just want everything under the current path, to any depth, use "./" as the path filter (where the answerer put "*/*.c"). – Ben Dilts Jul 03 '14 at 16:04
  • The command did not work for me at first. After some debugging I came up with: `git ls-tree --name-only -r HEAD -- app/**/*.(rb|haml|coffee|scss) | xargs -n1 git blame --line-porcelain | grep "^author " |sort|uniq -c|sort -nr` (you can change the regex to select files easily if necessary). – Augustin Riedinger Oct 07 '14 at 10:02
  • 2
    Maybe use "blame -w" to get better code ownership when code was only reformatted http://stackoverflow.com/questions/4112410/git-change-styling-whitespace-without-changing-ownership-blame – sleeplessnerd Apr 01 '15 at 11:58
  • @sleeplessnerd: my usual problem is people moving code around and importing from other repos. if you have a solution there: I'm listening – Alexander Oh Apr 01 '15 at 13:13
  • It gives a line `fatal: bad revision ' --line-porcelain'` * 8 times. – Mikhail Batcer Feb 04 '16 at 12:36
  • Using **git** version `2.7.4`, it seems that ls-tree does not support filtering by wild card expressions such as `'*/*.c'` – lanoxx Aug 23 '16 at 10:55
  • @lanoxx `*/*.c` is a shell glob. git doesn't do anything there if you do `'*/*.c'` you are passing the raw string to git that of course doesn't work, because you tell the shell to not expand the string. – Alexander Oh Aug 23 '16 at 11:46
  • 2
    For the really really lazy: `git config --global alias.authors '!f() { git ls-tree -r -z --name-only HEAD -- $1 | xargs -0 -n1 git blame --line-porcelain HEAD |grep "^author "|sort|uniq -c|sort -nr ; }; f'` – gnarf Dec 14 '16 at 16:50
  • @gnarf: what I did is store the stuff I wrote in a script made it executable and called it `git-blame-authors`. – Alexander Oh Dec 14 '16 at 17:10
  • sure, I just think it's easier to make it an alias in your `.gitconfig` (something everyone has) rather than having an added script in your bin folder, or having to edit your shell profile – gnarf Dec 16 '16 at 17:11
  • If you want any depth, but still want to limit by file type use this `git ls-files -co --exclude-standard | grep "\.go$" | xargs -n1 git blame --line-porcelain HEAD |grep "^author "|sort|uniq -c|sort -nr` – johnboiles Mar 02 '18 at 08:21
  • 1
    I noticed that some files with binary in them would break statistics for the whole project. I added a _**| cat -v**_ to the original to make it work for all files: `git ls-tree -r -z --name-only HEAD -- * | xargs -0 -n1 git blame --line-porcelain HEAD | cat -v | grep "^author "|sort|uniq -c|sort -nr` – kaycoder Dec 15 '18 at 02:39
  • 9
    `fatal: no such path 'HEAD' in HEAD` – Nakilon Feb 01 '19 at 15:29
  • The version on the manual page for `git blame` uses `sed` instead: `git ls-tree -r -z --name-only HEAD -- */*.c | xargs -0 -n1 git blame --line-porcelain HEAD | sed -n 's/^author //p' | sort | uniq -c | sort -rn` – jebob Oct 03 '19 at 12:29
  • 1
    It gives me an error - fatal: no such path 'HEAD' in HEAD – zer_ik Nov 29 '19 at 12:38
  • @zer_ik since I don't know what machine you have and what shell you are using it's hard to say what the specific root cause is. but try to check which of the commands containing HEAD gives the error. also it makes a difference of what path the command runs in. – Alexander Oh Nov 29 '19 at 12:55
  • In stead of */*.c you may also use a find command enclosed with back quotes: `\`find src/ -name "*.c"\``. In this way you include all .c files (or .py files of what every you use) in de directory src and all its subdirectories – Eelco van Vliet Jun 28 '21 at 09:19
  • @EelcovanVliet I was not using backticks on purpose. max console limit is 4096 characters by default (then your cmd will fail). – Alexander Oh Jun 28 '21 at 11:05
  • Good to know. For me it worked fine, but in case you have many files this will fail indeed. The problem for me is that the directory depth varies, so `*/*.py` did not work – Eelco van Vliet Jun 28 '21 at 17:13
  • @EelcovanVliet that should not be a problem with what I wrote, unless you want to only choose a certain sub directory. check the output of git ls-tree -r --name-only HEAD. – Alexander Oh Jun 28 '21 at 20:02
  • This can be made to work in bash by setting `shopt -s globstar` and using `**/*.c` as the path - not enclosed in quotes. NB: the `-r` argument to ls-tree is irrelevant because we're explicitly listing all the file paths we want (and `-r` only applies to directories). It's unfortunate that `ls-tree` doesn't take a pathspec, because if it did then we wouldn't have to rely on shell globbing. – Nye Dec 15 '21 at 17:02
  • Actually, you can avoid enabling `globstar` by adding `grep -z` as the 2nd command in the pipeline. E.g., for Python files (`.py` terminated): `git ls-tree -r -z --name-only HEAD | grep -z '\.py$' | sed 's/^/.\//' | xargs -0 -n1 git blame --line-porcelain | grep -ae "^author " | sort | uniq -c | sort -nr`. Replace expression in grep to match your needs or remove the whole `grep` step completely to look at *all* files tracked by Git. – tpwo Nov 18 '22 at 08:46
132

I wrote a gem called git-fame that might be useful.

Installation and usage:

  1. $ gem install git_fame
  2. $ cd /path/to/gitdir
  3. $ git fame

Output:

Statistics based on master
Active files: 21
Active lines: 967
Total commits: 109

Note: Files matching MIME type image, binary has been ignored

+----------------+-----+---------+-------+---------------------+
| name           | loc | commits | files | distribution (%)    |
+----------------+-----+---------+-------+---------------------+
| Linus Oleander | 914 | 106     | 21    | 94.5 / 97.2 / 100.0 |
| f1yegor        | 47  | 2       | 7     |  4.9 /  1.8 / 33.3  |
| David Selassie | 6   | 1       | 2     |  0.6 /  0.9 /  9.5  |
+----------------+-----+---------+-------+---------------------+
Nick Veys
  • 23,458
  • 4
  • 47
  • 64
Linus Oleander
  • 17,746
  • 15
  • 69
  • 102
  • 1
    Also doesn't work on Windows: `No such file or directory - /usr/bin/env` – Simon East Mar 31 '13 at 05:14
  • 7
    +1 finally 1 that works and looks like it gives sensible numbers, rest of the command line ones either dont work on OSX due to utils incompatibility or give teeny numbers on my repo. This is on OSX and ruby 1.9.3 (brew) – Karthik T Oct 30 '13 at 01:30
  • 11
    Don't be silly, @tcaswell. It's not spam to point to something useful, even if you did happen to be the one to write that something. – Wayne Mar 19 '14 at 23:27
  • @lwburk That it was labelled as self-written is the only thing that saved it (I didn't flag it, just left a comment). – tacaswell Mar 20 '14 at 12:23
  • 1
    @lwburk Further, see https://stackoverflow.com/posts/4590358/revisions (need sufficient rep to see) which is of exactly the same form "I wrote tool using unrelated language here is [link]", and that one was down voted, marked as spam, and deleted. – tacaswell Mar 20 '14 at 12:25
  • @tcaswell - What's your point? Yes, other people do silly stuff, too. I agree. – Wayne Mar 20 '14 at 17:17
  • 2
    Also, I have no idea what you mean by "unrelated language" in the context of this question. I get that you're trying to make this answer look bad, but you're trying too hard. – Wayne Mar 20 '14 at 17:19
  • and SO runs on the silly stuff enough people decide to do. Either they are both spam or both not. – tacaswell Mar 20 '14 at 17:29
  • Can you exclude certain paths form the stats? – Maciej Swic Jul 03 '14 at 07:55
  • 5
    Answering my own question: git fame --exclude=paths/to/files,paths/to/other/files – Maciej Swic Jul 03 '14 at 07:56
  • 2
    @Adam: Are you still having problems with this? Works very well for me on OS X 10.9.5. – Sam Dutton Mar 17 '15 at 16:00
  • would be nice to filter for filetype, like only include .hx – csomakk Apr 30 '15 at 17:32
  • 2
    For any repo thats larger than a few commits the time this gem needs to do it's job is astronomical –  Jul 01 '15 at 10:27
  • works fine and fast (~30 sec) for me. OS X 10.10.3, files: 480, lines: 33,448, commits: 753, authors: 6. – Ivan Zelenskyy Feb 25 '16 at 08:33
  • @IvanZelenskyy I found it took a while too. About 20 minutes currently for files:16090, lines: 6544205 , commits:2830 , authors 20. I have a GenuineIntel x86_64 2.8GHz with 2 threads per core and 4 cores per socket. When I limit the scope of the gem to just the sub-directory I commonly work in (711 files) it takes much less time. gitstats does not take so long but it does less line by line history mangling. – TafT Apr 06 '16 at 13:11
  • 2
    This does work on Windows when using new "Ubuntu on Windows" feature. – Matej Kormuth Sep 22 '16 at 19:27
  • It doesn't work for me, some committers are completely missing from the output. It's also insanely slow. – wim Jan 12 '17 at 22:47
  • Yes. There are source code files (.py) which have authors in the git blame , which are omitted. – wim Jan 12 '17 at 23:05
  • @wim Does any of the ignored files yield binary or image when you run `LC_ALL=C file --mime-type my-file.py` on them? (replace `my-file.py` with your own file) – Linus Oleander Jan 12 '17 at 23:23
  • No, they return `text/x-python` – wim Jan 12 '17 at 23:28
  • It would be cool if I could run this from a folder and then the main repo folder – sasklacz Feb 03 '17 at 23:32
  • Doesn't get over 3% on Debian 8 (1h 32m 47s ETA) – Simon Nitzsche Aug 19 '17 at 14:36
  • Awesome. Works fine on MacOS. – Jacek Oct 11 '17 at 08:33
  • @Oleander I wonder if it works with the new Windows __Linux Subsystem__ – EndermanAPM Nov 17 '17 at 10:12
58
git ls-tree -r HEAD|sed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c

Step by step explanation:

List all the files under version control

git ls-tree -r HEAD|sed -re 's/^.{53}//'

Prune the list down to only text files

|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'

Git blame all the text files, ignoring whitespace changes

|while read filename; do git blame -w "$filename"; done

Pull out the author names

|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'

Sort the list of authors, and have uniq count the number of consecutively repeating lines

|sort|uniq -c

Example output:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda
Edward Anderson
  • 13,591
  • 4
  • 52
  • 48
  • 1
    Seems that I have a different `sed` version, mine doesn't understand the `-r` flag and has problems with the regex (complains about unbalanced parens, even when I remove the surplus `(`). –  Jan 04 '11 at 08:01
  • 7
    Nevermind, `sudo brew install gnu-sed` solved it. Works like a charm! –  Jan 04 '11 at 08:13
  • 5
    Or `port install gsed` for MacPorts users. – Gavin Brock Apr 12 '11 at 06:04
  • I did a `sudo brew install gnu-sed` (which worked) but I still get errors that sed doesn't recognize -r. :( – Adam Tuttle May 06 '11 at 14:01
  • Got it - I backed up `/usr/bin/sed` and created a symlink from `/usr/bin/sed` to `/usr/local/Cellar/gnu-sed/4.2.1/bin/gsed`, and now this works. Thanks! – Adam Tuttle May 06 '11 at 14:07
  • Should really pass -w to blame to skip whitespace changes, otherwise someone who just changed the indentation of a file will be listed as author. – Zitrax Nov 29 '12 at 12:43
  • @nilbus: great and insightful answer! however consider using the newly posted answer. alot faster and doesn't use sed. – Alexander Oh Dec 03 '12 at 16:15
  • `git ls-tree` also have `--name-only` option – ДМИТРИЙ МАЛИКОВ Dec 04 '12 at 10:38
  • This seems to be the best answer for OSX users. Thanks! – Wayne Mar 19 '14 at 23:31
  • 1
    On OSX after installing gsed via macports I ran this command to make it work (replaced sed with gsed): `git ls-tree -r HEAD|gsed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|gsed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|gsed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c` – nerdherd Feb 15 '16 at 00:42
  • The output is corrupted when there are source code lines which have dates in them. – wim Jan 12 '17 at 22:46
50

git summary provided by the git-extras package is exactly what you need. Checkout the documentation at git-extras - git-summary:

git summary --line

Gives output that looks like this:

project  : TestProject
lines    : 13397
authors  :
8927 John Doe            66.6%
4447 Jane Smith          33.2%
  23 Not Committed Yet   0.2%
spinkus
  • 7,694
  • 4
  • 38
  • 62
adius
  • 13,685
  • 7
  • 45
  • 46
  • 1
    Nice, but doesn't seem support a path filter, or at least a sub directory argument. Would be nicer. – spinkus Nov 16 '18 at 03:53
  • 1
    Nice and clean solution. @Alex's answer yielded very small line counts for some reason. This just worked out of the box. Took something like 30 seconds for ~200k lines spread across a few hundred files. – fgblomqvist Jan 30 '20 at 19:04
  • On macOS: `brew install git-extras` – Sam Soffes Feb 25 '21 at 20:05
6

Erik's solution was awesome, but I had some problems with diacritics (despite my LC_* environment variables being set ostensibly correctly) and noise leaking through on lines of code that actually had dates in them. My sed-fu is poor, so I ended up with this frankenstein snippet with ruby in it, but it works for me flawlessly on 200,000+ LOC, and it sorts the results:

git ls-tree -r HEAD | gsed -re 's/^.{53}//' | \
while read filename; do file "$filename"; done | \
grep -E ': .*text' | gsed -r -e 's/: .*//' | \
while read filename; do git blame "$filename"; done | \
ruby -ne 'puts $1.strip if $_ =~ /^\w{8} \((.*?)\s*\d{4}-\d{2}-\d{2}/' | \
sort | uniq -c | sort -rg

Also note gsed instead of sed because that's the binary homebrew installs, leaving the system sed intact.

gtd
  • 16,956
  • 6
  • 49
  • 65
5

Here is the primary snippet from @Alex 's answer that actually does the operation of aggregating the blame lines. I've cut it down to operate on a single file rather than a set of files.

git blame --line-porcelain path/to/file.txt | grep  "^author " | sort | uniq -c | sort -nr

I post this here because I come back to this answer often and re-reading the post and re-digesting the examples to extract the portion I value it is taxing. Nor is it generic enough for my use case; its scope is for a whole C project.


I like to list stats per file, achived via with a bash for iterator instead of xargs as I find xargs less readable and hard to use/memorize, The advantage/disadvantages xargs vs for should be discussed elsewhere.

Here is a practical snippet that will show results for each file individually:

for file in $(git ls-files); do \
    echo $file; \
    git blame --line-porcelain $file \
        | grep  "^author " | sort | uniq -c | sort -nr; \
    echo; \
done

And I tested, running this stright in a bash shell is ctrl+c safe, if you need to put this inside a bash script you might need to Trap on SIGINT and SIGTERM if you want the user to be able to break your for loop.

Community
  • 1
  • 1
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
  • 1
    `git blame -w -M -C -C --line-porcelain path/to/file.txt | grep -I '^author ' | sort | uniq -ic | sort -nr` Found a slight tweak to the `git blame` [here](https://gist.github.com/amitchhajer/4461043) that more accurately portrays the stats I was looking for. Specifically, the -M and -C -C option (those are two C's on purposes). -M detects moves within file, and -C -C detects copied lines from other files. See doc [here](https://git-scm.com/docs/git-blame). For completeness sake, -w ignores whitespace. – John Lee Mar 08 '19 at 22:00
5

git shortlog -sn

This will show a list of commits per author.

aug
  • 11,138
  • 9
  • 72
  • 93
moinudin
  • 134,091
  • 45
  • 190
  • 216
3

Check out the gitstats command available from http://gitstats.sourceforge.net/

Ivan -Oats- Storck
  • 4,096
  • 3
  • 30
  • 39
2

I adopted the top answer to Powershell:

(git ls-tree -rz --name-only HEAD).Split(0x00) | where {$_ -Match '.*\.py'} |%{git blame -w --line-porcelain HEAD $_} | Select-String -Pattern '^author ' | Group-Object | Select-Object -Property Count, Name | Sort-Object -Property Count -Descending

It's optional on whether you run git blame with the -w switch, I added it because it ignores whitespace changes.

Performance on my machine was in favor of Powershell (~50s vs ~65s for the same repo), although the Bash solution was running under WSL2

Mattwmaster58
  • 2,266
  • 3
  • 23
  • 36
2

This works in any directory of the source structure of the repo, in case you want to inspect a certain source module.

find . -name '*.c' | xargs -n1 git blame --line-porcelain | grep "^author "|sort|uniq -c|sort -nr
Martin G
  • 17,357
  • 9
  • 82
  • 98
1

I have this solution that counts the blamed lines in all text files (excluding the binary files, even the versioned ones):

IFS=$'\n'
for file in $(git ls-files); do
    git blame `git symbolic-ref --short HEAD` --line-porcelain "$file" | \
        grep  "^author " | \
        grep -v "Binary file (standard input) matches" | \
        grep -v "Not Committed Yet" | \
        cut -d " " -f 2-
    done | \
        sort | \
        uniq -c | \
        sort -nr
Gabriel Diego
  • 950
  • 2
  • 10
  • 22
-1

Made my own script which is a combination of @nilbus and @Alex

#!/bin/sh

for f in $(git ls-tree -r  --name-only HEAD --);
do
    j=$(file "$f" | grep -E ': .*text'| sed -r -e 's/: .*//');
    if [ "$f" != "$j" ]; then
        continue;
    fi
    git blame -w --line-porcelain HEAD "$f" | grep  "^author " | sed 's/author //'`enter code here`
done | sort | uniq -c | sort -nr
vossman77
  • 1,397
  • 14
  • 13
-1

Bash function that targets a single source file run on MacOS.

function glac {
    # git_line_author_counts
    git blame -w "$1" |  sed -E "s/.*\((.*) +[0-9]{4}-[0-9]{2}.*/\1/g" | sort | uniq -c | sort -nr
}
jxramos
  • 7,356
  • 6
  • 57
  • 105