Skip to content

Instantly share code, notes, and snippets.

@ezamelczyk
Created June 14, 2019 09:45
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ezamelczyk/78b9c0dd095f8706a3f6a41e8eae0afd to your computer and use it in GitHub Desktop.
Save ezamelczyk/78b9c0dd095f8706a3f6a41e8eae0afd to your computer and use it in GitHub Desktop.
Git count lines by author
#!/bin/sh
git log --shortstat | grep -E "(Author: )(\b\s*([A-Z]\w+)){2}|fil(e|es) changed" | awk '
{
if($1 ~ /Author/) {
author = $2" "$3
} else {
files[author]+=$1
inserted[author]+=$4
deleted[author]+=$6
}
}
END { for (key in files) { print "Author: " key "\n\tfiles changed: ", files[key], "\n\tlines inserted: ", inserted[key], "\n\tlines deleted: ", deleted[key] } }
'
@Y130311-NAV
Copy link

Y130311-NAV commented Aug 6, 2019

When I tried this script on a git repository, at least one Author was missing in the otherwise very nice result.

@FlorianGuhl
Copy link

Yes, for us also many authors were missing, also Lines of Code are not shown with that script.

@matthiasschobner
Copy link

This script count also the merge commits. That's obvious, but unfortunately, it looks like someone's commit a lot, who doesn't. How can i filter by commit name?
--no-merges Doesn't seem to be working.

@gianpaolof
Copy link

gianpaolof commented Oct 31, 2019

hello. That's very nice.
I think it needs a minor correction to handle lowercase names:

git log --shortstat | grep -E "(Author: )(\b\s*([a-zA-Z]\w+)){1,2}|fil(e|es) changed" | awk ' {

@pshri
Copy link

pshri commented May 27, 2020

Thanks. Saved me lot of time. I have made some changes to get logs by month of an year. Added delta of additions and deletions. If no parameters are passed then logs are generated for current month. Invoking script with parameter all generates logs for all commits so far. Also incorporated gianpaolof fix for lowercase names.

#!/bin/bash

#inspired by https://gist.github.com/ezamelczyk/78b9c0dd095f8706a3f6a41e8eae0afd

if [ -z "$1" ]; then
    # Use current month
    set -- "$(date +%b)"
fi

if [ -z "$2" ]; then
    # Use current year
    set -- "$1" "$(date +%Y)"
fi

if [ "$1" != "all" ]; then
    # Filter by month and year
    # previous month as number
    pm=$(date -d "$1 1, $2 -1 month" +%m)
    # previous month as name
    pms=$(date -d "$1 1, $2 -1 month" +%b)
    # last day of previous month
    ld_pm=$(date -d "$pms 1, $2 +1 month -1 day" +%d)
    # next month as number
    nm=$(date -d "$1 1, $2 +1 month" +%m)
    after_year=$2
    before_year=$2
    if [ $pm -eq 12 ]; then
        # Decrement after year if previous month is December
        ((after_year--))
    fi
    if [ $nm -eq 01 ]; then
        # Increment before year if next month is January
        ((before_year++))
    fi
    filter="--after="$after_year-$pm-$ld_pm" --before="$before_year-$nm-01""
    msg="for $1 $2"
else
    # Get all logs
    filter=""
    msg="as of $(date "+%b %Y")"
fi

echo "" ; echo "Generating contribution log $msg ..." ; echo ""

git log --shortstat $filter | grep -E "(Author: )(\b\s*([a-zA-Z]\w+)){1,2}|fil(e|es) changed" | awk '
{
    if($1 ~ /Author/) {
        author = $2" "$3
    }
    else {
        files[author]+=$1
        inserted[author]+=$4
        deleted[author]+=$6
        delta[author]+=$4-$6
    }
}
END { for (key in files) { print "Author: " key "\n\tfiles changed: ", files[key], "\n\tlines inserted: ", inserted[key], "\n\tlines deleted: ", deleted[key], "\n\tlines delta: ", delta[key] } }
'

@justinphelps
Copy link

justinphelps commented Nov 23, 2021

MacOS has their own 'date' utility with different syntax, so I put a test condition in so it will work the same on OSX or Linux.
Requires GNU date: brew install coreutils:

