Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Created November 5, 2012 21:35
Show Gist options
  • Save xeoncross/4020489 to your computer and use it in GitHub Desktop.
Save xeoncross/4020489 to your computer and use it in GitHub Desktop.
Git - calculate how many lines of code were added/changed by someone
# Run this in the project repo from the command-line
# http://stackoverflow.com/a/4593065/99923
git log --shortstat --author "Xeoncross" --since "2 weeks ago" --until "1 week ago" | grep "files changed" | awk '{files+=$1; inserted+=$4; deleted+=$6} END {print "files changed", files, "lines inserted:", inserted, "lines deleted:", deleted}'
@felixbuenemann
Copy link

You can replace grep "files changed" | awk '{… with awk '/files changed/ {..., that way one less process is needed.

@sastorsl
Copy link

sastorsl commented Jun 3, 2019

Thanks a lot for this!
Expanded on your idea and came up with this to count across projects:

for i in */.git
do
    (cd ${i%/*}
    git log --shortstat --author "Xeoncross" | awk '
        BEGIN { f=0 ; i=0 ; d=0 }
        /files? changed/ {f+=$1; i+=$4; d+=$6}
        END { printf("files changed: %4i - lines inserted: %6i lines deleted: %6i - %s\n", f, i, d, p) }' p=${i%/*}
    )
done | awk '
    { f+=$3 ; i+=$7 ; d+=$10 ; print }
    END { print "----" ; printf("files changed: %4i - lines inserted: %6i lines deleted: %6i - %s\n", f, i, d, "Total") }'

Also updated "files changed" to "files? changed" which will match both "file changed" and "files changed".

@jamiehaywood
Copy link

Just another improvement on this:

author="YourAuthorHere"
for i in */.git
do
    (cd ${i%/*}
    git log --shortstat --author $author | awk '
        BEGIN { f=0 ; i=0 ; d=0 }
        /files? changed/ {f+=$1; i+=$4; d+=$6}
        END { printf("files changed: %4i - lines inserted: %6i lines deleted: %6i - %s\n", f, i, d, p) }' p=${i%/*}
    )
done | awk '
    { f+=$3 ; i+=$7 ; d+=$10 ; print }
    END { print "----" ; printf("files changed: %4i - lines inserted: %6i lines deleted: %6i - %s\n", f, i, d, "Total") }'

@SheldonWangRJT
Copy link

or just make a function and put into bash profile

function gline() {
	cd path/to/your/repo
	git log --shortstat --author $1 --since "10 years ago" --until "1 week ago" | grep "files changed" | awk '{files+=$1; inserted+=$4; deleted+=$6} END {print "files changed", files, "lines inserted:", inserted, "lines deleted:", deleted}'
}

and then you can do
gline YourName

@kirhgoff
Copy link

kirhgoff commented Jun 17, 2020

It misses commits where only 1 file was changed:
1 file changed, 3 insertions(+), 2 deletions(-)

could modify grep part as
egrep "file[s]* changed"

@lack3r
Copy link

lack3r commented Sep 11, 2020

Very good try. However, the command does not produce correct results.
First, it can misinterpret deletions as additions.
Please consider the following stat:
2 files changed, 2 deletions(-)
In case a commit does not have any additions, but only removals, as the one shown above, the number of lines removed will be added to the total of the lines added.
Given the example provided above, the command will report that 2 lines were added, and 0 were deleted, while in fact, it was the opposite.
Second, it misses the commits where 1 file was changed as mentioned by @kirhgoff.

@neuged
Copy link

neuged commented Dec 9, 2021

To address @lack3r 's valid concerns, you can insert '0 insertions ', e.g.: sed 's/changed, \([0-9]\+ deletions\)/changed, 0 insertions(+), \1/g'.

Together with @kirhgoff 's modified grep, this gives us:

git log --shortstat --author "user"  \
    | egrep "file[s] changed" \
    | sed 's/changed, \([0-9]\+ deletions\)/changed, 0 insertions(+), \1/g' \
    | awk '{files+=$1; inserted+=$4; deleted+=$6} END {print "files changed", files, "lines inserted:", inserted, "lines deleted:", deleted}'

@xresch
Copy link

xresch commented Feb 16, 2022

@neuged: Changes to your command:

  • Added missing asterisk to egrep
  • added since and until parameters
git log --shortstat --author "username"  --since "5 days ago" --until "today" \
    | egrep "file[s]* changed" \
    | sed 's/changed, \([0-9]\+ deletions\)/changed, 0 insertions(+), \1/g' \
    | awk '{files+=$1; inserted+=$4; deleted+=$6} END {print "files changed", files, "lines inserted:", inserted, "lines deleted:", deleted}'

@RobinBastiaan
Copy link

How do I make an alias of this? Because we use both ' and ", I do not know a syntax to get a valid command. This is what I have now:

git config --global alias.my-contribution "!git log ..."

@fedemengo
Copy link

building on the previous solutions, if you want to skip certain files you can add -- ':!pattern'

git log --stat 0000000..HEAD -- ':!*test.go' | rg "files changed" | awk ...

@FL33TW00D
Copy link

FL33TW00D commented Jul 2, 2024

Alias for ZSH folks:

alias pastmonth="git log --shortstat --author \"FL33TW00D\" --since \"31 days ago\" --until \"today\" | \
  grep -E \"file[s]* changed\" | \
  sed -E 's/changed, ([0-9]+) deletions/changed, 0 insertions(+), \1 deletions/g' | \
  awk '{files+=\$1; inserted+=\$4; deleted+=\$6} END {print \"files changed\", files, \"lines inserted:\", inserted, \"lines deleted:\", deleted}'"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment