Tuesday, March 3, 2009

Optimize git-svn workflow with bash auto complete and Hack&Ship scripts

I've just started using Git at work. We have a large and old subversion repository at work, so git-svn comes to the rescue. Git-svn provides a connection between a central subversion repository and your local git repository. This enables you to get most of the benefits git provides, while still adhering to company standards and commit code to a subversion repository.

I recommend reading Git SVN Workflow to get started with git-svn.

I had some trouble installing Git properly on my computer running Ubuntu 8.10. When executing git svn rebase I got the following message:

Can't locate SVN/Core.pm

After a lot of debugging I figured i was missing a perl library. Installing libsvn-perl did the trick:

sudo aptitude install libsvn-perl


To get the most out of git-svn I'm using git bash completion and two small Hack && Ship scripts to automate the workflow.

Bash autocompletion

Download and install git-completion.sh

Modify your PS1 variable in ~/.bashrc to show the current branch when inside a directory in a git repository:

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


Your prompt will look something like this:

neo@zion:~/dev/emp (trunk)$


Automating the workflow

The recommended git workflow is to create a branch for every new feature you work on. For your branches to be up to date you have to switch to your master branch, rebase with the svn repository, switch back to your branch and then rebase your branch with the master. This is 4 commands that can be automated.

hack.sh

#!/bin/bash
CURRENT=`git branch | grep '\*' | awk '{print $2}'`
status=`git checkout master | awk '{print $1}'`
if [[ ! "${status}" =~ error ]]; then
git svn rebase
git checkout ${CURRENT}
git rebase master
fi


After making sure your branch is up to date you'll want to merge your branch with the master and then push your changes to the central repository (the subversion repository):

ship.sh

#!/bin/bash
CURRENT=`git branch | grep '\*' | awk '{print $2}'`
git rebase -i master
status=`git checkout master | awk '{print $1}'`
if [[ ! "${status}" =~ error ]]; then
git merge ${CURRENT}
git svn dcommit
fi