Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active May 20, 2019 23:08
Show Gist options
  • Save nilium/2fbe41eca03db202721f4e0047b0d740 to your computer and use it in GitHub Desktop.
Save nilium/2fbe41eca03db202721f4e0047b0d740 to your computer and use it in GitHub Desktop.
Git script to scan diff --numstat output and sum it.
#!/bin/bash
usage() {
cat >&2 <<-'EOF'
Usage: git-instat [range] [path...] [-path pattern...] [-only pattern...] [-omit pattern...]
Print a stat summary for the given paths in a ref.
If no range is given, the default is 'HEAD^1..HEAD'.
-only and -omit may be passed to filter lines of the numstat, such that
only lines containing none of the omitted patterns and all of the 'only'
patterns are the only remaining outputs.
-path arguments are any path pattern accepted by git-diff(1).
EOF
exit 2
}
var=paths
paths=()
only=()
omit=()
ref='HEAD^1..HEAD'
case "${1---}" in
-h|--help) usage;;
-path|-omit|-only) :;;
--) shift;;
*) ref="$1"; shift;;
esac
set -e
push() {
local var="$1"
shift
for arg; do
eval "${var}"'[${#'"${var}"'[@]}]="$arg"'
done
}
noswitch=
for arg; do
shift
case "${noswitch}${arg}" in
-only) var=only; noswitch=x;;
-omit) var=omit; noswitch=x;;
-path) var=paths; noswitch=x;;
*)
push "$var" "$arg"
noswitch=
;;
esac
done
if [ ${#paths[@]} -gt 0 ]; then
paths=(-- "${paths[@]}")
fi
recurse() {
cmd=()
for arg; do
shift
if [ "$arg" = -- ]; then
break
fi
push cmd "$arg"
done
if [ $# -eq 0 ]; then
cat
else
local arg="$1"
shift
"${cmd[@]}" "$arg" | recurse "${cmd[@]}" -- "$@"
fi
}
git diff --numstat "$ref" "${paths[@]}" |
recurse grep --line-buffered -ve -- "${omit[@]}" |
recurse grep --line-buffered -e -- "${only[@]}" |
awk -F $'\t' '
BEGIN { added = deleted = 0 }
{ added += $1; deleted += $2; print $0 }
END { printf "%d\t%d\n", added, deleted }
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment