Saturday, August 15, 2009

GIT migration

A few years ago, I watched Linus Torwald's presentation on git. I was so thoroughly put off by his style that I did not give git another thought for several years, that is until recently. Hearing more and more about git, I recently raised the question of migrating the logback project to git on our mailing list and the ensuing discussion had me convinced.

Here is a recount of the steps I've taken to migrate logback to git from SVN.

First, I installed git on our Linux servers. Nothing newsworthy there. Gitosis' installation on those servers was equally uneventful.

Installing git on Windows was more of an ordeal. Supposedly, on Windows git is officially supported with cygwin, which I've been using daily for over 10 years. Git just did not work me with cygwin. Migrating to cygwin 1.7-beta was not much of a help. Fortunately, the msysgit project provides a solution for Windows.

The next step was to create a git repository from our existing SVN repo which was as easy as invoking "git svn --stdlayout --no-metadata -A authors.txt clone http://svn.qos.ch/repos/logback" where authors.txt is a file mapping login names to user names. The --no-metadata flag tells GIT to drop noisy references to the SVN url and other useless details.

My next step was to allow anonymous reading of the git repository, which as easy as starting git-daemon which was part of the core git package (installed by gentoo).

Git makes it very easy to fork projects. On github, you can track work done on forks, which was one of the arguments that convinced me to switch to git hub. However, pushing to github is slower than pushing to git.qos.ch, our dedicated git server. The idea is to push to git.qos.ch on a regular basis and to githib with lower frequency (say once a week). To add a remote server, the command is "git remote add github git@github.com:ceki/logback.git". Once github is added as a remote server, pushing to it is as easy as invoking "git push github master".

Now that the essential pieces are in place, the next step was to better understand git's philosophy by reading the Pro Git book.

After much of the initial migration was done, Jukka Zitting observed that the branches and tags which existed in the SVN repository were missing. Since I had removed the original git repo which was created from SVN, I had lost the branch and tag information. I had to re-import from SVN. Since the initial import contained metadata which I no longer wanted, my newly imported repository was incompatible with the earlier git repository containing new work but missing the tagging information. I did not want to waste half-a-day's work. I saved the new work with the ' git format-patch -o ~/patches/ 088f.." command, where 088f.. stands for the SHA-1 of my earliest commit since the SVN migration. Such information is very easy to obtain from the git.qos.ch and github servers.

The next step was to create the tags from the latest git repository. Since tags can be created a posteriori, all you need is the SHA-1 of the snapshot you want to tag. The "git for-each-ref refs/remotes/tags" does give you exactly that. Here is sample output:
a8f066010596dc.. commit refs/remotes/tags/SLF4J_1.3.0
260b5f6f9d0f14.. commit refs/remotes/tags/SLF4J_1.3.1
d8eadb09a11dbd.. commit refs/remotes/tags/SLF4J_1.4.0
7011d1f3665e88.. commit refs/remotes/tags/SLF4J_1.4.1
5fd428e3dd03ed.. commit refs/remotes/tags/SLF4J_1.4.2
04a8c2c2cf4230.. commit refs/remotes/tags/SLF4J_1.4.3


Which can be easily massaged into:
git tag -a SLF4J_1.3.0 a8f066010596dc -m "SLF4J_1.3.0"
...
...

Once the tags are created locally, they can be pushed remotely with "git push origin --tags"