asemanfar - a blog about programming

Current Git Branch in Bash Prompt

April 12, 2008

Earlier today, my roommate and I were enjoying our afternoon watching the TextMate for Rails 2 Peepcode and I noticed that in the bash prompt, the current branch was shown in parenthesis. I thought this was a wonderful idea and thought I'd add it to my own bash prompt.

Update: Some much better alternative methods have been posted in the comments, please take a look below.

Here is the code to do it:

   1  export PS1="\[\033[38m\]\u@\h\[\033[01;34m\] \w \[\033[31m\]\`ruby -e \"print (%x{git branch 2> /dev/null}.grep(/^\*/).first || '').gsub(/^\* (.+)$/, '(\1) ')\"\`\[\033[37m\]$\[\033[00m\] "

This will make your bash prompt look like this:

   1  user@hostname currentDirectory (branch name) $

The important part of the PS1 in the first code snippet is this:

   1  # this goes somewhere in your PS1 (it'll make the branch name red)
   2  \[\033[31m\]\`ruby -e \"print (%x{git branch 2> /dev/null}.grep(/^\*/).first || '').gsub(/^\* (.+)$/, '(\1) ')\"\`\[\033[37m\]

I decided to try to do this with sed and not ruby. I came up with this:

   1  export PS1="...\`git branch 2> /dev/null | grep -e ^* | sed -E  s/^\\\\\\\\\*\ \(.+\)$/\(\\\\\\\\\1\)\ /\`\[\033[37m\]$\[\033[00m\] "
   2  # no, your browser is not having rendering issues
   3  # there seriously are that many backslashes

Other than the disgusting backslashes, it's pretty nice. If you use single quotes on the outside instead of double, you can lose a few backslashes:

   1  export PS1='...`git branch 2> /dev/null | grep -e ^* | sed -E  s/^\\\\\*\ \(.+\)$/\(\\\\\1\)\ /`\[\033[37m\]$\[\033[00m\] '

Comments

posted by Evgeny on 04/14/08 01:19 AM PDT

Mine:

   1  PS1='\[\033[00;32m\]\u\[\033[01m\]@\[\033[00;36m\]\h\[\033[01m\]:\[\033[00;35m\]\w\[\033[00m\]\[\033[01;30m\](`git branch 2>/dev/null|tr -d \*\ `)\[\033[00m\]\$ '
posted by Arya Asemanfar on 04/14/08 01:36 AM PDT

Evgeny,

Your solution doesn't work quite the same way. git branch outputs every local branch, so your solution would list all the branches, not just the current one.

So to fix that, you can pipe git branch through grep:

   1  git branch 2>/dev/null|grep -e ^* | tr -d \*\

Also, your solution includes the parenthesis regardless if you're in a git directory or not.

I'm sure there is a better way to do what I'm doing using sed or awk, but I'm not well-versed in either so I stuck to ruby.

Update: I took a stab at it in sed. (see bottom of post)

posted by adam on 04/14/08 02:50 AM PDT

There is already a function to do this in the git distribution. If you check out the source there is a directory called contrib which has a bash completion file that gives you a __git_ps1 function.

Then you can just put \$(__git_ps1) somewhere in your PS1 and get the current branch. It doesn't output anything when you're not in a git directory. It also gives you branch name and subcommand tab completion.

posted by Philip Hofstetter on 04/14/08 04:03 AM PDT

this ends up in my ZSH prompt, but it should work for bash too and comes with as few backslashes as possible, which makes it even readabel:

   1  git_branch=`git branch 2>/dev/null | grep -e '^*' | sed -E 's/^\* (.+)$/(\1) /'`
   2    PS1="... $git_branch$path_prompt ..."

Philip

posted by Philip Hofstetter on 04/14/08 04:35 AM PDT

I've adapted the solution to work without any backslashes in a ZSH prompt theme environment.

Here's my take on this:

http://www.gnegg.ch/2008/04/git-branch-in-zsh-prompt/

Philip

posted by Timothy Johnson on 04/14/08 05:04 AM PDT

Here is mine

   1  parse_git_branch() {
   2    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
   3  }
   4  PS1="\w\$(parse_git_branch) $ "
posted by Rodrigo Urubatan on 04/14/08 05:47 AM PDT

I used a cut because the original solution was inclusing all branches upto the one I was working on, and one line break for each too ... the "cut version" is:

   1  git branch 2>/dev/null|cut -f2 -d\* -s
posted by Nathan Weizenbaum on 04/14/08 07:48 AM PDT

I've been doing the same thing, but I've found that

   1  git name-rev

tends to give more detailed output when you aren't on a branch (e.g. try checking out master^). The code I use is:

   1  git name-rev HEAD 2> /dev/null | awk "{ print \\$2 }"

I actually nabbed that code from someone else's bashrc a while ago, but I forgot to save a link and so can't give credit, unfortunately.

posted by Eric Goodwin on 04/14/08 10:51 AM PDT

If you use the auto completion script that come with Git, you get the auto complete functionality plus the __git_ps1 method that Adam mentioned above. You can place the __git_ps1 method in your PS1 and get the branch name in your prompt. I've got a short tutorial on getting it working on OS X at http://blog.ericgoodwin.com/2008/4/10/auto-completion-with-git.

Eric

posted by Jeremy Friesen on 04/14/08 05:41 PM PDT

Well that was somewhat botched. Here it goes In ~/.bashrc

   1  parse_git_branch() {
   2    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(git::\1)/'
   3  }
   4  parse_svn_branch() {
   5    parse_svn_url | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | awk -F / '{print "(svn::"$1 "/" $2 ")"}'
   6  }
   7  parse_svn_url() {
   8    svn info 2>/dev/null | grep -e '^URL*' | sed -e 's#^URL: *\(.*\)#\1#g '
   9  }
  10  parse_svn_repository_root() {
  11    svn info 2>/dev/null | grep -e '^Repository Root:*' | sed -e 's#^Repository Root: *\(.*\)#\1\/#g '
  12  }
  13  export PS1="\[\033[00m\]\u@\h\[\033[01;34m\] \w \[\033[31m\]\$(parse_git_branch)\$(parse_svn_branch) \[\033[00m\]$\[\033[00m\] "

For git directories

   1  jeremyf@jnf ~/ccs_portal (git::master) $

For svn directories

   1  jeremyf@jnf ~/ccs_main/app/controllers (svn::ccs_main/trunk) $
posted by Geoffrey Grosenbach on 04/15/08 07:49 PM PDT

Thanks for the plug!

I first learned it here:

http://acts.as.streeteasy.com/archives/2007/12/19/git_in_your_prompt/

posted by Rob Olson on 04/18/08 03:40 PM PDT

After reading this post I switched over to the __git_ps1 method.

   1  export PS1='\[\033[01;32m\]\h\[\033[01;34m\] \w\[\033[31m\]$(__git_ps1 "(%s)") \[\033[01;34m\]$\[\033[00m\] '

The relevant part being...

   1  $(__git_ps1 "(%s)")
posted by Eddy Petrisor on 08/21/08 06:18 AM PDT

the 'grep | sed' part can be avoided and implemented in a single sed:

   1  parse_git_branch ()
   2  {
   3  	git name-rev HEAD 2> /dev/null | sed 's#HEAD\ \(.*\)#(git::\1)#'
   4  }
   5  parse_svn_branch() {
   6  	parse_svn_url | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | awk -F / '{print "(svn::"$1 "/" $2 ")"}'
   7  }
   8  parse_svn_url() {
   9  	svn info 2>/dev/null | sed -ne 's#^URL: ##p'
  10  }
  11  parse_svn_repository_root() {
  12  	svn info 2>/dev/null | sed -ne 's#^Repository Root: ##p'
  13  }
posted by Geoffrey Grosenbach on 11/26/08 08:56 PM PST

I've since added a Unicode skull and crossbones when I'm in a branch with uncommitted changes:

http://www.scrnshots.com/users/topfunky/screenshots/89842

posted by Leonid Volnitsky on 04/16/09 04:37 AM PDT

branch, status and changed files: http://volnitsky.com/project/git-prompt

posted by Simon Oosthoek on 06/30/09 04:27 AM PDT

Thanks for the useful hints here, I tried to make a version that changes colour depending on the state of the git tree (green for no changes, red for uncommitted changes). I had a hard time getting the colours right, but I finally found out how to do it (I'm using the bash):

   1  c_red='^[[31m'
   2  c_green='^[[32m'
   3  c_sgr0='^[[00m'
   4  
   5  parse_git_branch ()
   6  {
   7          if git rev-parse --git-dir >/dev/null 2>&1
   8          then
   9                  gitver=$(git branch 2>/dev/null| sed -n '/^\*/s/^\* //p')
  10                  if git diff --quiet 2>/dev/null >&2 
  11                  then
  12                          gitver=${c_green}$gitver${c_sgr0}
  13                  else
  14                          gitver=${c_red}'!'$gitver${c_sgr0}
  15                  fi
  16          else
  17                  return 0
  18          fi
  19          echo $gitver
  20  }
  21  
  22  export PS1="\u@\h:\w \$(parse_git_branch)\$ "

NB: the colour codes are ANSI terminal codes with a REAL escape code in ASCII value.

Just for reference, I found this page with a good description of the colours: http://ascii-table.com/ansi-escape-sequences.php

Before I set the git branch version, I first test (line 7) whether I'm in a git managed tree.

Cheers

Simon

posted by Mike Green on 07/22/09 05:50 PM PDT

So I've added the __git_ps1 function to my PS1 bash variable, but it only runs once (when the shell is started). Is there a way to make this refresh every time a command is run? Right now it will still say "(master)" even when I leave a repo's folder and cd to a non-git folder.

posted by Arya Asemanfar on 07/22/09 09:32 PM PDT

Mike,

It's only running once because it's evaluating at that time. You can stop that by either using single quotes instead of double, or using a backslash before the $.

I hope that works out for you.

posted by hron84 on 07/31/09 08:20 AM PDT

@Mike: or, you can make a function, and pass this functions name to PROMPT_COMMAND variable. From this function, you can update xterm terminal title too, like:

   1  echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\007"
posted by matt on 03/11/10 03:46 PM PST

Simon, did you resolve the command prompt line-wrap issue that arises due to the escape codes?

posted by Mikko Nylén on 07/08/10 07:32 PM PDT

@Simon: I took the liberty to modify your version a bit, because the colors in your version weren't working for me. This version uses tput setaf to determine the ASCII color codes. It also does some tricks to avoid the problem with line wrapping when writing longer lines.

Tested on Mac OS X Terminal on Snow Leopard.

   1  c_cyan=`tput setaf 6`
   2  c_red=`tput setaf 1`
   3  c_green=`tput setaf 2`
   4  c_sgr0=`tput sgr0`
   5  
   6  
   7   
   8  parse_git_branch ()
   9  {
  10    if git rev-parse --git-dir >/dev/null 2>&1
  11    then
  12            gitver=$(git branch 2>/dev/null| sed -n '/^\*/s/^\* //p')
  13    else
  14            return 0
  15    fi
  16    echo -e $gitver
  17  }
  18  
  19  branch_color ()
  20  {
  21          if git rev-parse --git-dir >/dev/null 2>&1
  22          then
  23                  color=""
  24                  if git diff --quiet 2>/dev/null >&2 
  25                  then
  26                          color="${c_green}"
  27                  else
  28                          color=${c_red}
  29                  fi
  30          else
  31                  return 0
  32          fi
  33          echo -ne $color
  34  }
  35  
  36  PS1='[\[$(branch_color)\]$(parse_git_branch)\[${c_sgr0}\]] \u@\[${c_red}\]\w\[${c_sgr0}\]: '
posted by Let on 07/10/10 03:29 AM PDT

I use 'tput' since escape codes confuse me:

   1  export PS1='\[$(tput setaf 3)\]\u@\h:\[$(tput sgr0)$(tput setaf 5)\]\w\[$(tput sgr0)$(tput setaf 2)\] $(__git_ps1 "[%s]") \[$(tput sgr0)\]$ '

Leave a Comment