July 24, 2008
Converting a Shared Subversion Repository to Git
At Alien Camel, we've always run our Rails projects from a central Subversion repository. We've recently become Git converts, and love its distributed development capabilities, but the centralised repository model suits Rails deployment and we want to stick with it.
There’s plenty of documentation out there on how to convert a Subversion repo to Git, and there’s some stuff on setting up a shared Git repo, but its not obvious how to combine the two.
We've worked out how to do it, and successfully converted a couple of projects. This is our recipe.
Create a git user and group
First of all, you need a git
user and group on the server where
you host your repositories. On Ubuntu, this will do the job:
sudo adduser git
Now edit /etc/group
, and add any users who’ll need to access the
Git repository to the git
group:
...
git:x:1005:pete,fred
...
Make a directory for Git repositories
We put ours in /usr/local/gitroot
, but pick somewhere that suits your setup.
sudo mkdir /usr/local/gitroot
sudo chown git.git /usr/local/gitroot
sudo chmod 2770 /usr/local/gitroot
It’s common practice (although I don’t recommend it) to have multiple projects in a
single Subversion repository. You definitely shouldn’t do this with Git. Each project
should have its own Git repository within the /usr/local/gitroot
directory.
Convert the Subversion repository
First you need to tell Git how to convert your Subversion user names to Git user names. For this you create an authors file, which looks something like this:
pete = Pete Yandell <pete@notahat.com>
fred = Fred Bloggs <fred@bloggs.com>
On the left are the Subversion user names; on the right are the Git equivalents.
We save this in /usr/local/gitroot
, just in case we want to use it
for converting other projects later on.
Now do the conversion and put the result into a temporary repository (you’re going to clean it up and clone it again a bit later), passing in the authors file and the Subversion repo.
cd /tmp
git svn clone --stdlayout --authors-file=/usr/local/gitroot/authors file:///usr/local/svnroot/my_project
This will probably take a while if your repo is large.
The —stdlayout
flag
tells Git to expect trunk
, tags
, and branches
directories inside your Subversion project and deal with them correctly.
Some people also recommend the —no-metadata
flag. Normally git svn clone
puts information about the Subversion revision into each converted Subversion commit. The
—no-metadata
flag prevents this. I prefer to leave this information in, just
in case I need to refer back to the old Subversion repo at some point.
Make the shared Git repository
Now you need to create the git repo in the right place, and with the right permissions.
Do it all as the git
user:
sudo -u git bash
Clone the temporary repo into its final location:
umask 007
cd /usr/local/gitroot
git clone --bare /tmp/my_project my_project.git
Finally, make sure all the permissions are correct, and will stay that way:
cd my_project.git
git config core.sharedrepository 1
git config receive.denyNonFastforwards true
find objects -type d -exec chmod 02770 {} \;
The core.sharedrepository
flag tells git to keep everything group readable
and writable.
The receive.denyNonFastforwards
flag makes sure that merges can’t happen
when you push to the repo. You have to do the merges on your local machine, and then push the
result.
If you’re creating an empty shared repo, you can use the —shared
option
to git init
to set these two flags automatically. A word of warning though:
the —shared
option to git clone
does something completely
different.
Try a clone
Now you should switch to your local machine and try cloning the repo:
git clone ssh://myhost.com/usr/local/gitroot/my_project.git
You should be able to commit to this repo, and use git push
to push changes back up to the central repo.
Clean up
Once you’re happy that everything is working, delete the temporary repo that you
created in /tmp
, and you’re done!
This is a fantastic guide – thank you. Everything worked exactly as expected
Is there a way to automatically create remote branches from our branches and tags in our existing SVN repository? Currently we’re pulling in the trunk fine into the bare git repository, but I'd like to see all our branches and tags as remote branches / tags in our GIT repository as well. How can I do that? Great guide by the way ;)
Thanks for the great guide.
I also documented my process of migrating our SVN repos to GIT. The difference is (much like the guy above me) that I needed to get all branches and tags into my GIT repo as well.
See my post here: http://qugstart.com/blog/git-and-svn/migrate-an-svn-repository-to-git-while-maintaining-branches-and-tags-structure/