Git in my Subversion

Two weeks ago, I discovered magic: it’s possible to initialize a Git repo inside of Subversion (SVN).

Since the advent of Github as a leading collaboration platform, I’ve forever been trying to reconcile the Git to SVN workflow. Progress is faster in Git(hub) because it’s a far superior platform for fostering contributions. Seamless pull requests are much nicer than the multi-step process of creating and uploading patches. Distribution still happens in SVN, however, because many legacy deploy systems are coupled to it. Etsy took the leap of switching from SVN to Git, and essentially recommends against it. For the time being, we need to be able to live with both.

Two years ago (almost to the day), I wrote a post called “How to properly use Git with WordPress.org Subversion.” The thing is though — it wasn’t ever properly using Git with SVN. It was grinding the two tools together like a sixteen year-old learning to drive a stick. Furthermore, if I ever nuked my Git repo, I’d have to wait literally for hours to run git svn fetch on the WordPress.org repo. Boone has worked in a similar way for a while; I eventually gave up and started copying my files over manually when I needed to release. Mo does this with an rsync command.

A recent stroke of insight has changed my outlook on life, improved how I sleep, increased my libido, and generally made me a much happier developer. It’s this: Git and SVN can live side-by-side in the same directory. You just need to tell them to ignore each other.

This afternoon, for instance, I decided to spend a little bit of time on Edit Flow. I like to develop Edit Flow locally, keep the WordPress.com VIP shared plugins repo version on the bleeding edge, and occasionally release a version on WordPress.org. Because I haven’t yet applied this “Git in my Subversion” approach to what’s in the latter two repos, let me now walk through what that looks like.

The first thing you should do is edit the “svn:ignore” property on your existing SVN repo. You can do so with:

svn propedit svn:ignore edit-flow

In this situation, I specifically want SVN to ignore two things: .git and .gitignore. Add those, save, and commit. SVN will now respect Git’s living style.

Next, change into your target directory and initialize a new Git repo. Running the following pulls my full remote project into the working directory:

git remote add -f origin https://github.com/danielbachhuber/Edit-Flow.git

But, if I run git status, I’ll see that my local working files aren’t tracked by Git, I can’t checkout master or change branches, and Git is flummoxed. Don’t worry — as long as you’ve kept Git as master, and ported your SVN commits back to Git, you can run:

git checkout -f master

Boom, Git in my Subversion. Running git status I notice there’s a lot of .svn junk I don’t want tracked in my repo, so I create a .gitignore file to handle those (on WordPress.com trunk, I also ignore the wpcom-helper.php file we use for every community plugin to handle local action and filter modifications). The integration is complete.

With Git and SVN side-by-side, I can easily pull features I’ve developed locally into the VIP shared plugins repo, VIPs can create pull requests for community plugins, and I can push hotfixes discovered by WordPress.com usage back to the Git(hub) master project. It works well because Git and SVN are tracking the same files, but I don’t have to get them to live together harmoniously — they just ignore each other. Git-SVN be damned, this is much better.

24 Comments

mbijon September 30, 2012 Reply

Magic is right.

Do you .gitignore anything other than .svn to make this work?

Daniel Bachhuber October 1, 2012 Reply

wpcom-helper.php, but that’s specific to wpcom

Ozh September 30, 2012 Reply

I accidentally mixed git with SVN in a SVN tracked directory and went “ho, the hell with it, it seems to work after all”. My only concern is that you can now have 2 repo that are totally unsynced

Daniel Bachhuber October 1, 2012 Reply

Yes, one limitation this approach has is that the repos are completely independent of one another and never share histories, etc. Philosophically I’m not opposed to this. Pragmatically, it hasn’t yet posed a problem.

Nikolay Bachiyski October 1, 2012 Reply

Have you developed a policy on how/when you commit to both repositories? Do you generally repeat each commit in both places? Or you selectively bundle/split commits in each repository?

Daniel Bachhuber October 1, 2012 Reply

No hard and fast rule yet. I think a ratio of up to five to one works pretty well. I keep git commits small and atomic, and SVN commits tied to a specific enhancement or bug.

