A git-aware prompt (part2)

It seems I've been doing some unnecessary stuff in my previous post. Once again, when one tries to do something, he should always remember that someone most probably already had the same idea :-)

Someone pointed to me in the comments that Git already provided a way to have a Git-aware prompt in Bash. Here is an attempt to explain how to use it to have the same result as my previous attempt at scripting it.

One would only need to set the following in their ~/.bashrc file:

PS1='[\u@\h \W]$(__git_ps1 " (%s)")\\$ '

This gives you the following prompt:

[mathieu@localhost ~]$
[mathieu@localhost rpmbuild] (master)$

As you can see, when you enter a Git repository, your prompt displays the name of the current branch.

But that's not quite enough. One might want to show the current changes, to help with their workflow. Just add the following in your ~/.bashrc file, right above the previous line:

export GIT_PS1_SHOWDIRTYSTATE=true

Now, your prompt will look like this:

[mathieu@localhost rpmbuild] (master)$ echo "titi" > SPECS/dummy.spec
[mathieu@localhost rpmbuild] (master*)$ git add SPECS/dummy.spec
[mathieu@localhost rpmbuild] (master+)$ git commit
[mathieu@localhost rpmbuild] (master)$

The above should be pretty self-explainatory, but in case you didn't get it:

  • prompt displays the name of the current branch
  • a file was modified, the prompt displays a *
  • the modified file was staged, the * becomes a +
  • staged file was commited, there are no more changes (either staged or unstaged) in the working dir, prompt goes back to only displaying the branch name.

That's better, but something is still missing compared to what I had written:

[mathieu@localhost rpmbuild] (master)$ touch foobar
[mathieu@localhost rpmbuild] (master)$

That's right, untracked files are not shown on the prompt!

The solution came from a second comment on my previous post. All that is necessary is to add the following in your ~/.bashrc file:

export GIT_PS1_SHOWUNTRACKEDFILES=true

Now, you'll get:

[mathieu@localhost rpmbuild] (master)$ touch foobar
[mathieu@localhost rpmbuild] (master%)$

That's it! The exact same fonctionality as what I had hacked in an ugly way, with only the following 3 lines:

export GIT_PS1_SHOWDIRTYSTATE=true
export GIT_PS1_SHOWUNTRACKEDFILES=true
PS1='[\u@\h \W]$(__git_ps1 " (%s)")\\$ '

Nice isn't it? :)

Remark 1: the env vars GIT_PS1_SHOWDIRTYSTATE and GIT_PS1_SHOWUNTRACKEDFILES only need to be set to something not empty. I used true because it kinda made sense, but setting them to iamagitn00bz would produce the exact same result.

Remark 2: Fedora 11 comes with Git 1.6.2.5 which doesn't support GIT_PS1_SHOWUNTRACKEDFILES in the bash completion script it ships. To make the above work I simply grabbed the file from the Rawhide Git 1.6.4 package. You could alternatively take it in the Git Git repository.

Remark 3: as mentioned in the comments on my previous blog article, there also is the GIT_PS1_SHOWSTASHSTATE env var that can be used to display other things in your prompt. This article was only about replicating the behavior I described before, and this variable is not part of it. But go play with it yourself :)