Editor’s Note: New capabilities of Grails make this a much more useful approach: Github Grails Plugin 2.
The superb Grails web development framework is extremely extensible via a system they call (uncreatively) Plugins. For a list of current plugins, check out http://grails.org/plugins/ — functionality ranges from functional testing (e.g. Functional Testing) to user interface libraries (e.g. YUI, GTW, iUI) to data migration (e.g. Autobase). And developing a plugin is far from black magic — in fact, it’s basically the same as developing an application, but with a plugin meta-information file (more here and here).
As a plugin developer, I was a bit disappointed to discover that the Grails plugin repository was still on svn. I have been converted to git by my project with Vita Rara, and now do my open source development over at GitHub.
This leads me into a problem: after I do my first release of a project, my definitive repository from the project shifts from git at github.com to svn at svn.codehaus.org. I do not want to shift to doing development in svn, though, and give up all the advantages of git.
Enter git-svn. Here’s how I created an Autobase working directory that handles both my GitHub and Codehaus commits. Hopefully you find it useful.
The most important thing for the set-up is to ensure that the base of your project in GitHub is the root folder of your plugin. Unlike subversion, git doesn’t provide the ability for any folder in the repository to become a project root — git defines a single project root, and you can’t work right off of subsets of it (or, rather, if you can, I don’t know how). If you were clever and put the plugin in a subdirectory of the project (like I originally did with Autobase), git-svn won’t be able to rectify the two repositories, and you’ll just end up with two sets of code.
First, create a directory to act as your working directory, and then move into it.
mkdir autobase; cd autobase
We’re going to start with the svn side of things, because it seems to work better that way.
git svn init --username=robertfischer -s https://svn.codehaus.org/grails-plugins/grails-autobase/
At this point, I get the following message:
Using higher level of URL: https://svn.codehaus.org/grails-plugins/grails-autobase => https://svn.codehaus.org/grails-plugins
But things seem to work okay anyway, so I ignore it and move on.
That just initialized the directory: the next step is to actually pull the information down from the directory.
git svn fetch
There’s a warning message, and then another warning message telling you to ignore the previous warning message, and then a long pause as git-svn tries to figure out what’s up with your repository and starts extracting information from the remote svn server — you can either watch the fits and spurts of network activity in your favorite network analysis tool or go get some coffee. According to the following time report, you’ll probably have about 2 minutes:
real 2m10.367s user 0m8.872s sys 0m12.879s
Once that’s done, your trunk will be merged into master, and you can see your svn structure reflected in your git branches:
git branch -a
For me, this gives:
* master tags/LATEST_RELEASE tags/RELEASE_0_1 tags/RELEASE_0_2 tags/RELEASE_0_3 trunk
As a matter of course, I now do a pack to shrink the repository:
git repack -d
i do this because I was told to by Andy Delcambre’s blog post, and it seems to work.
I test out the svn connection by making a trivial change (adding “foo=bar” to application.properties), committing it to my local repository, and then committing it back to svn.
vi application.properties git commit application.properties git svn dcommit
Looks good. Now I’m going to switch back to “master” (my local working branch) and start integrating the GitHub stuff. Setting up GitHub is just setting up a remote repository — if you’re not sure what’s going on, there’s a bit more information here. The one important thing in this step is to be logged into GitHub in order to get the private clone URL: you can’t push to the public clone URL. Also, the fetch is going to take a long while again — by Web 2.0 standards, anyway.
git checkout master git remote add github git@github.com:RobertFischer/autobase.git git fetch github
The is warning is foreshadowing some suck coming up:
warning: no common commits
Although I’ve got everything pulled down (I can see them with git branch -r), I want to create a local branch where I can do work. So I issue the following commands:
git checkout github/master git checkout -b github_local vi .git/config
Under [remote "github"], I add the following line:
push = github_local:master
That means that when I make a change to github_local and issue a git push github, I’m pushing code back up to the GitHub repository.
Now the time has come to merge everything together into the local working branch (“master”). After checking out the master branch (git checkout master), I pull the simple change I made from trunk:
git merge trunkNow I pull the stuff from GitHub:
git merge github/master
This is where the pain comes in — lots of conflicts to sort out. I now get to go through and hack the things into behaving well again. Once that’s done, though, I’m good to go!
Related posts: