Skip to content

Instantly share code, notes, and snippets.

@frxstrem
Last active March 28, 2016 10:49
Show Gist options
  • Save frxstrem/83f7a62a9ec5f85dd060 to your computer and use it in GitHub Desktop.
Save frxstrem/83f7a62a9ec5f85dd060 to your computer and use it in GitHub Desktop.
# custom two-line bash prompt for git users
#
# example (without formatting):
# [12:34] [✔ 0] [1r/2s] [master abcdefgh N] Some Author Commit message
# username@hostname ~/working/directory $
#
# to install, append this to the end of your ~/.bashrc file
#
# features (in order):
# * current time
# * last command exit code (and ✓ or ✗ depending on success or failure)
# * number of jobs in background, running and stopped
# * show information about current git repository:
# * branch name (if on a branch)
# * commit ref
# * GPG signature status of commit (G = good signature, B = bad signature, N/U = no/unknown signature)
# * author name (in bold)
# * commit message
# * username and hostname
# * current working directory
_ps() {
local LAST="$?"
local HEADER="" WARNROW=""
# current time
HEADER+="\e[01;35m[$(date +"%H:%M")]"
# last command
if [[ "$LAST" -eq 0 ]]; then
HEADER+=" \e[01;32m[✔ $(printf '%3d' "$LAST")]"
else
HEADER+=" \e[01;31m[✘ $(printf '%3d' "$LAST")]"
fi
# active jobs
local RUNNING_JOBS="$(jobs -rp | wc -l)"
local STOPPED_JOBS="$(jobs -sp | wc -l)"
HEADER+=" \e[01;36m[${RUNNING_JOBS}r/${STOPPED_JOBS}s]"
# git
# TODO: handle case with initial commit
local GITBRANCH GITREF GITSIG GITMESSAGE
if GITBRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"; then
false
GITREF="$(git log -1 --pretty=format:%h 2>/dev/null)"
GITSIG="$(git log -1 --pretty=format:%G? 2>/dev/null)"
GITAUTHOR="$(git log -1 --pretty=format:%an 2>/dev/null)"
GITMESSAGE="$(git log -1 --pretty=format:%s 2>/dev/null)"
local GITSTATUS="$( git status --untracked-files=all --porcelain 2>/dev/null )"
local GIT_STAGED=0 GIT_CHANGED=0 GIT_CONFLICTS=0 GIT_UNTRACKED=0 GIT_AHEAD=0 GIT_BEHIND=0
# local line
while IFS='' read -r line && [[ -n "$line" ]]; do
local status="${line:0:2}"
case "$status" in
?A|?M|?D|?R|?C) ((GIT_CHANGED++)) ;;
U?) ((GIT_CONFLICTS++)) ;;
\?\?) ((GIT_UNTRACKED++)) ;;
*) ((GIT_STAGED++)) ;;
esac
done <<< "$GITSTATUS"
GIT_AHEAD="$(git rev-list @{u}..HEAD 2>/dev/null | wc -l)"
GIT_BEHIND="$(git rev-list HEAD..@{u} 2>/dev/null | wc -l)"
HEADER+=" \e[00;01;33m["
if [[ -n "$GITBRANCH" && "$GITBRANCH" != "HEAD" ]]; then
HEADER+="$GITBRANCH"
if [[ "$GIT_AHEAD" -gt 0 ]]; then
HEADER+="\e[00;32m+$GIT_AHEAD"
fi
if [[ "$GIT_BEHIND" -gt 0 ]]; then
HEADER+="\e[00;31m-$GIT_BEHIND"
fi
HEADER+=" "
fi
HEADER+="\e[00;33m$GITREF"
case "$GITSIG" in
'G')
HEADER+=" \e[32m$GITSIG\e[01;33m"
;;
'N')
HEADER+=" \e[37m$GITSIG\e[01;33m"
;;
'U')
HEADER+=" \e[31m$GITSIG\e[01;33m"
;;
'B')
HEADER+=" \e[31m$GITSIG\e[01;33m"
;;
*)
;;
esac
HEADER+="]"
local GIT_UPDATED=()
if [[ "$GIT_STAGED" -gt 0 ]]; then
GIT_UPDATED=( "${GIT_UPDATED[@]}" "\e[00;32m${GIT_STAGED}" )
fi
if [[ "$GIT_CONFLICTS" -gt 0 ]]; then
GIT_UPDATED=( "${GIT_UPDATED[@]}" "\e[00;31m${GIT_CONFLICTS}" )
fi
if [[ "$GIT_CHANGED" -gt 0 ]]; then
GIT_UPDATED=( "${GIT_UPDATED[@]}" "\e[00;33m${GIT_CHANGED}" )
fi
if [[ "$GIT_UNTRACKED" -gt 0 ]]; then
GIT_UPDATED=( "${GIT_UPDATED[@]}" "\e[00;37m${GIT_UNTRACKED}" )
fi
if [[ "${#GIT_UPDATED}" -gt 0 ]]; then
HEADER+=" \e[00;01;33m[${GIT_UPDATED[*]}\e[00;01;33m]"
fi
HEADER+=" \e[00;01;33m$GITAUTHOR \e[00;33m$GITMESSAGE"
fi
HEADER+="\e[00m\n"
tput rmam
echo -en "$HEADER"
if [[ -n "$WARNROW" ]]; then
echo -en "$WARNROW"
fi
tput smam
PS1="\[\e[01;32m\]\u@\h\[\e[01;34m\] \w \$\[\e[00m\] "
shopt -u promptvars
}
PROMPT_COMMAND=_ps
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment