Skip to content

Instantly share code, notes, and snippets.

@ajardin
Last active November 9, 2021 16:10
Show Gist options
  • Save ajardin/b9e0d33ec8c3a3b2874d to your computer and use it in GitHub Desktop.
Save ajardin/b9e0d33ec8c3a3b2874d to your computer and use it in GitHub Desktop.
A bash script that generates a report about contributions to a Git repository.
#!/bin/bash
# ====================================================================================================
# The script below allows to have a quick overview of contributions on a Git repository. Bash 4+ is required.
# Especially useful when we do not have access to graphs like those that we can find on Github.
#
# This script handles three non-mandatory parameters:
# - START is used to keep commits only since the given date (default = 01 Jan 2000).
# - END is used to keep commits only until the given date (default = 01 Jan 2050).
# - MINIMUM is used to define the minimum number of commits in order to appear in the report (default = 10).
# ====================================================================================================
START="${1}" ; END="${2}" ; MINIMUM="${3}"
function define_criteria()
{
if [[ ! -z "${START}" ]]; then
SINCE="--since=\"${START}\""
else
SINCE="--since=\"01 Jan 2000\""
fi
if [[ ! -z "${END}" ]]; then
UNTIL="--until=\"${END}\""
else
UNTIL="--until=\"01 Jan 2050\""
fi
if [[ -z "${MINIMUM}" ]]; then
MINIMUM=10
fi
}
function extract_stats()
{
declare -A AUTHORS_IDENTITY
declare -A RAW_STATS
while read -r LINE; do
if [[ "${LINE}" =~ ^([[:digit:]]+)[[:space:]](.+)[[:space:]]\<(.+)\>$ ]]; then
AUTHOR_COMMITS="${BASH_REMATCH[1]}"
AUTHOR_NAME="${BASH_REMATCH[2]}"
AUTHOR_EMAIL="${BASH_REMATCH[3]}"
if [[ "${RAW_STATS[${AUTHOR_EMAIL}]+isset}" ]]; then
RAW_STATS["${AUTHOR_EMAIL}"]="$(( ${RAW_STATS["${AUTHOR_EMAIL}"]} + ${AUTHOR_COMMITS} ))"
else
AUTHORS_IDENTITY["${AUTHOR_EMAIL}"]="${AUTHOR_NAME}"
RAW_STATS["${AUTHOR_EMAIL}"]="${AUTHOR_COMMITS}"
fi
fi
done <<< "${AUTHORS}"
for AUTHOR_EMAIL in "${!RAW_STATS[@]}"
do
if (( "${RAW_STATS[${AUTHOR_EMAIL}]}" >= "${MINIMUM}" )); then
echo "${RAW_STATS[${AUTHOR_EMAIL}]} ${AUTHORS_IDENTITY[${AUTHOR_EMAIL}]} <${AUTHOR_EMAIL}>"
fi
done | sort -rn
}
function format_report()
{
OUTPUT="\nRank\tName\tEmail\tCommits\tFiles Changed\tInsertions (+)\tDeletions (-)"
OUTPUT+="\tDiff/Commits (~)\tFirst Commit\tLast Commit"
RANK=0
while read -r LINE; do
if [[ "${LINE}" =~ ^([[:digit:]]+)[[:space:]](.+)[[:space:]]\<(.+)\>$ ]]; then
(( RANK+=1 ))
AUTHOR_COMMITS="${BASH_REMATCH[1]}"
AUTHOR_NAME="${BASH_REMATCH[2]}"
AUTHOR_EMAIL="${BASH_REMATCH[3]}"
FILES=0 ; INSERTIONS=0 ; DELETIONS=0
eval $(git log --shortstat --author="${AUTHOR_EMAIL}" "${SINCE}" "${UNTIL}" --no-merges | grep -E "fil(e|es) changed" \
| awk '{ files+=$1; inserted+=$4; deleted+=$6 } END { print "FILES="files, "INSERTIONS="inserted, "DELETIONS="deleted }')
FIRST_COMMIT="`git log --author="${AUTHOR_EMAIL}" "${SINCE}" "${UNTIL}" --no-merges --reverse --pretty=format:%H | head -1`"
FIRST_COMMIT_DATE="`git show -s --format=%ar "${FIRST_COMMIT}"`"
LAST_COMMIT="`git log --author="${AUTHOR_EMAIL}" "${SINCE}" "${UNTIL}" --no-merges --pretty=format:%H | head -1`"
LAST_COMMIT_DATE="`git show -s --format=%ar "${LAST_COMMIT}"`"
OUTPUT+="\n${RANK}\t${AUTHOR_NAME}\t${AUTHOR_EMAIL}\t${AUTHOR_COMMITS}\t${FILES}\t${INSERTIONS}\t${DELETIONS}"
OUTPUT+="\t"$(( (INSERTIONS+DELETIONS) / AUTHOR_COMMITS ))"\t${FIRST_COMMIT_DATE}\t${LAST_COMMIT_DATE}"
fi
done <<< "${REFINED_STATS}"
}
function format_footer()
{
FOOTER="\nThis report has been generated using the "$(tput bold)$(git rev-parse --abbrev-ref HEAD)$(tput sgr0)" branch"
if [[ ! -z "${START}" && ! -z "${END}" ]]; then
FOOTER+=" (commits between ${START} and ${END})"
elif [[ ! -z "${START}" && -z "${END}" ]]; then
FOOTER+=" (commits since ${START})"
elif [[ -z "${START}" && ! -z "${END}" ]]; then
FOOTER+=" (commits until ${END})"
fi
FOOTER+="."
}
define_criteria
AUTHORS="`git shortlog -sne "${SINCE}" "${UNTIL}" --no-merges`"
if [[ ! -z "${AUTHORS}" ]]; then
REFINED_STATS="$(extract_stats)"
if [[ ! -z "${REFINED_STATS}" ]]; then
format_report
echo -e "${OUTPUT}" | column -ts $'\t'
format_footer
echo -e "${FOOTER}"
fi
fi
@akiavara
Copy link

akiavara commented Sep 7, 2015

I have adapted it in Python, you can see it here: https://gist.github.com/akiavara/51d0d9d302013521bb10

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