Color Bash Prompt (PS1) with git Integration

December 11, 2015

You’ve seen it in screenshots and guides around the net: colorful custom bash prompts with useful info like what branch you’re currently in and if there are any uncommitted changes. Let’s learn how to make our own custom prompt with git integration!

Screenshot from 2015-12-11 18-17-28

git

Obviously, you will need git installed for this to work. But if you didn’t already use git, then you probably wouldn’t be reading this post so … Anyway, in order for us to add git info to our PS1, we’ll need to find the git-prompt.sh script on your system. On Fedora, it’s located at /usr/share/git-core/contrib/completion/git-prompt.sh, but on Arch it’s at /usr/share/git/completion/git-prompt.sh. If it’s not in either location, then just use the locate command to find it:

sudo updatedb && locate git-prompt.sh

~/.bashrc

Bash looks in a few different places for customizations, but the best place to put yours is usually your ~/.bashrc file. Anything in this file will sourced by Bash when you open a new shell or terminal window. The ~/.bashrc is specific to your user. Other user accounts on the system (like root) won’t source your user’s .bashrc. Learning your way around the .bashrc file is an essential skill for any Linux power-user. There is a lot you can do with it, but we’ll just focus on the PS1, aka the bash prompt.

Most distributions have a simple, default PS1, usually something like this:

user@host $ 

Note: The $ usually indicates that this is an unprivileged user, whereas # denotes the root user

That’s a serviceable prompt, but Bash allows you to customize it to your heart’s content. I’m only going to cover my personal PS1 in this post. If you want something tailored just for your needs and want to create your own custom bash prompt, then a good place to start is the Arch wiki: Color Bash Prompt.

If you just want to use my PS1, then comment out your current PS1 (in case you don’t like the new one and want to go back) and paste the following into your ~/.bashrc

# Simple PS1
#PS1='(\u:\h), \W, '

# Change this to the location of git-prompt.sh on your distribution.
source /usr/share/git-core/contrib/completion/git-prompt.sh

# Creates the bash_prompt function
bash_prompt () {

# Checks to see if the current directory is a git repo or not
gitcheck_branch="$(git branch &>/dev/null; if [ $? -eq 0 ]; then echo "yes"; else echo "no"; fi)"

if [ $gitcheck_branch == "yes" ];
then
        # If we are in a git repo, then check to see if there are uncommitted files
        gitcheck_status="$(git status | grep "nothing to commit" > /dev/null 2>&1; if [ $? -eq 0 ]; then echo "clean"; else echo "unclean"; fi)"

	if [ $gitcheck_status == "clean" ];
	then
                # If there are no uncommitted files, then set the color of the git branch name to green
		git_prompt='\[\033[0;32m\]$(__git_ps1)'
	else
                # If there are uncommitted files, set it to red.
		git_prompt='\[\033[0;31m\]$(__git_ps1)'
	fi
else
        # If we're not in a git repo, then display nothing
	git_prompt=""
fi

# This is what actually sets our PS1. The ${git prompt} is what will display our git status.
PS1="\[\e[0;36m\]┌─\[\e[1;37m\][\u@\h]\[\e[0m\]\[\e[0;36m\]─\[\e[0;93m\](\w)${git_prompt} \n\[\e[0;36m\]└─\[\e[1;32m\][\A]\[\e[0m\]\$(if [[ \$? == 0 ]]; then echo \"\[\033[0;32m\]$\"; else echo \"\[\033[0;31m\]$\"; fi)\[\033[00m\] "

}
# PROMPT_COMMAND is run just before the PS1 is printed. We've set it to run our bash_prompt function.
PROMPT_COMMAND=bash_prompt

The key to all of this working is the PROMPT_COMMAND. Bash will execute whatever the PROMPT_COMMAND is set to just before it prints the PS1, in other words, every time you open a new shell, execute any command yourself, or even just hit the enter key. With the above in your .bashrc, Bash will check to see if the present working directory is a git repo or not. If it is, it will check to see if there are uncommitted files. If there are no uncommitted files, it will append the branch name in green after the working directory in our PS1. If there are uncommitted files, it will append the branch name in red. If the working directory isn’t a git repo, then it will print nothing after the working directory in the PS1.

Oh, I almost forgot to mention. There’s another neat little trick in here that I really appreciate:

\$(if [[ \$? == 0 ]]; then echo \"\[\033[0;32m\]$\"; else echo \"\[\033[0;31m\]$\"; fi)\[\033[00m\]

This bit will check the exit code of last executed command. If it’s zero (successful), then the $ will be green. If the command failed, the $ will be red. Can be handy for commands that don’t tell you whether they succeeded or not.

Screenshot from 2015-12-11 18-18-32

There are of course, other ways to implement something like this. A quick google search will turn up plenty of guides for doing it differently. But ultimately, this is the method that works the best for me. It’s also quite versatile. Having PROMPT_COMMAND call a function that sets the PS1 allows you to do all kinds of conditionals on what your PS1 will look like. You could have different colors for different times of the day, A status indicator for whether you’re connected over ssh or through a local terminal emulator (useful if you have the same .bashrc on all of your remote machines), an indicator for whether you’re connected to your vpn or not. Anything you can do with a bash script, you can put in your PS1.