`#!/bin/bash
case $(uname -s) in
Linux*) datecmd=date;;
Darwin*) datecmd=gdate;;
*) datecmd=date;;
esac
#inspired by https://gist.github.com/ezamelczyk/78b9c0dd095f8706a3f6a41e8eae0afd

if [ -z "$1" ]; then
# Use current month
set -- "$(date +%b)"
fi

if [ -z "$2" ]; then
# Use current year
set -- "$1" "$(date +%Y)"
fi

if [ "$1" != "all" ]; then
# Filter by month and year
# previous month as number
pm=$($datecmd -d "$1 1, $2 -1 month" +%m)
# previous month as name
pms=$($datecmd -d "$1 1, $2 -1 month" +%b)
# last day of previous month
ld_pm=$($datecmd -d "$pms 1, $2 +1 month -1 day" +%d)
# next month as number
nm=$($datecmd -d "$1 1, $2 +1 month" +%m)
after_year=$2
before_year=$2
if [ $pm -eq 12 ]; then
# Decrement after year if previous month is December
((after_year--))
fi
if [ $nm -eq 01 ]; then
# Increment before year if next month is January
((before_year++))
fi
filter="--after="$after_year-$pm-$ld_pm" --before="$before_year-$nm-01""
msg="for $1 $2"
else
# Get all logs
filter=""
msg="as of $($datecmd "+%b %Y")"
fi

echo "" ; echo "Generating contribution log $msg ..." ; echo ""

git log --shortstat $filter | grep -E "(Author: )(\b\s*([a-zA-Z]\w+)){1,2}|fil(e|es) changed" | awk '
{
if($1 ~ /Author/) {
author = $2" "$3
}
else {
files[author]+=$1
inserted[author]+=$4
deleted[author]+=$6
delta[author]+=$4-$6
}
}
END { for (key in files) { print "Author: " key "\n\tfiles changed: ", files[key], "\n\tlines inserted: ", inserted[key], "\n\tlines deleted: ", deleted[key], "\n\tlines delta: ", delta[key] } }
'`

@DarenHayward
Copy link

DarenHayward commented Mar 18, 2022

Updated version support for macOS without needing to install gdate utility

#!/bin/bash

#inspired by https://gist.github.com/ezamelczyk/78b9c0dd095f8706a3f6a41e8eae0afd

if [ -z "$1" ]; then
# Use current month
set -- "$(date +%b)"
fi

if [ -z "$2" ]; then
# Use current year
set -- "$1" "$(date +%Y)"
fi

echo "$1 $2"
if [ "$1" != "all" ]; then
# Filter by month and year
case $(uname -s) in
Darwin*)
    # previous month as number
    pm=$(date -j -v$1m -v1d -v$2y -v-1m +%m)
    # previous month as name
    pms=$(date -j -v$1m -v1d -v$2y -v-1m +%b)
    # last day of previous month
    ld_pm=$(date -j -v${pms}m -v1d -v$2y -v+1m -v1d +%b)
    # next month as number
    nm=$(date -j -v$1m -v1d -v$2y -v+1m +%m)
    ;;
*)
    # previous month as number
    pm=$(date -d "$1 1, $2 -1 month" +%m)
    # previous month as name
    pms=$(date -d "$1 1, $2 -1 month" +%b)
    # last day of previous month
    ld_pm=$(date -d "$pms 1, $2 +1 month -1 day" +%d)
    # next month as number
    nm=$(date -d "$1 1, $2 +1 month" +%m)
    ;;
esac
after_year=$2
before_year=$2
if [ $pm -eq 12 ]; then
# Decrement after year if previous month is December
((after_year--))
    fi
    if [ $nm -eq 01 ]; then
# Increment before year if next month is January
((before_year++))
    fi
    filter="--after="$after_year-$pm-$ld_pm" --before="$before_year-$nm-01""
    msg="for $1 $2"
    else
# Get all logs
    filter=""
    msg="as of $($datecmd "+%b %Y")"
    fi

    echo "" ; echo "Generating contribution log $msg ..." ; echo ""

    git log --shortstat $filter | grep -E "(Author: )(\b\s*([a-zA-Z]\w+)){1,2}|fil(e|es) changed" | awk '
{
    if($1 ~ /Author/) {
        author = $2" "$3
    }
    else {
        files[author]+=$1
            inserted[author]+=$4
            deleted[author]+=$6
            delta[author]+=$4-$6
    }
}
END { for (key in files) { print "Author: " key "\n\tfiles changed: ", files[key], "\n\tlines inserted: ", inserted[key], "\n\tlines deleted: ", deleted[key], "\n\tlines delta: ", delta[key] } }
'

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