Quick and easy git branch prompt for zsh (and a quick rant)

Update (2011/12/03): I have since changed my prompt and got a little crazy with it all and took concepts from Phil's zsh prompt and took the git stuff from Brian Carper's site. It's totally going against what I have stated below (wanting something simple), however, I really liked these concepts and here is what I came up with:


So, I have recently moved back to using vim and I have been loving it. I have specifically been using MacVim for mostly everything. However, I have also been using vim on the command line for quick editing. Mainly, I start up MacVim for a project while I just browse the filesystem and edit files as needed from the command line at times.

What I have noticed with my increased use of the command line on OSX is that bash and BSD commands don't play nicely together. For example, the cp and mv commands in OSX (or, any BSD system by default unless you're using GNU Utils, I believe) will copy what is inside of a directory - not the actual directory - if you append a trailing slash. Example:

% cp -r /Users/someguy/whatever/ /Users/otherguy/

This doesn't do what you think it does if you're a long time Linux user. That trailing slash on the end of the from portion of that command tells cp to copy what is inside of the directory. So if /Users/someguy/whatever contains 52 files, those 52 files are going to be copied into /Users/otherguy, not the directory itself.

This is completely annoying if you're used to using tab completion to the path you want to copy or move. In bash, it always appends a / if it's a directory. Sure, you could remove that /, but that's annoying when you're typing fast and in a zone.

Enter zsh! Tab completion in zsh is much more intelligent. It will append that / if it's a directory, but if you stop there and hit enter or space, it will remove that / since it's not needed! Also, it does some fancy stuff when you tab, much like the way vim auto completes when you tab through directories. This is nice.

So, on to my point. I had a nice little color coded prompt in my bash profile that would detect if I was in a directory that was a git repo and tell me what branch I was on. This is super useful for me when I code. This was relatively simple to add thanks to this post about it. However, when I switched off to zsh, I had a little trouble getting this to work. Searching the web I found very many very involved ways of doing this that had very many lines of code in your .zshrc file. Being that I like things short and simple, I reconfigured it. While this may not be as robust as other examples on the net, it works for my purposes, which is to just tell me the branch I'm on if I'm in a git repository. I also added some custom coloring to match a (vim color scheme I use)[https://github.com/gigamo/sunburst.vim]. Here is my entire .zshrc file...

alias ls='ls -G'

# Stuff for git
parse_git_branch () {
    git branch 2> /dev/null | grep "*" | sed -e 's/* \(.*\)/ (\1)/g'

# sunburst.vim like colors for prompt

function precmd() {
    export PROMPT="%{$RED%}%n@%m%{$BLACK%}:%{$GREEN%}%~%{$YELLOW%}$(parse_git_branch)%{$BLACK%}%# "

# System dependent setup stuff goes in here
foreach f (~/.zshrc.d/*); do
    . "$f"

Focus mainly on the precmd function. That's pretty much all there is to it. That function gets run every time, after a command is executed. So I set my prompt in there. If the git branch command shows up, it grabs the current branch you're on and appends it to the prompt. If it isn't available, you just simply don't see it.

The last bit of code should be obvious, but I have two systems I work from. My home laptop and my work laptop. I sync things over Dropbox and Github. However, I don't want all of the same environment variables and such in my .zshrc file at home that I have at work and vice-versa. So, I store those things in a ~/.zshrc.d directory. Everything else that's shared across both systems is in .zshrc.

This works for me. I know there are other ways but this is simple. That's all I wanted. Simple but effective.