Last active
November 9, 2021 16:10
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have adapted it in Python, you can see it here: https://gist.github.com/akiavara/51d0d9d302013521bb10