Bash prompt with Git and Python virtualenv

On Fedora there is git-prompt.sh script provided by git-core package which allows to extend PS1 prompt with information about GIT repo in current location.

However just overriding PROMPT_COMMAND with __git_ps1() will bring 2 problems:

  • Standard VTE helper command will be overridden as well and integration with teminal some emulators will break (e.g. displaying current location in header bar);
  • Python virtualenv will not show it’s name in the beginning of comman prompt when activated.

Some days ago I wrote a script which takes both these things into account (gist):

__ps1() {
    local undo_color="\[\e[m\]"
    local host_color="\[\e[38;5;153m\]"
    local user_color="\[\e[38;5;172m\]"
    if [ $EUID -eq 0 ]; then
        user_color="\[\e[0;31m\]"
    fi

    echo "[$user_color\u$undo_color@$host_color\h$undo_color \W]"
}

__git_ps1_venv() {
    local pre=$1
    local post=$2

    # Let's only check for a virtual environment if the VIRTUAL_ENV variable is
    # set. This should eek out a little more performance when we're not in one
    # since we won't need to call basename.
    if [ -n "${VIRTUAL_ENV}" ] && [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ]; then
        # The python venv module hard-codes the name of the virtual environment into
        # the activate script for my configuration, so we need to pull it out of
        # VIRTUAL_ENV to have an appropriate prefix. If we're doing that, might has
        # well comment out the hard-coded part and rely on the else in the
        # if-statement that follows it.
        #
        #if [ "x(env) " != x ] ; then
        #    PS1="(env) ${PS1:-}"
        #else

        local venv_color="\[\e[38;5;127m\]"
        local undo_color="\[\e[m\]"

        # This is the else of the if-statement with PS1 replaced with pre.
        # Otherwise, no changes.
        if [ "$(basename "${VIRTUAL_ENV}")" = "__" ] ; then
            # special case for Aspen magic directories
            # see http://www.zetadev.com/software/aspen/
            pre="($venv_color$(basename "$(dirname "${VIRTUAL_ENV}")")$undo_color) ${pre}"
        else
            pre="($venv_color$(basename "${VIRTUAL_ENV}")$undo_color) ${pre}"
        fi
    fi

    GIT_PS1_SHOWCOLORHINTS=true
    GIT_PS1_SHOWDIRTYSTATE=true
    GIT_PS1_SHOWUNTRACKEDFILES=true
    GIT_PS1_SHOWUPSTREAM="auto"

    # Call the actual __git_ps1 function with the modified arguments
    __git_ps1 "${pre}" "${post}"
}

# Fallback if VTE prompt command is unavailable
PROMPT_COMMAND=${PROMPT_COMMAND:='printf "\033]0;${USER}@${HOSTNAME}\007"'}

source /run/host/usr/share/git-core/contrib/completion/git-prompt.sh 2>/dev/null
if command -v __git_ps1 > /dev/null; then
    # If __git_ps1 exist, add it to PROMPT_COMMAND
    PROMPT_COMMAND=$PROMPT_COMMAND';__git_ps1_venv "$(__ps1)" "\\\$ "'
else
    # Otherwise use plain PS1
    PS1="$(__ps1)\\$ "
fi

Put this directy into your ~/.bashrc or to a separate script in /etc/profile.d/git-ps1.sh and then add the following to ~/.bashrc:

# Enable git hints in PS1
source /etc/profile.d/git-ps1.sh

And you will get fancy colored bash prompt with git and venv helpers working correctly with all terminal emulators!

Here’s an example of how it looks for me:

Screenshot of bash prompt