Git Workflow with SVN

April 28, 2009 📬 Get My Weekly Newsletter

The best way to get started with Git and have a better experience at work if you have to use SVN is to use git svn as a client to Subversion. You can take advantage of Git's awesomeness while not requiring your team or infrastructure to change immediately.

Setup

git svn clone -t tags -T trunk -b branches svn+ssh://your.svn.com/path/to/svn/root (This may take a while for a large or old svn repo)

Working on Trunk

The initial clone should leave you on git's master branch, which is connected to svn's trunk.
  1. git svn rebase # Optional: only if you want to get work from svn; you don't have to
  2. Hack some code
  3. git add any new files you created.txt
  4. git commit -a
  5. Repeat from step 2 until done

Sharing Your Changes

You will rebase your changes against's SVN's (this means git will pretend you made all your changes from SVN's current HEAD, not the HEAD you started with [you do this to avoid conflicts and merges, which SVN cannot handle]).
  1. git svn rebase
  2. git svn dcommit

If you got Conflicts

  1. Git will tell you about them, so go and resolve them
  2. For each file you had to resolve, git add the_filename
  3. git rebase --continue
  4. Repeat until done

Working with SVN's branches

Suppose you need to do some work on a branch called 1.3.x in your SVN repo:
  1. git svn fetch # This updates your local copy of remote branches
  2. git checkout 1.3.x# This checks out a remote branch, which you shouldn't work directly on
  3. git checkout -b 1.3.x-branch # This creates a local branch you can work on, based on the remote 1.3.x branch
  4. Hack some code
  5. git add and git commit -a as needed
  6. Follow same procedure as above for Sharing Your Changes. Git will send your changes to the 1.3.x branch in SVN and not the trunk

Merging the Changes You Made

Due to the way git interacts with SVN, you shouldn't automatically just merge your branch work onto the trunk. This may create strange histories in SVN.

So What?

So, this isn't buying you much more than you get with SVN. Yes, when you git checkout 1.3.x-branch it's lightning fast, and you can work offline. Here's a few things that happen to me all the time that would be difficult or impossible to do without Git.

Gotta Fix a Bug Real Quicklike

You are in the middle of working on a new feature and you need to to push out a bugfix in production code. Your in-development code can't be checked into trunk:
  1. git stash
  2. git checkout production-branch-name
  3. git checkout -b bugfix-xyz
  4. Fix bugs
  5. git commit -a
  6. git svn dcommit
  7. git checkout master
  8. git stash apply
You are now back where you started, without a fake revision just to hold your code and you didn't have to go checkout the branch elsewhere.

Can't commit to SVN due to a release

Often, teams restrict commit access to SVN while a release is being prepared. If the team is releasing version 1.5 and I'm working on 1.6 features, there can be some period of time where I'm not supposed to commit, because the 1.5 release is being prepared and under feature freeze.
  1. git commit -a
  2. Continuing working
When feature freeze is over, then I'll git svn dcommit to send my changes to the SVN server

Blocked on Feature X, Want to work on Feature Y

This happens to me quite frequently: I'm slated to work on a few features that aren't interdependent. I start hacking away on Feature X and hit a roadblock and can't continue working. I've got a half-implemented feature and I can't make any forward motion until a meeting next week. Feature Y, on the other hand, is ready to go. This requires some planning ahead:
  1. git checkout master
  2. git checkout -b feature-X
  3. Work on Feature X
  4. git commit -a etc. as I work
  5. Get blocked; meeting next week. D'oh!
  6. git checkout master
  7. git checkout -b feature-Y
  8. Work on Feature Y
At this point, X and Y are on two local branches and I can switch back and forth as needed. Don't underestimate how powerful this is, especially when you have certain features that are priorities, but can become blocked frequently. I can now easily put aside Feature Y once I have my meeting and start back up on Feature X. When I'm done, I git merge everything back to master and dcommit to SVN.

Type your log message, save it, realize you forgot to reference a bug ticket #

You have a bug tracker set up that links tickets and revisions; all you have to do is put the ticket # in your log message. It's a nice feature, but I forget to do it frequently. As long as you haven't done git svn dcommit, you can fix this:
  1. git commit --amend
Your editor will pop up and you can change the log message! Awesome.

Advanced Stuff

Once you get used to this, you will feel more comfortable doing some more advanced things.

Topic Branches

The most obviously beneficial was touched on above, but it boils down to: make every new feature on its own branch. This means you never work on master and you never work on an SVN branch. Those are only for assembling what you will send to SVN. This gives incredible flexibility to work on code when its convenient and not worry about checking in bad things. Git calls this topic branches.

Save your Experiments

If you do everything on a branch, you don't have to delete your work, ever. You can go back and revisit experiments, or work on low-priority features over a long period of time with all the advantages of version control, but without the baggage of remote branches you have to share with the world.

Cherry Pick

With Git, you typically commit frequently and you restrict the scope of each revision. A commit in git is more like a checkpoint, and a push in Git is more like a commit in SVN. So, commit in git like crazy. What this lets you do is move diffs around. On several occasions, I've had some code on a branch that I needed to use, but didn't want to pull in the entire branch. git cherry-pick lets me do that.

Mindlessly Backup Your Repo

  1. ssh your_user@some.other.box.com
  2. mkdir awesome_project
  3. cd awesome_project
  4. git init
  5. exit
  6. git remote add other-box your_user@some.other.box.com:/home/chrisb/awesome_project
  7. git push --all other-box
  8. echo "git push --force --all other-box" > .git/hooks/post-commit && chmod +x .git/hooks/post-commit
You now will back up your repository on every commit to the other box. Or, use GitHub!