ruby, rails, textmate, automation, etc.

Easy git-svn for Rails (or "git-me-up")

Posted on April 24, 2008

This post is about how to use git-me-up.

What does git-me-up do?

In a nutshell, it:

  1. Clones the latest version of the source in your Subversion repository into a new local Git repository. It doesn’t import any history for performance reasons.

  2. Recreates empty directories that git-svn ignored (but that your app might need).

  3. Converts any svn:ignore Subversion properties into entries in the .git/info/exclude file.

  4. Checks for Rails plugins installed via svn:externals and clones them into their own git repositories. Each external plugin is then symlinked into vendor/plugins.

  5. Creates a local working branch.

In other words, it takes all the hard work out of creating a local Git repository that points at your Subversion repo.

Installation

You need git-svn installed first. On a Mac, install MacPorts and then type:

$ sudo port install -u git-core +svn +bash_completion

When the package has finished building run these commands to benefit from bash completion:

$ cp /opt/local/etc/bash_completion.d/git ~/.git-bash-completion.sh
$ echo '[ -f ~/.git-bash-completion.sh ] && . ~/.git-bash-completion.sh' \
    >> ~/.bashrc
$ . ~/.bashrc

On Ubuntu Linux:

$ sudo apt-get install git-svn

Installing git-me-up

The source is hosted on GitHub. You can either download the tar ball or pull the source with git:

$ git clone git://github.com/gma/git-me-up.git

The Makefile will install it into /usr/local/bin:

$ cd git-me-up
$ sudo make install

Using git-me-up

This is pretty easy. Let’s start with an empty directory so you can see what gets created:

$ pwd
/home/graham/test
$ git-me-up https://myhost.com/path/to/myproject/trunk myproject
git-me-up: finding latest revision of https://myhost.com/path/to/myproject/trunk
git-me-up: creating git repository in /home/graham/test/myproject
git-me-up: making empty directory: app/views/comments
git-me-up: making empty directory: app/views/pages
git-me-up: making empty directory: components
git-me-up: making empty directory: log
git-me-up: making empty directory: test/mocks/development
git-me-up: making empty directory: test/mocks/test
git-me-up: making empty directory: tmp/cache
git-me-up: making empty directory: tmp/pids
git-me-up: making empty directory: tmp/sessions
git-me-up: making empty directory: tmp/sockets
git-me-up: setting ignored files from subversion (this can take a while)
git-me-up: checking for plugins installed with svn:externals
git-me-up: finding latest revision of https://myhost.com/path/to/plugin/trunk
git-me-up: creating git repository in /home/graham/test/myproject/../plugins/site_theme
git-me-up: setting ignored files from subversion (this can take a while)
git-me-up: symlinking site_theme into myproject/vendor/plugins
git-me-up: creating 'work' branch on /home/graham/test/myproject
Switched to a new branch "work"
$ ls
myproject/  plugins/

If you’re running on a Mac you may see this error message part way through the output:

No such file or directory: PROPFIND request failed on '/app': Could not open the requested SVN filesystem at /opt/local/bin/git-svn line 1872

It appears as though the git svn show-ignore command (using the current version of git from MacPorts–version 1.5.4.4) doesn’t work on my Mac. If you see this too don’t worry about it; it will only mean that Git doesn’t know which files you’ve chosen to ignore in your Subversion repo.

Now we’re ready to use our new Git repo. Note that we’ve got a work branch by default:

$ cd myproject
$ git branch
  master
* work

If you want to call the branch something else, set the BRANCH environment variable before you run git-me-up.

Samuel recommends a good work flow for working with Subversion (skip down to “Step Five: Using this thing”) . When you want to update your working branch from subversion, try this:

$ git checkout master  # switches to local master branch
$ git svn rebase       # pulls recent changes from subversion
$ git checkout work    # switches to local work branch
$ git rebase master    # pulls recent changes to master into work

There’s a good description of why rebase is so great on James Bowes’s blog.

When you want to commit changes back into subversion:

