Skip to content

Instantly share code, notes, and snippets.

@zambonin
Last active November 18, 2020 05:01
Show Gist options
  • Save zambonin/d9398232a694176e1f664521e38a7ef9 to your computer and use it in GitHub Desktop.
Save zambonin/d9398232a694176e1f664521e38a7ef9 to your computer and use it in GitHub Desktop.
Estimates how much time a project has taken according to the commit timeline.
#!/usr/bin/env sh
# shellcheck disable=SC2214
#
# A POSIX-compliant shell script that estimates the number of hours taken to
# create the contents of a Git repository. The heuristic is based on grouping
# bundles of commits according to a certain period limit, accumulating time
# differences between pairs of commits in each bundle, and compensating for its
# first commit with another parametrized quantity. Timestamps are taken from
# the author of the commit.
#
# It accepts three options to customize its behavior, described as follows. The
# last argument must be a valid Git folder, with the current folder as default.
#
# -f, --first-delay=<amount>
# Consider that the first commit of each bundle took <amount> seconds
# to create. The default value is 1800, i.e. half an hour. Note that
# this must be smaller or equal than the amount set by -g, such that
# the bundles do not overlap.
#
# -g, --group-period=<amount>
# Create a new bundle of commits when the difference between two
# timestamps is greater than <amount> seconds. The default value is
# 7200, or two hours.
#
# -p, --pass-options=<options>
# Pass options to git-log(1). Suggested options are
# --author/--committer, --since/--until, --no-merges etc.
#
# Parsing of long options is adapted from https://stackoverflow.com/a/28466267.
FIRST_DELAY=1800
GROUP_TIME=7200
OTHER_OPT="--"
while getopts f:g:p:-: OPT ; do
if [ "$OPT" = "-" ] ; then
OPT="${OPTARG%%=*}"
OPTARG="${OPTARG#$OPT}"
OPTARG="${OPTARG#=}"
fi
case "$OPT" in
f | first-delay ) FIRST_DELAY="${OPTARG:-$FIRST_DELAY}" ;;
g | group-period ) GROUP_TIME="${OPTARG:-$GROUP_TIME}" ;;
p | pass-options ) OTHER_OPT="${OPTARG:-$OTHER_OPT}" ;;
??* ) exit 1 ;;
\? ) exit 2 ;;
esac
done
shift $((OPTIND - 1))
FOLDER="${1:-.}"
: $((DIFF=GROUP_TIME - FIRST_DELAY))
if [ ! -d "${FOLDER}/.git" ] || [ $((DIFF)) -lt 0 ] ; then
cat <<-EOF
Usage: sh ${0##*/} [options] [folder]
-f, --first-delay=<seconds>
-g, --group-period=<seconds>
-p, --pass-options=<options>
EOF
exit 1
fi
git -C "$FOLDER" log --format="%at" "$OTHER_OPT" | sort \
| awk -v first="$FIRST_DELAY" -v threshold="$GROUP_TIME" '
{
diff = $0 - prev;
spent += (diff > threshold) ? first : diff;
prev = $0;
}
END { print spent / 3600 }'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment