Version Control Display In Shell Prompt

Version control is a neat thing when programming, but I sometimes forget which project uses which system. All of my projects use git, some others use SVN, Mercurial or Bazaar. When I work on the command line, I would like to know whether the current directory is version controlled and which system is used.

One could use a simple ls -A and check whether some .bzr or .git directory is present, but these are only in the root directory of your tree. You could enter git status and see the error message if you were wrong, but that does not help if you use Mercurial and Subversion on your machine as well.

Picking up the idea of looking for .bzr, I wrote a simple Bash function that I put into my .bashrc. Then I added a small \$(scmprompt) into my prompt in my .bashrc.

scmprompt() {
    local cdir=$(pwd)

    while [[ "$cdir" != "/" ]]
    do
        # git
        if [[ -d "$cdir/.git" ]]
        then
            echo " git"
            exit 0
        fi

        # Other rules for the other systems …

        # Go op one dir in the directory tree.
        cdir=${cdir%/*}
        if [[ -z "$cdir" ]]
        then
            cdir="/"
        fi
    done
}

It basically checks for the .git directory (just as you would by hand) and then goes up in the directory tree until it finds a directory. If it finds one, it displays “git” which is then displayed right in the prompt:

martin@iMac:~/Code/scmprompt git $

That way, I know that I used git on this project, and then can use the appropriate commands. You could also beef the script up with some colors, I altered my prompt so that “git” show up in a dark yellow so that it does not draws too much attention. You can do this by wrapping the call to the prompt like this:

\[\033[00;33m\]\$(scmprompt)\[\033[00m\]

__git_ps1

For git, there is a very nice __git_ps1 function, that does this exact thing, but it can also show the status of the working directory.

So now I use my scmprompt function, but for git, I then use the __git_ps1 function instead of a simple git output.

Full Version Of The Function

This is my current version which makes the git repositories look very nice.

#!/bin/bash
# Copyright © 2012 Martin Ueding <dev@martin-ueding.de>

# This script has been placed in the public domain via the CC0 license:
# https://creativecommons.org/publicdomain/zero/1.0/

# Checks the current working directory for a git, bzr (or svn or hg, …) tree
# and displays the apropriate name. If the status is supposed to be displayed,
# a ``bzr status`` is run. Git features the ``__git_ps1``, which is used instead in
# case a git repo is found.
scmprompt() {
	local showstatus=false

	# enable color
	#shopt -s xpg_echo

	local cdir=$(pwd)

	while [[ "$cdir" != "/" ]]
	do
		if [[ "$cdir" = "/home/mu" ]]
		then
			exit 0
		fi

		# git
		if [[ "$(basename "$cdir")" = ".git" ]]
		then
			exit 0
		fi

		if [[ -d "$cdir/.git" ]]
		then
			if type -t __git_ps1 > /dev/null
			then
				echo "$(__git_ps1)"
			else
				echo " git"
			fi
			exit 0
		fi

		# bzr
		if [[ -d "$cdir/.bzr" ]]
		then
			if [[ -d "$cdir/.bzr/branch" ]]
			then
				if [[ $showstatus = 'false' ]]
				then
					echo " bzr"
				else
					if [[ "$(bzr status 2>&1 | wc -l)" -le 1 ]]
					then
						echo " bzr✓"
					else
						echo " bzr"
					fi
				fi
			else
				echo " bzr repo"
			fi
			exit 0
		fi

		# svn
		if [[ -d "$cdir/.svn" ]]
		then
			echo " svn"
			exit 0
		fi

		# mercurial
		if [[ -d "$cdir/.hg" ]]
		then
			echo " hg"
			exit 0
		fi

		# Go up one dir in the directory tree.
		cdir=${cdir%/*}
		if [[ -z "$cdir" ]]
		then
			cdir="/"
		fi
	done
}

You can save this function and the variable declarations somewhere into your .bashrc.

Insert the \$(scmprompt) into the declaration of the PS1 variable to get this displayed into your prompt.

Then enter . ~/.bashrc to reload the config into bash.