Automatically mirroring SVN repositories to git and github

Updated 21 February 2013: the scripts below have now been adapted to run conveniently from cron and mirror multiple repositories. You can find full scripts and documentation on github

There are a number of scripts around, including an earlier blog post of my own, for making a once-off conversion of an SVN repository to a Git repository.

However, what if the project team is not yet ready for a full move to git? You may want to start benefiting from git (e.g. using the project as a submodule of another git project, or using for automated builds) while development officially continues to take place in SVN.

If you don't need to make commits into git just now, you can set up a mirror and refresh it periodically from SVN.

This process can be used with various SVN repositories, including Sourceforge and Google Code SVN repositories.

Process overview

  • An authors.txt file is created manually before the first run - see my other blog entry for convenient scripts to help generate authors.txt
  • A git-svn clone of the SVN repository is created. This clone needs to be retained between replication runs.
  • On each run, a temporary git repository is created. The svn-clone is rebased and pushed to the fresh git repository.
  • Fixes (e.g. branch renames and tagging) are made in the temporary git repository.
  • The final results are then pushed from the temporary repository to the real git mirror that is being maintained.
  • Finally, the temporary git repository is deleted, but the svn-clone is kept.

Here is a diagram of the workflow:

Config file

Here is a sample config file for the script, it mirrors the rather complicated reSIProcate repository with 10,000 commits:

SVN_LAYOUT="--trunk=main --branches=branches --tags=tags"

Of particular note here:

  • The $PROJECT_ROOT is where the svn-clone and the temporary repositories will be created
  • $GIT_REPO is the final destination repository. For testing, it could just be a local directory initialised with git init --bare .
  • In this repository, our trunk is actually called main, hence we have the layout argument --trunk=main. Many projects would just use --trunk=trunk

The script

The script itself is below. I'd suggest running it manually a few times first and observing how it behaves, disk space requirements, etc.


set -e

if [ ! $# -eq 1 ];
  echo "Usage:"
  echo "$0 "
  exit 1


. "${CONFIG_FILE}" || exit 1


if [ ! -d "${PROJECT_ROOT}" ];
  mkdir -p "${PROJECT_ROOT}"


if [ ! -d "${SVN_CLONE}" ];
  git svn clone \
    "${SVN_REPO}" \
    -A "${AUTHORS_FILE}" \
    ${SVN_LAYOUT} \
  cd "${SVN_CLONE}"
  cd "${SVN_CLONE}"
  git remote rm bare || echo "failed to delete remote:bare, proceeding anyway"
  git svn rebase \
    --fetch-all \
    -A "${AUTHORS_FILE}"

git remote add bare "${GIT_BARE}"
git config remote.bare.push 'refs/remotes/*:refs/heads/*'

if [ -d "${GIT_BARE}" ];
  rm -rf "${GIT_BARE}"

mkdir -p "${GIT_BARE}"
cd "${GIT_BARE}"
git init --bare .
git symbolic-ref HEAD refs/heads/trunk

cd "${SVN_CLONE}"
git push bare

cd "${GIT_BARE}"
git branch -m trunk master
git for-each-ref --format='%(refname)' refs/heads/tags | \
   cut -d / -f 4 | \
   while read ref;
      git tag "$ref" "refs/heads/tags/$ref"
      git branch -D "tags/$ref"
git remote add origin "${GIT_REPO}"
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
git push --tags origin master
git push --all

rm -rf "${GIT_BARE}"
svn-mirror.png32.65 KB


Hi Daniel, thanks a lot for the useful script! this is exactly what I've been looking for to begin the migration over to git :-) one problem though is that for very basic repos that have no branches (SVN_LAYOUT="") it raises errors and fails. I got it to work by making the git commands involving branches conditional upon SVN_LAYOUT being not empty.

The script works great for me, thank you for taking the time and posting it :)