Working with different development teams and in different corporate environments, one may find that some teams have migrated to Git for source code management. Other development teams use Subversion (SVN) for historical reasons, a lack of infrastructure to support Git, or the general inertia of being resistant to adopting new technologies. Suppose that a team of developers would ideally like to move to Git, but finds too many barriers to its adoption and can’t make the conversion happen all at once, there is a solution that allows individual developers to make the switch if they wish to while still pushing code to a central SVN repository. This is the goal of Git-SVN. This open source product provides as they say “bidirectional operation between a Subversion repository and Git”. The Git documentation even calls it “a good way to sneak Git into the corporate environment and help your fellow developers become more efficient while you lobby to get the infrastructure changed to support Git fully”.
With that goal in mind, we will now cover a sample workflow using Git-SVN to clone a SVN repository, create a new branch, make some changes to the code adding a new feature, and merge those changes back to the central repository.
Now, assuming the operating system is Ubuntu (but feel free to make the corresponding changes for Redhat, CentOS, Fedora, etc.), the first thing we want to do is install git and git-svn from apt-get. I also like to throw in git-gui because it makes things easy to use:
sudo apt-get install git git-svn git-gui
Let’s consider a SVN repository located at this fictitious URL: https://vcs.example.com/svn/corporate-project-1/
In this repository we have a typical layout:
We can clone just the trunk with:
git svn clone -T trunk https://vcs.example.com/svn/corporate-project-1/ ./corporate-project-1
In addition to the ‘-T’ flag, which specifies the trunk subdirectory, the ‘-b’ flag can be used to specify the branches subdirectory, and the ‘-t’ flag can be used to specify the tags subdirectory. If you want to clone the whole thing use the flag ‘–stdlayout’. This assumes that the layout looks like the one above. This flag is not recommended for cloning large repositories because it can cause the process to take a long time. We’ll assume that we’re just cloning the trunk for this example. This creates a “master” branch in our Git repository. Changes to the master will be committed back to the SVN trunk.
Typical Workflow: Branching and Merging
Once our Git repository is created, we can use the typical Git workflow of branching to add new features to our code, but we must be careful when merging back to the master to keep a linear history so as not to cause problems when committing back to the SVN repository. We will cover this later.
Let’s create a new branch in Git to add a feature:
git checkout -b feature_x
This simultaneously creates the new branch and checks it out. Note that a Git checkout is different from a SVN checkout. A SVN checkout corresponds to a Git clone. A Git checkout switches between active branches in your repository.
When we’ve added our new feature and committed it to our feature branch (Note: here is where I like to use the Git GUI to view changes and make the commit.), we’re ready to merge our work back into our master branch. But first we want to bring our master up-to-date with any recent changes in the SVN repository:
git checkout master git svn rebase
Now we can “merge” these changes into our feature branch using “git rebase master” from inside our feature branch:
git checkout feature_x git rebase master
The rebase command “rewinds” the changes that we’ve made to this branch to bring it back to the state it was in when we originally branched it from the master. It then brings this branch up-to-date with the master and re-applies those changes. What we’re left with is a linear history, as if we only just created this branch after pulling the latest changes from the SVN repository into master, and then added our new feature on top of that.
Now that our feature branch is up-to-date with the latest changes from the SVN repository, we can merge it back in to the master. Here it’s safe to do a “git merge” while still preserving our linear history:
git checkout master git merge feature_x
And finally, now that we’ve incorporated our new feature into our master branch, we can commit back to SVN:
git svn dcommit
It may be a good idea to run “git svn dcommit -n” first (the ‘-n’ flag means dry-run) as a sanity check to make sure Git-SVN is doing what you expect it to do. The “dcommit” makes each of your git commits into SVN commits, including your commit messages.
And there you have it! You’ve successfully combined a Git workflow with a SVN workflow. Go tell your co-workers and get them to convert to Git!