Skip to content

Instantly share code, notes, and snippets.

@ysim
Last active March 9, 2018 19:49
Show Gist options
  • Save ysim/845d8d2140c6d73dce8caff64331b829 to your computer and use it in GitHub Desktop.
Save ysim/845d8d2140c6d73dce8caff64331b829 to your computer and use it in GitHub Desktop.
A bash prompt for your git status and more.
#!/bin/bash
# DESCRIPTION:
# You might find this bash prompt useful if you make regular use of Git and
# virtualenv.
#
# FEATURES:
# - Displays any activated virtualenv.
# - Displays the username and current working directory.
# - Displays the current git branch, as well as the number of commits to
# pull (red) or push (green). The colour of the branch name will also change
# depending on whether your working directory is clean (grey), has untracked
# files with no other modifications (light blue), has unstaged changes
# (yellow), has changes to be committed (dark orange), or if your local
# branch has diverged from the remote (red).
# - The prompt symbol is highlighted in red if the exit code of the last
# command was anything other than 0.
#
# INSTRUCTIONS:
# 1. Either move or symlink this file to ~/.bash_prompt
# 2. Add `source ~/.bash_prompt` to ~/.bash_profile or ~/.bashrc
#
# NOTES:
# - The number of commits will not appear if you do not have an upstream
# branch set for the current branch in your .gitconfig.
#
# ACKNOWLEDGEMENTS:
# - https://gist.github.com/insin/1425703
# colour codes
NONE="\[\033[0m\]"
RED="\[\033[0;31m\]"
GREEN="\[\033[0;32m\]"
YELLOW="\[\033[0;33m\]"
BLUE="\[\033[0;34m\]"
PURPLE="\[\033[0;35m\]"
LIGHT_BLUE="\[\033[0;36m\]"
LIGHT_GREY="\[\033[0;37m\]"
# 256 colour support
function fg_colour { echo -ne "\[\033[38;5;$1m\]"; }
function bg_colour { echo -ne "\[\033[48;5;$1m\]"; }
function set_titlebar {
case $TERM in
xterm*)
TITLEBAR='\[\033]0;\w\007\]'
;;
*)
TITLEBAR=""
;;
esac
}
function set_virtualenv {
if [[ -z "$VIRTUAL_ENV" ]] ; then
VIRTUALENV=""
else
VIRTUALENV="${LIGHT_GREY}{`basename \"$VIRTUAL_ENV\"`}"
export PYLIB="$(python -c "import distutils; print distutils.sysconfig.get_python_lib()")"
fi
}
function set_username {
USERNAME="${GREEN}\u"
}
function set_current_working_directory {
CWD="${LIGHT_GREY}\w"
}
# returns 0 if the current directory is a git repository
function is_git_repository {
git branch &> /dev/null
}
# set current git branch
function set_git_branch {
branch_name="$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')"
git_status="$(git status 2> /dev/null)"
if [[ ${git_status} =~ "Changes to be committed" ]] || [[ ${git_status} =~ "Unmerged paths" ]] ; then
branch_colour="${RED}"
elif [[ ${git_status} =~ "Changes not staged for commit" ]] ; then
branch_colour="${YELLOW}"
elif [[ ${git_status} =~ "Untracked files" ]] ; then
branch_colour="${LIGHT_BLUE}"
else
branch_colour="${LIGHT_GREY}"
fi
# The hyphen in the pattern for the branch name needs to be at the
# beginning of the pattern so that it isn't interpreted as a range,
# as in a-z.
# See this for more information on the restrictions on naming git branches:
# https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
remote_pattern="Your branch is (.*) '([a-zA-Z0-9_-]+)/([-a-zA-Z0-9_.]+)' by ([0-9]+) commit"
if [[ ${git_status} =~ ${remote_pattern} ]] ; then
commits="${BASH_REMATCH[4]}"
if [[ "${BASH_REMATCH[1]}" == "ahead of" ]] ; then
branch_status=" ${GREEN}${commits}↑"
else
branch_status=" ${RED}${commits}↓"
fi
else
branch_status=""
fi
# if your local branch and the remote branch have diverged, make it red
diverge_pattern="Your branch and '([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)' have diverged"
if [[ ${git_status} =~ ${diverge_pattern} ]] ; then
diverge_detail="and have ([0-9]+) and ([0-9]+) different commit(s)? each, respectively."
if [[ ${git_status} =~ ${diverge_detail} ]] ; then
local_branch="${BASH_REMATCH[1]}"
remote_branch="${BASH_REMATCH[2]}"
fi
branch_colour="${RED}"
branch_status=" ${local_branch}↕${remote_branch}"
fi
if [[ ! "$branch_name" ]] ; then
branch_name='NO BRANCH'
if [[ ! "$(git remote -v)" ]] ; then
branch_name='NO REMOTE'
fi
branch_colour="${PURPLE}"
fi
GIT_BRANCH="${branch_colour}(${branch_name}${branch_status}${branch_colour})"
}
function set_prompt_symbol {
if [[ $1 -eq 0 ]] ; then
PROMPT_SYMBOL="${NONE}\$"
else
PROMPT_SYMBOL="${RED}[$1]\$"
fi
}
function set_bash_prompt {
# get return value of last command
set_prompt_symbol $?
# set the TITLEBAR variable
set_titlebar
# set the VIRTUALENV variable
set_virtualenv
# set the USERNAME variable
set_username
# set the CWD (current working directory) variable
set_current_working_directory
if is_git_repository ; then
set_git_branch
else
GIT_BRANCH=""
fi
export PS1="${TITLEBAR}${VIRTUALENV}${USERNAME}:${CWD}${GIT_BRANCH}${PROMPT_SYMBOL}${NONE} "
export PS2="${LIGHT_BLUE}>${NONE} "
}
# An environment variable provided by bash. The contents of this variable
# are executed as a regular bash command just before bash displays a prompt.
PROMPT_COMMAND=set_bash_prompt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment