How to Migrate from SVN to Git

Notes to self. Should be a one-time move, but there were two issues that might be helpful to remember in the future if not.

Install Git, Setup SSH

On git server:

  • Install git
  • Setup and switch to git user
  • Setup ssh files
  • Setup directory that holds bare repos
sudo apt-get install git

sudo su
adduser git
su git

mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

mkdir ~/repos

On SVN server:

  • Install git and git-svn
  • Generate SSH keys and copy to git user on git server
  • Setup directory that will hold git repos cloned from SVN
sudo apt-get install git git-svn

ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub git@192.168.1.16

mkdir ~/repos

Convert from SVN to Git

On git server:

Create bare repo.

cd ~/repos
git init --bare REPONAME

On SVN server:

Retrieve a list of all SVN committers.

cd ~/repos

svn log -q svn+ssh://localhost/home/svn/athena/REPONAME | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt

In authors-transform.txt, convert SVN usernames…

username = username <username>

… to git usernames.

username = Firstname Lastname <username@example.com>

Clone SVN repo to a temporary directory.

git svn clone svn+ssh://localhost/home/svn/athena/REPONAME --no-metadata -A authors-transform.txt --stdlayout ~/repos/temp

If there’s a “malformed index info error“, then clone in batches:

git svn clone -r 0:<problematic_revision - 1> <repo URL>
git svn clone -r <problematic_revision - 1>:problematic_revision <repo URL>
git svn clone -r <problematic_revision>:HEAD <repo URL>

git svn clone -r 824:825 svn+ssh://localhost/home/svn/athena/REPONAME --no-metadata -A authors-transform.txt --stdlayout ~/repos/temp

Convert svn:ignore properties to .gitignore

cd ~/repos/temp
git svn show-ignore -i origin/trunk > .gitignore

git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'

Push temp repo to bare git repo. Some old instructions to need to be updated to add “refs/remotes/origin/*:refs/heads/*”

git init --bare ~/repos/REPONAME.git
cd ~/repos/REPONAME.git
git symbolic-ref HEAD refs/heads/trunk

cd ~/repos/temp
git remote add bare ~/repos/REPONAME.git
git config remote.bare.push 'refs/remotes/origin/*:refs/heads/*'
git push bare

Rename SVN “trunk” to git “master”

cd ~/repos/REPONAME.git
git branch -m trunk master

Clean up branches and tags

cd ~/repos/REPONAME.git
git for-each-ref --format='%(refname)' refs/heads/tags |
cut -d / -f 4 |
while read ref
do
  git tag "$ref" "refs/heads/tags/$ref";
  git branch -D "tags/$ref";
done

Move bare repo on SVN server to bare repo on git server

git remote add origin ssh://git@192.168.1.16/home/git/repos/REPONAME.git
git push origin master

Clone Project Locally

On local development machine:

Create ssh keys for regular user, clone project from git server to work on locally. In this case the local development machine is the git server (hence, localhost).

ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub git@localhost

git clone ssh://git@localhost/home/git/repos/REPONAME.git

Empty directories aren’t stored in git, so recreate them and add a .gitignore file with the contents below:

# Ignore everything in this directory
*
# Except this file
!.gitignore

Install a git gui. Many exist, git-cola is available in the default ubuntu repository. Use meld to diff files.

sudo apt-get install git-cola meld

Appendix

I initially cloned from the local files instead of SSH, but ran into permission problems since the bare repos are owned by the git user. You can reclone like above or change the origin using the commands below. The first lists the current origin, the second changes it to SSH using the git user.

git remote -v
git remote set-url origin ssh://git@localhost/home/git/repos/REPONAME.git