mirror of
https://github.com/tj/git-extras.git
synced 2026-09-10 23:46:24 -04:00
The output of `git log` is not exactly in chronological order. The
default sort option (--date-order) is described in the man page as
follows:
Show no parents before all of its children are shown, but otherwise
show commits in the commit timestamp order.
The `uniq` program will only remove duplicate lines if they follow each
other. In order for this to work correctly, we need to ensure that the
list of dates is exactly in chronological order. There doesn't seem to
be a `git log` option to achieve this, but we can use the `sort`
program. I used reverse sort (`sort -r`) since the output will be roughly
reverse-sorted already.
It's also worth noting that the default --date-order option sorts by
commit date, but git-summary uses *author* date (%ai). Passing
--author-date-order doesn't fix this issue, though, so I didn't change
that.
At the time of writing, this change reduces the number of 'active days'
for git-extras.git from 367 to 331.
204 lines
3.5 KiB
Bash
Executable file
204 lines
3.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
tmp=$(git_extra_mktemp)
|
|
above=0
|
|
color=
|
|
|
|
#
|
|
# print usage message
|
|
#
|
|
usage() {
|
|
echo 1>&2 "usage: git effort [--above <value>] [<path>...] [-- [<log options>...]]"
|
|
}
|
|
|
|
#
|
|
# get dates for the given <commit>
|
|
#
|
|
dates() {
|
|
eval "git log $args_to_git_log --pretty='format: %ad' --date=short \"$1\""
|
|
}
|
|
|
|
#
|
|
# hide cursor
|
|
#
|
|
|
|
hide_cursor() {
|
|
printf '\033[?25l'
|
|
}
|
|
|
|
#
|
|
# show cursor, and remove temporary file
|
|
#
|
|
|
|
show_cursor_and_cleanup() {
|
|
printf '\033[?25h'
|
|
printf '\033[m\n'
|
|
rm "$tmp" > /dev/null 2>&1
|
|
exit 0
|
|
}
|
|
|
|
#
|
|
# get active days for the given <commit>
|
|
#
|
|
|
|
active_days() {
|
|
echo "$1" | sort -r | uniq | wc -l
|
|
}
|
|
|
|
#
|
|
# set 'color' based on the given <num>
|
|
#
|
|
|
|
color_for() {
|
|
test $1 -gt 10 && color='33'
|
|
test $1 -gt 25 && color='33;1'
|
|
test $1 -gt 50 && color='93'
|
|
test $1 -gt 75 && color='93;1'
|
|
test $1 -gt 100 && color='31'
|
|
test $1 -gt 125 && color='31;1'
|
|
test $1 -gt 150 && color='91'
|
|
test $1 -gt 200 && color='91;1'
|
|
}
|
|
|
|
#
|
|
# compute the effort of the given <path ...>
|
|
#
|
|
|
|
effort() {
|
|
path=$1
|
|
local commit_dates
|
|
commit_dates=`dates "$path"`
|
|
[ $? -gt 0 ] && exit 255
|
|
|
|
# Ensure it's not just an empty line
|
|
if [ -z "`head -c 1 <<<$(echo $commit_dates)`" ]
|
|
then
|
|
exit 0
|
|
fi
|
|
|
|
commits=`wc -l <<<"$(echo "$commit_dates")"`
|
|
color='90'
|
|
|
|
# ignore <= --above
|
|
test $commits -le $above && exit 0
|
|
|
|
# commits
|
|
color_for $(( $commits - $above ))
|
|
len=${#path}
|
|
dot="."
|
|
f_dot="$path"
|
|
i=0 ; while test $i -lt $((45-$len)) ; do
|
|
f_dot=$f_dot$dot
|
|
i=$(($i+1))
|
|
done
|
|
|
|
msg=$(printf " \033[${color}m%s %-10d" "$f_dot" $commits)
|
|
|
|
# active days
|
|
active=`active_days "$commit_dates"`
|
|
color_for $(( $active - $above ))
|
|
msg="$msg $(printf "\033[${color}m %d\033[0m\n" $active)"
|
|
echo "$msg"
|
|
}
|
|
|
|
#
|
|
# print heading
|
|
#
|
|
|
|
heading() {
|
|
echo
|
|
printf " %-45s %-10s %s\n" 'path' 'commits' 'active days'
|
|
echo
|
|
}
|
|
|
|
#
|
|
# output sorted results
|
|
#
|
|
|
|
sort_effort() {
|
|
clear
|
|
echo
|
|
heading
|
|
< $tmp sort -rn -k 2
|
|
}
|
|
|
|
declare -a paths=()
|
|
while [ "${#}" -ge 1 ] ; do
|
|
|
|
case "$1" in
|
|
--above)
|
|
shift
|
|
above=$1
|
|
;;
|
|
--)
|
|
shift
|
|
args_to_git_log=$(printf " %q" "${@:1}")
|
|
break
|
|
;;
|
|
--*)
|
|
usage
|
|
echo 1>&2 "error: unknown argument $1"
|
|
echo 1>&2 "error: if that argument was meant for git-log,"
|
|
echo 1>&2 "error: please put it after two dashes ( -- )."
|
|
exit 1
|
|
;;
|
|
*)
|
|
paths+=( "$1" )
|
|
;;
|
|
esac
|
|
|
|
shift
|
|
done
|
|
|
|
# Exit if above-value is not an int
|
|
if [ -z "${above##*[!0-9]*}" ] ; then
|
|
echo "error: argument to --above was not an integer" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# remove empty quotes that appear when there are no arguments
|
|
args_to_git_log="${args_to_git_log#\ \'\'}"
|
|
export args_to_git_log
|
|
|
|
# [path ...]
|
|
|
|
if test "${#paths}" -eq 0; then
|
|
save_ifs=$IFS
|
|
IFS=`echo -en "\n\b"`
|
|
paths=(`git ls-files`)
|
|
IFS=$save_ifs
|
|
unset save_ifs
|
|
fi
|
|
|
|
# hide cursor
|
|
|
|
hide_cursor
|
|
trap show_cursor_and_cleanup INT
|
|
|
|
# export functions so subshells can call them
|
|
export -f effort
|
|
export -f color_for
|
|
export -f active_days
|
|
export -f dates
|
|
export above
|
|
export log_args
|
|
|
|
|
|
bash_params=
|
|
# If bash exits sucessfully with --import-functions,
|
|
# then we need to pass it (FreeBSD probably)
|
|
bash --import-functions -c ":" 1>/dev/null 2>&1
|
|
if [ $? -eq 0 ] ; then
|
|
bash_params="--import-functions"
|
|
fi
|
|
|
|
heading
|
|
# send paths to effort
|
|
printf "%s\0" "${paths[@]}" | xargs -0 -n 1 -P 4 -I % bash $bash_params -c "effort \"%\"" | tee $tmp
|
|
|
|
# if more than one path, sort and print
|
|
test "$(wc -l $tmp | awk '{print $1}')" -gt 1 && sort_effort
|
|
echo
|
|
|
|
show_cursor_and_cleanup
|