fakerr.git-recall/git-log
2017-01-14 00:46:10 +01:00

250 lines
5.2 KiB
Bash

#!/usr/bin/env bash
# usage info
usage() {
cat <<EOF
Usage: git log [options]
Options:
-d, --date Number of days.
-a, --author Author name.
-h, --help This message.
-- End of options.
EOF
}
# Global variables
SINCE="1 days ago" # show logs for last day by default
AUTHOR=""
FETCH=false
GIT_FORMAT=""
GIT_LOG=""
COMMITS=""
VERSION="1.0.0"
# Are we in a git repo?
if [[ ! -d ".git" ]]; then
echo "abort: not a git repository." 1>&2
exit 1
fi
# Parse options
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do
case $1 in
-v | --version )
echo $version
exit
;;
-d | --date )
SINCE="$2 days ago"
shift;
;;
-a | --author )
AUTHOR="$2"
shift
;;
-f | --fetch )
FETCH=true
;;
-h | --help )
usage
exit
;;
* )
echo "abort: unknown argument" 1>&2
exit 1
esac
shift
done
if [[ "$1" == "--" ]]; then shift; fi
# Colored output.
function colored() {
GREEN=$(tput setaf 4)
YELLOW=$(tput setaf 3)
NORMAL=$(tput sgr0)
REVERSE=$(tput rev)
}
# Uncolored output.
function uncolored() {
GREEN=""
YELLOW=""
NORMAL=""
REVERSE=""
}
# Enable colors if supported by terminal.
if [[ -t 1 ]] && [[ -n "$TERM" ]] && which tput &>/dev/null && tput colors &>/dev/null; then
ncolors=$(tput colors)
if [[ -n "$ncolors" ]] && [[ "$ncolors" -ge 8 ]] ; then
colored
else
uncolored
fi
else
uncolored
fi
# Set AUTHOR to current user if no param passed or display for all users if param equal to "all".
if [[ ! -n $AUTHOR ]]; then
AUTHOR=$(git config user.name 2>/dev/null)
elif [[ $AUTHOR = "all" ]]; then
AUTHOR=".*"
fi
# Fetch changes before.
if [[ $FETCH = true ]]; then
echo "${GREEN}Fetching changes...${NORMAL}"
git fetch --all &> /dev/null
tput cuu1
tput ed # clear screen
fi
# Log template.
GIT_FORMAT="%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset"
# Log command.
GIT_LOG="git log --pretty=format:'${GIT_FORMAT}'
--author \"$AUTHOR\"
--since \"$SINCE\" --abbrev-commit"
# Change temporary the IFS to store GIT_LOG's output into an array.
IFS=$'\n'
COMMITS=($(eval ${GIT_LOG} 2>/dev/null))
unset IFS
NI=${#COMMITS[@]} # Total number of items.
SN=$(( `tput lines` - 1 )) # Screen number of lines.
TN=$(( $NI < $((SN -1)) ? $NI : $((SN -1)))) # Number of lines that we will display.
# If there is no items, exit.
[[ $NI = 0 ]] && echo "${YELLOW}The contributor \"${AUTHOR}\" did nothing during this period.${NORMAL}" && exit 0
# Set keys.
au="`echo -e '\e[A'`" # arrow up
ad="`echo -e '\e[B'`" # arrow down
ec="`echo -e '\e'`" # escape
nl="`echo -e '\n'`" # newline
## Get commit's diff.
function get_diff() {
ELT="$(echo "${COMMITS[$CP-1]}" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")" # remove colors escape codes
DIFF_TIP=${ELT:0:7}
DIFF_CMD="git show $DIFF_TIP --color=always"
DIFF=$(eval ${DIFF_CMD} 2>/dev/null)
DIFF_LINES_NUMBER="$(echo "$DIFF" | wc -l)"
}
## This function will print the diff according the commit's tip. If the diff is too long, the result will be displayed using 'less'.
function print_diff() {
get_diff
if [[ $(( TN + DIFF_LINES_NUMBER )) -ge $(( `tput lines` - 1 )) ]]; then
echo -e "$REVERSE ${COMMITS[$CP - 1]}\n\n $DIFF" | less -r
else
stop=false
tput ed
for i in `seq 1 $TN`
do
echo -n "$NORMAL"
[[ $CP == $i ]] && echo -n "$REVERSE"
echo "${COMMITS[$i - 1]}"
if [[ $CP == $i ]]; then
echo "$DIFF"
fi
done
while ! $stop
do
read -sn 1 key
case "$key" in
"$nl")
stop=true
;;
"q")
stop=true
END=true
;;
esac
done
[[ $END = false ]] && tput cuu $(( TN + DIFF_LINES_NUMBER )) && tput ed
[[ $END = true ]] && tput cuu 1
fi
}
{ # capture stdout to stderr
tput civis # hide cursor.
CP=1 # current position
SI=1 # index
END=false # end while loop
## Loops, reads inputs and prints commits until user presses 'q' to exit or TAB to show the diff.
while ! $END
do
for i in `seq $SI $(( $TN + $SI -1 ))`
do
echo -n "$NORMAL"
[[ $CP == $i ]] && echo -n "$REVERSE"
echo "${COMMITS[$i - 1]}"
done
read -sn 1 key
[[ "$key" == "$ec" ]] &&
{
read -sn 2 k2
key="$key$k2"
}
case "$key" in
"$au")
CP=$(( CP - 1 ))
[[ $CP == 0 ]] && [[ $SI=1 ]] && [[ $TN == $(( SN - 1 )) ]] && CP=$NI && SI=$(( NI - SN + 2 ))
[[ $CP == 0 ]] && [[ $SI=1 ]] && [[ $TN == $NI ]] && CP=$TN
[[ $CP == $(( SI - 1 )) ]] && [[ $SI != 1 ]] && SI=$(( SI - 1 ))
tput cuu $TN
[[ $SI != 1 ]] && tput ed # clear screen
;;
"$ad")
CP=$(( CP + 1 ))
[[ $CP == $(( NI + 1 )) ]] && CP=1 && SI=1
[[ $CP == $(( SN + SI - 1)) ]] && [[ $TN == $(( SN - 1 )) ]] && SI=$(( SI + 1 ))
tput cuu $TN
[[ $SI != 1 ]] && tput ed # clear screen
[[ $SI = 1 ]] && [[ $CP = 1 ]] && tput ed # clear screen
;;
"$nl")
tput cuu $TN
print_diff
;;
"q")
si=false
END=true
tput cuu 1
;;
* )
tput cuu $TN
esac
done
tput cnorm # unhide cursor
echo "$NORMAL" # normal colors
} >&2 # END capture