Ruby On Rails has a Subversion repository with over 7500 commits at the time of writing. In this article I show how you can use Git to have a full local copy of the repository in 9MB, and use it to track upstream changes.
In a subsequent article I will show you how to use such a repository to easily maintain Rails patches for the six months it takes you to get them accepted into Core (wink).
Background
Git is a revision control system that is distributed, which means that every developer using Git gets to be the ruling dictator of his own distinct code repository. With a distributed RCS, a central "master" repository is an optional result of a consensus decision, and not a technical requirement.
Having a full local repository lets you work off-line, branch and merge freely, and check in regularly without being a project member.
Mirroring subversion repositories: git-svn
Git ships with a nifty tool called 'git-svn', which can pull and push changesets between a subversion repository and a git repository, maintaining tag, branch and author information.
After reading a helpful article I used git-svn to make a mirror of the Rails subversion repository. That step took many hours, so I've set up my mirror to update itself regularly throughout the day, and published it at the following Git URL:
git://git.sanityinc.com/rails.git
More on how to use that URL later.
What you will need
Make sure you have git installed, with svn support. (To follow this article, you don't need the svn support, but you'll no doubt want to play with git-svn yourself.) In most Linuxes, the package to install is called "git-core". On a Mac, if you value your time you will use the MacPorts package with 'svn' variant enabled:
% sudo port install git-core +svn +doc
Make a local clone of the repository
You can clone my Git mirror of the Rails repository using git-clone:
Initialized empty Git repository in /tmp/rails/.git/
remote: Generating pack...
remote: Counting objects: 6041
Done counting 59416 objects.
remote: Deltifying 59416 objects...
100% (59416/59416) done16) done
Indexing 59416 objects...
remote: Total 59416 (delta 45829), reused 58267 (delta 45039)
100% (59416/59416) done
Resolving 45829 deltas...
100% (45829/45829) done
The newly-created 'rails' directory contains every changeset in Rails' history, all stored in only 9.2MB of packed Git data:
% du -hs .git/objects
9.2M .git/objects
This magic is possible due to Git's delta compression. Note that a plain 'vendor/rails' directory alone weighs in at over 8MB.
Here are all the branches:
* master
origin/1-1-stable
origin/1-2-pre-release
origin/1-2-stable
origin/HEAD
origin/cap2-on-netssh2
origin/cap2-on-netssh2@2073
origin/cap2-on-netssh2@3784
origin/cap2-on-netssh2@7243
origin/capistrano_1-x-stable
origin/capistrano_1-x-stable@2073
origin/capistrano_1-x-stable@3784
origin/capistrano_1-x-stable@6222
origin/master
origin/p2
origin/performance
origin/restful_aws
origin/restful_aws@1324
origin/restful_aws@668
origin/routing
origin/stable
origin/trunk
Note that the default branch is 'master', which corresponds to 'origin/trunk' - Rails "edge".
You can trivially switch the working copy in the current directory to another branch, such as the Rails 'stable' branch:
Branch stable set up to track remote branch refs/remotes/origin/stable.
Switched to a new branch "stable"
(It's considered bad practice to check out remote branches directly, so here we made a local 'stable' branch that tracks 'origin/stable'.)
'git-log' gives us the commit history for the current branch:
commit 1f5a5285c45caf49261ded485aa9994296e0305e
Author: ulysses
<ulysses@5ecf4fe2-1ee6-0310-87b1-e25e094e27de>
Date: Thu Aug 10 17:13:55 2006 +0000
Can't use controller_path due to Admin model and Admin::UserController case
git-svn-id: http://svn.rubyonrails.org/rails/branches/stable@4750 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
...
Note the embedded subversion revision, '@4750'.
You can browse the history of the current branch using the 'gitk' GUI.
Keeping your mirror up to date
You'll want to periodically pull new changes from the Rails repository into your local repository. Use 'git-pull' for this:
remote: Generating pack...
remote: Done counting 23 objects.
remote: Result has 15 objects.
remote: Deltifying 15 objects...
remote: 100% (15/15) done
remote: Total 15 (delta 13), reused 0 (delta 0)
Unpacking 15 objects...
100% (15/15) done
* refs/remotes/origin/trunk: fast forward to branch 'trunk' of git://git.sanityinc.com/rails
old..new: 258ae9d..6bf2bef
Already up-to-date.
Making changes locally
With a little git knowledge, you can commit changes into your local repository, getting git to do the magic of merging upstream changes.
If you want to contribute patches back to Rails, you can use git to maintain them; git can regenerate your patches automatically as the surrounding Rails code changes. A follow-up article on this site will describe how to do this.
Futher reading
- Git documentation
- This site -- why not subscribe to future articles?
Update: I've set up gitweb, so you can browse the Rails git mirror here.
Further update: my mirror will be discontinued now that Rails development has switched to Git






Thankyou for providing the Rails git repository. A real time safer and much appreciated
Thanks for the tutorial and the git mirror, but how does one create a Core-friendly diff? This method produces a repository that has no svn association with the rails repo, so
svn diffdoesn't work.git diff HEAD^produces something git-specific.Brad: According to
man git-diff, you can use the "-p" option to get apatch-compatible unified diff instead of the git-specific diff.Just came across mr, a tool to unify handling of different versioning systems. Check it out here: http://kitenet.net/~joey/code/mr/
Hi,
I had tried to do a git svn fetch from http://dev.rubyonrails.org/svn/rails/ and compared it against a clone of your git repository. However, mine's did not do all the tags correctly.
Would you mind posting up how you initialized your git repository you are hosting now?
I may not necessarily want to maintain yet another Rails git mirror, but I do like to know how properly use git to mirror a subversion server.I have a few private subversion servers I want to mirror.
Thanks,
Ho-Sheng Hsiao
Isshen, LLC
Great intro to git, Steve. Thanks. I've been using Mercurial for a while now. Having a similar interface, it seems to lack out-of-the-box integration with other kinds of SCM tools. Looks like git is really ahead of the pack in this respect.
Looking forward to seeing the next article - thanks for demistifying git a bit. Great design on the blog too! :)