Saturday, June 4, 2011

migrate Subversion repository/dump to Git & Github, with tags and branches

A simple and complete method for migrating from subersion to git, bringing over past tags and branches.

I migrated a work repository from Subversion to Git last week. It went surprisingly smoothly. There were a more steps than I expected after reading various, selected, sources.

My repository was in "standard layout" containing only a single tree/project. I was sent a dump of the repository created with svndump. If you have direct access to your svn repository, skip step one. Similarly you can skip the github steps or replace them with your own "primary git server."

Note, if you don't want to maintain the svn tags and branches, then there is a simple single step solution using git-svn. This works if you don't have tags and branches to keep, or you just want a personal git checkout of a remote svn repository.
git svn clone --no-metadata --stdlayout --A users.txt http://svn/repo/here/ new_checkout_name/

Overview:

  1. import svn dump into svn repository
  2. create mapping file of svn committer to email address
  3. create empty git repository
  4. cd to git repository
  5. import from svn repo to git repo
  6. pull branch and tag information from svn to git
  7. create github repository
  8. add remote repository
  9. push all tags and branches to github repository.
Steps:
  1. import svn dump into svn repository from dump file svn_repo.dump
    % svnadmin create svnrepo
    % svnadmin load svnrepo < svn_repo.dump
  2. create mapping file of svn committer to email address
    Create a file called authors.txt and fill it with line separated “svn-name = git-name ” pairs.
    #example:
    % cat authors.txt
    user_a = Alpha <alpha@example.com%gt;
    user_b = B Dawg <bdawg@github.example.com%gt;
  3. create empty git repository
    % mkdir gitrepo
    % git init gitrepo
  4. import from svn repo to git repo
    #   git svn clone file:///pathto/svnrepo /pathto/gitrepo –no-metadata -A authors.txt --stdlayout
    svn repo path must be an absolute path when using file://
    % git svn clone file://$(pwd)/svnrepo gitrepo/ --no-metadata -A authors.txt --stdlayout
  5. cd to the git repository
    % cd gitrepo
  6. pull branch and tag information from svn to git
    tags and branches are both viewed as remote branches, tags are prefixed with "tag/".
    For each branch you want to migrate, make a local branch.
    For each tag, make a local tag.
    % git svn fetch                          # fetch remote branches and tags from svn
    % git branch -r                          # view remote branches
    % git branch local_branch remote_branch  # for each branch to migrate
    % git tag local_tag tags/remote_tag      # for each tag to migrate
    % git branch                             # check work by viewing local branches and ...
    % git tag -l                             # ... local tags 
  7. create github repository
    ( github repo ui, create yourrepo )
  8. add remote repository
    % git remote add origin git@github.com:yourname/yourrepo
  9. push all tags and branches to github repository.
    % git push origin --tags   # push all tags
    % git push origin --all    # push all branches 

3 comments:

sundar said...

As many svn->git migrations as I've read about over the years I've never seen anything quite as concise as this. The missing ingredient is a simple bash script that does this (the svn2git script in gitorious and the svn2git gem have problems and do not handle error cases well). I'm in the process of writing one which I'll post a github link to once it's done

sundar said...

This sucks. After I spent a few hours working on a script I decided to look harder since it seemed too obvious that someone would not already have as SVN->GIT migration script that was better that svn2git. Voila:
https://github.com/JohnAlbin/git-svn-migrate

Anonymous said...

I run into trouble with the --no-metadata. If that's there then a subsequent "git svn rebase" says: "Unable to determine upstream SVN information from working tree history".

If I leave the --no-metadata out, it works.