Matt Krol


Display git status information in your shell prompt!

Categories: Programming
Tags: Bash Git

I have been using git frequently these days. Recently, I have been on the hunt for a script to display git status information in my bash prompt. This way I can easily see important git repository information in my shell prompt without having to type git status all of the time which would save frequent git users like myself a lot of time. However, many of the existing solutions that I found were either too simplistic or complete overkill for the task at hand, so I decided to create my own.

My implementation prints the name of the current git branch along with some other indicators:

The internals of the script take advantage of the git porcelain command and some relatively simple awk to parse its output. I felt that awk was the right tool for the job since awk made it easy to combine the grep and sed operations that I needed to use into one command. I also avoided the use of bash specific shell scripting features in effort to keep the script POSIX compliant, so given that your system has a POSIX compliant shell and awk, you should be able to use the script without any problems.

git_status() {
    STATUS="$(git status --branch --porcelain=v2 2>/dev/null)"
    if [ -z "$STATUS" ]; then
        return
    fi
    BRANCH="$(echo "$STATUS" | awk '$2 == "branch.head" { print $3 }')"
    DIRTY="$(echo "$STATUS" | awk '$1 ~ /[^#?]+/ { print $0 }')"
    if [ ! -z "$DIRTY" ]; then
        DIRTY_IND='*'
    else
        DIRTY_IND=''
    fi
    UNTRACKED="$(echo "$STATUS" | awk '$1 ~ /\?+/ { print $0 }')"
    if [ ! -z "$UNTRACKED" ]; then
        UNTRACKED_IND='?'
    else
        UNTRACKED_IND=''
    fi
    REMOTE="$(echo "$STATUS" | awk '$2 == "branch.ab" { gsub(/[+-]/, ""); print $3,$4 }')"
    case "$REMOTE" in
        '')
            REMOTE_IND='' ;;
        '0 0')
            REMOTE_IND='=' ;;
        '0 '*)
            REMOTE_IND='<' ;;
        *' 0')
            REMOTE_IND='>' ;;
        *)
            REMOTE_IND='<>' ;;
    esac
    INDICATORS="${UNTRACKED_IND}${DIRTY_IND}${REMOTE_IND}"
    if [ ! -z "$BRANCH" ] && [ ! -z "$INDICATORS" ]; then
        echo -n " (${BRANCH} ${INDICATORS})"
    elif [ ! -z "$BRANCH" ] && [ -z "$INDICATORS" ]; then
        echo -n " (${BRANCH})"
    elif [ -z "$BRANCH" ] && [ ! -z "$INDICATORS" ]; then
        echo -n " (${INDICATORS})"
    fi
}

Here is a snippet of my .bashrc file. I like to keep things tidy by checking to see if git is installed before using the PS1 loaded with the git status information.

export GIT_PS1="\[\033[1;32m\]\u@\h \[\033[1;33m\]\w\[\033[1;35m\]\$(git_status)\[\033[0m\]\n\$ "
export DEFAULT_PS1='\[\033[1;32m\]\u@\h \[\033[1;33m\]\w\[\033[0m\]\n\$ '

if [ -x "$(command -v git)" ]; then
    export PS1=$GIT_PS1
else
    export PS1=$DEFAULT_PS1
fi

Cheers! I hope you enjoy the script.