Using git-svn: making the switch

A lot of people are already convinced that Git has a good chance of replacing Subversion as the version control system of your choice in the long run. Git is in most ways far superior to SVN (If you want to know why, have a look at this comparison). The feeling that Git is the way to go is only strengthened by the fact that major (PHP) projects are switching or planning to switch to the decentralized version control system: Zend Framework, phpBB, Symfony and Drupal, to name a few.

Lots of projects are still stored in SVN repositories though. It’s not always easy to switch from one VCS to another, often projects have SVN-specific build scripts or infrastructure in place. If you’re interested in using Git but you’re still tied to Subversion as your main version control system, you can do so with the git-svn bridge.

Note: this is not a git tutorial, I’m kind of assuming you’re already familiar with git and how to create, add, modify, delete, commit, diff and more. If you’re a bit unfamiliar with the git commands but know the svn toolset, have a look at this excellent svn to git crash course.

Git svn magic

git-svn – Bidirectional operation between a Subversion repository and git. The basic idea is that you keep your SVN respository in place (for as long as it will last), but still use git for all your day to day version control operations. When you feel like, you can then issue a command which will synchronise your git commits with the central Subversion repository. Let’s get started on the setup.

I’m assuming you have a traditional SVN repository layout with trunk in project/trunk, branches in project/branches/* and tags in project/tags/*. The -s switch indicated you want git svn to assume this layout is in place, so it can transform the repository paths to remote git repositories. The parameter --no-minimize-url is sometimes needed when you don’t have read permissions on the full repository, since git will try to connect to the root of the repository because sometimes, this provides better tracking of history when you’re importing the project. This step will initialize a git repository in the current directory with the needed metadata information to fetch the svn repositories later on:

$ git svn init -s

Next up, we’ll fetch the history from the svn repository and store it inside our git repository. An optional revision parameter (-r) can be added to only fetch history from that revision and up:

$ git svn fetch -r XXX

You can also replace the previous 2 commands with the command below. The only difference is that the git svn clone command creates a new git repository directory for you instead of using the current directory, hence the last parameter which indicates the directory name:

$ git svn clone -s project_dir

Updating from and committing to svn

When you do a git commit, these commits won’t be pushed directly to the svn repository. Interacting with the svn repository is done separately, so two additional commands are useful.
Updating your repo with the latest changes from SVN (similar to svn update):

$ git svn rebase

Pushing your commits to the SVN repository (somewhat similar to svn commit):

$ git svn dcommit

Basically, right now you’re set to go and you can start working on your git repository like you would normally do. In my case, I wanted to know how to do some additional things. They might not be needed in your case, but I found them useful to set up my working environment.

Working with branches

Since you have imported the git repository using a standard layout (remember the -s from the git svn init), you have all branches and tags available as you normally would with an svn checkout. Have a look at those remote branches:

$ git branch -r

Of course, you can start working on these branches too. To create a local branch which tracks one of the remote branches, do:

$ git checkout -b new_branch remote_branch
# so, for example to create a branch 'release_1.5' which tracks remote 'release_1_5':
$ git checkout -b release_1.5 release_1_5

When you fetched the SVN repository into your git repository, it automatically set your local master repo to follow the remote trunk repository. If you want to change that (for example, to have a branch as default master repo), you can change it like this:

$ git reset --hard remote_branch
$ git reset --hard release_1_5 # example

Fixing svn ignore

Svn ignores aren’t automagically transfered to your newly created git project, but git does have a similar way of ignoring files or directories inside a project. Better yet, git svn provides a built-in command which looks for svn ignores. If you then add those to .git/info/exclude (locally) or .gitignore (project-wide), you have exactly the same setup as you would have with svn.

$ git svn show-ignore > .git/info/exclude

Fixing svn externals

If you’re using svn externals, you might have to jump to some additional loops to set everything up. There’s no real replacement for svn externals, but one way Git manages to simulate this is by using submodules. Submodules are a bit cumbersome to set up, but luckily for us, there’s a script which searches your project for svn externals and checks them out as git submodules. Of course, it’s not guaranteed to work, but might make it easier to set it up. Get it here:

I’m hoping this is enough to get you started on using Git, an awesome version control system with too much cool features to name. If I’m missing something, please let me know in the comments and I’ll be glad to update the post.

2 responses to “Using git-svn: making the switch”

  1. Why yes, but… mercurial > git ;)

    It never ends!!!

    Oh, and some people are still happily using cvs :gasp:
    ( Well, i don’t know if they are happy,… ;) … )

  2. As I know “git svn dcommit” pushes only one Git branch to SVN. But what if you want to push more complex history to SVN (don’t forget about correct svn:mergeinfo that is important for “svn merge” command)? And this approach loses all dates too.

    Have a look at SubGit that is truly bi-directional SVNGit translation. It translates arbitrary Git history to SVN correctly (and arbitrary SVN history to Git too), preserving tags, commits dates, ignores (.gitignore -> svn:ignore), EOLs (“eol” attribute in .gitattributes -> svn:eol-style), merges, and so on.