Aaron D. Campbell October 1, 2012 Reply

This is a great idea. I’m just trying it out with my Google Analytics plugin to see if I can get used to it. Already when I use both GIT and SVN I tend to treat my SVN as a bit of a second class citizen. It gets bundled commits, and often I bundle far too many at once. Maybe now I’ll remember to commit to SVN more often.

Aaron D. Campbell October 1, 2012 Reply

Well, I ran into my first problem with this already. It freaks out my IDE. I use Komodo, and I love that I can use simple keyboard shortcuts from inside a file to view a svn or git diff, revert, commit, etc. However, when the directory is both SVN & Git, it doesn’t seem to be able to do anything. It ends up being alt+tab to terminal and command line tools, which isn’t bad but it’s not near as nice as the built-in tools.

Aaron D. Campbell October 9, 2012 Reply

As a followup, I had something weird in my setup. Komodo sees SVN first, and ignores Git. It’s not ideal (although I’m not sure what kind of UI WOULD be ideal for something like this), but it’s really not that bad.

Simon Wheatley October 2, 2012 Reply

Can I come out of the closet now? I’ve got a project where this kind of accidentally happened; the main project uses SVN, but a very significant plugin uses Git. I always felt a little dirty.

Aaron: I totally get the confused IDE thing, Netbeans sees Git first and looks no further. I use DTerm to quickly and easily get at the relevant directory in the command line, which works well for me.

Milan January 4, 2013 Reply

Looking at both of your repositories, I’m assuming you are putting master at trunk, thus making tags SVN only. Is this right?

beatpanda January 28, 2013 Reply

So I’m assuming you’re developing and testing the plugin somewhere else, then pulling in changes to your SVN repo via git, then committing via SVN, right? Because if I have the entire SVN repo for my plugin checked out, I can’t actually *use* the plugin.

Daniel Bachhuber January 28, 2013 Reply

Because if I have the entire SVN repo for my plugin checked out, I can’t actually *use* the plugin.

If you’re referring to your WordPress.org plugin directory (with /trunk, /tags, etc.), I actually have all of those checked out somewhere else for the occasional release. In this case, I check out the Git repo into /trunk.

Nikolay Bachiyski January 29, 2013 Reply

You don’t even need the tags and branches checked. Subversion supports tagging using URLs:

svn copy https://plugins.svn.wordpress.org/plugin/trunk https://plugins.svn.wordpress.org/plugin/tags/x.y.z

John Blackbourn August 4, 2013 Reply

Nice tip Nikolay! Thanks.

Dmitry November 4, 2014 Reply

Really nice tip, but what do I do in situation like this: Let’s say I have version 1.0.0 in trunk. I fix some bugs and decide to tag it 1.0.1. I change version in plugin-name.php and readme.txt and check it in to trunk. But what if before I copy trunk to tag 1.0.1. someone try to install the plugin? It will probably result in an error? Or not? If yes, how to prevent it from happening?

James Ellis March 26, 2013 Reply

@Daniel – You might want to update the post to note that this pattern requires Subversion 1.7. With that release Subversion centralized its metadata storage rather than sprinkle .svn folders in every sub-directory. If you’re using an older cut of svn the git checkout commands will break the svn sub-directory metadata gets removed.

Izkata May 7, 2014 Reply

It doesn’t, actually. Just make sure git is ignoring all the “.svn” directories.

paul bearne June 27, 2013 Reply

I use a slight twist on your setup.

I code against GIT on the head/trunk and have production branch which I keep checked on a separate folder which merge head into when I am happy with the changes and its this folder that I have SVN also setup on.

So the workflow is code /test/debug code on the git only head and then on the production folder I just do a merge and commit in git and then a commit in SVN

I tried to switching the working/head but found it was unstable (and fought to switch back) so I am happy to with the extra code copy.

Mocha Dwi July 8, 2015 Reply

It’s awesome, SVN and Git ignore each other (y)

tbelknap January 5, 2016 Reply

Well, dangit, Dan! After struggling with your original implementation, killing it, and then getting sick at the thought of fetching all that crap from the Repository.. this is a heck of a boon! Thank you!

Leave a Reply