$ git checkout work    # you were probably there already
... run your tests ...
$ git commit -a -m "Blah blah blah..."
$ git checkout master
$ git merge work
$ git svn rebase       # checks for fresh changes in subversion
... run tests again if rebase pulled any changes ...
$ git svn dcommit

Make sure that you use git svn rebase to pull upstream changes into your master branch before you check in.

What git-me-up does with svn:externals plugins

The Rails app that I cloned above has a plugin that is installed via svn:externals called site_theme. I usually use piston or braid to install Rails plugins, but when the plugin is stored on my own servers I’ve always preferred to pull in the source directly by setting the svn:externals property.

I initially tried to convert svn:externals into Git submodules, but it didn’t work well. No matter what I tried, I couldn’t persuade git-svn to ignore the submodule when committing back to Subversion. It turns out that it’s easy to achieve with a symbolic link.

git-me-up cloned the site-theme plugin into a Git repository, then made it available with a symbolic link:

$ ls
myproject/  plugins/
$ ls plugins/
site_theme/
$ ls -l myproject/vendor/plugins/ | grep site_theme
lrwxrwxrwx  1 graham development   32 Apr 24 18:41 site_theme -> ../../../plugins/site_theme/

To avoid checking the symlink into Subversion, git-me-up told Git to ignore it:

$ grep site_theme myproject/.git/info/exclude
/vendor/plugins/site_theme

The result is a trouble free alternative to submodules that allows you to integrate Git with svn:externals in your Subversion repo.

Comments
  1. GregApril 27, 2008 @ 05:41 AM
    Thank you!
  2. GregApril 28, 2008 @ 04:32 PM
    You should note that this script expects you to be checking out project/trunk or wherever the actual source is. Would be nice to make a quick check and exit if otherwise. Normally with git-svn you can use it from the root where branches/ tags/ and trunk/ are, and it recognizes them all as branches. I think this will work fine for me though, thanks.
  3. GrahamApril 28, 2008 @ 10:42 PM
    Greg - good point, it does only support cloning one URL in your git repository. I did consider the -s switch to git-svn (that assumes you're using /trunk, /tags and /branches). In the end I didn't bother with it because I wasn't bothered about pulling history or all the tags--I was just after something that would run the import quickly. It wouldn't be too hard to add support for -s/-T/-t/-b if there's any demand for it (register the demand below if you want it!).
  4. GregApril 29, 2008 @ 09:23 PM
    What license is the source under?
  5. GrahamApril 30, 2008 @ 08:19 AM
    Good question. Something very liberal. Perhaps I should look at the MIT/BSD licenses, choose one, and drop one of them into the repo. In the meantime feel free to do what you like with it. Sounds like you might be thinking of doing something useful with it. Are you thinking of building something else on top of it?
  6. GregApril 30, 2008 @ 03:05 PM
    Any license that allows sharing. It really won't matter for a script like this. I was going to allow cloning options and do a more extensive check for svn:externals. I will fork the repo on github when I see a LICENSE.
  7. Mike BreenApril 30, 2008 @ 08:20 PM
    If I installed git via MacPorts without the "+bash_completion" option do I need to reinstall?
  8. GrahamApril 30, 2008 @ 11:47 PM
    Greg - LICENSE is uploaded. Looking forward to seeing what you come up with.

    Mike - You don't need to have installed the +bash_completion variant to get git-me-up to work, but it makes git nicer to use as you don't have to type as much while you're using it (tab completes most commands and arguments for you). If you have already installed git via MacPorts you could deactivate your existing version before you start. For example:

        $ sudo port deactivate git-core
        $ sudo port install git-core +svn +bash_completion
    

    You could then remove the old version later with `port uninstall`. Alternatively, try intsalling the bash_completion variant with this (which ought to remove old versions for you):

        $ sudo port upgrade -u git-core +svn +bash_completion
    
  9. GregMay 06, 2008 @ 04:30 PM
    git-it-up http://github.com/gregwebs/git-me-up/tree git-it-up <svn> <local> <clone_options> [--recursive-externals]
Post a comment
Comment