An Open Access Peon

12 September 2012

Migrating svn to git with sub-directories

On EPrints we have a slightly odd layout in our svn repository:

branches/
  3.3/
    docs/
    extensions/
    system/
  tags/
    ....
  trunk/
    docs/
    extensions/
    system/

This works well enough with svn where you can checkout a sub-directory but git only allows you to check out the entire repository - branches are real branches rather than just named directories. The correct git usage is to use separate repositories for "docs", "extensions" and "system" and place the contents for each one at the repository root.

The goal of the migration to git is therefore to move trunk/system up to trunk/, branches/3.3/system up to branches/3.3 and so on for branches still in use. (For my own sanity I'm going to ignore tags.)

One approach might be to "git svn clone" the entire svn tree and then move the elements of system/* up a directory. The downside to this approach is every file in the repository will then be touched with that movement, losing the ability to (trivially) see the last time a file was modified.

I also tried use the svn svn-dump-reloc tool to move directory contents up into their parent. That drove me down a path of despair of broken historical file movements and duplicated directory creations (because moving system/trunk/ to trunk/ duplicates the initial trunk/ creation).

The eventual approach taken was to use git-svn's ability to clone a sub-directory and magically place it in the root of the new git repository. I started with trunk/:


git svn clone -A users.txt https://svn.eprints.org/eprints/trunk/system eprints


And the same with the 3.3 branch:


git svn clone -A users.txt https://svn.eprints.org/eprints/branches/3.3/system 3.3


I can then create an empty branch for 3.3 (kudos to http://www.bitflop.dk/tutorials/how-to-create-a-new-and-empty-branch-in-git.html) in my git trunk clone:


cd eprints
git checkout --orphan 3.3
git rm -rf .


git can pull in the content of a remote repository like so:


git remote add -f 3.3 ../3.3/
git merge -s ours 3.3/master


Tidying up:


git remote rm 3.3
git checkout master


This repository can then be pushed up to github using their standard instructions:


git remote add origin https://github.com/...
git push -u origin master


And to push the branch(es):


git push origin 3.3