Daniel Pocock: 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 Travis-CI.org 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
Config file
Here is a sample config file for the script, it mirrors the rather complicated reSIProcate repository with 10,000 commits:
- An authors.txt file is created manually before the first run.
- 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.
Config file
Here is a sample config file for the script, it mirrors the rather complicated reSIProcate repository with 10,000 commits:
PROJECT_ROOT=/home/daniel/svn-mirror/resiprocate AUTHORS_FILE=$ PROJECT_ROOT /authors.txt SVN_REPO=https://svn.resiprocate.org/rep/resiprocate SVN_LAYOUT="--trunk=main --branches=branches --tags=tags" GIT_REPO=git@github.com:resiprocate/resiprocate.gitOf 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
#!/bin/bash
set -e
if [ ! $# -eq 1 ];
then
echo "Usage:"
echo "$0 <config-file>"
exit 1
fi
CONFIG_FILE="$1"
. "$ CONFIG_FILE " exit 1
SVN_CLONE="$ PROJECT_ROOT /svn-clone"
GIT_BARE="$ PROJECT_ROOT /git-bare-tmp"
if [ ! -d "$ PROJECT_ROOT " ];
then
mkdir -p "$ PROJECT_ROOT "
fi
cd "$ PROJECT_ROOT "
if [ ! -d "$ SVN_CLONE " ];
then
git svn clone \
"$ SVN_REPO " \
-A "$ AUTHORS_FILE " \
$ SVN_LAYOUT \
"$ SVN_CLONE "
cd "$ SVN_CLONE "
else
cd "$ SVN_CLONE "
git remote rm bare echo "failed to delete remote:bare, proceeding anyway"
git svn rebase \
--fetch-all \
-A "$ AUTHORS_FILE "
fi
git remote add bare "$ GIT_BARE "
git config remote.bare.push 'refs/remotes/*:refs/heads/*'
if [ -d "$ GIT_BARE " ];
then
rm -rf "$ GIT_BARE "
fi
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;
do
git tag "$ref" "refs/heads/tags/$ref"
git branch -D "tags/$ref"
done
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 "
</config-file>| Attachment | Size |
|---|---|
| 32.65 KB |
here's the list of my contributions around release-critical bugs for the
last week:








As you have probably already noticed, Google Summer of Code 2013 has been officially announced. As usual, we want to participate with
I wrote that I would 


We are searching a motive for a painting or a painting itself for a quite while now. This should find it's place in our living room.
Unfortunately we didn't found one, which matched our both prospect and/or wasn't compatible with the rest of our living room.
Yesterday we stumbled upon a motive which was quite nice, but was too small and it was neighter possible to get it in a bigger size nor to find out who was the origin painter of the picture. Now we are searching for the name of the picture and/or the painter.
The extension fields will most likely not show up in any normal
vCard reader, so those parts would have to go directly into a system
handling invoices. I am a bit unsure how vCards without name parts
are handled, but a simple test indicate that this work just fine.
Update 2013-02-12 11:30: Added KID to the proposal
based on feedback from Sturle Sunde.
With kids in the house, one challenge is getting them to sleep
during the night and wake up when it is morning. I mean, when I
believe it is morning, and not two hours earlier. In our household we
have decided that 07:00 is the turning point, but getting the kids to
sleep until 07:00 is a small challenge every day. They have adapted
quite well, and rarely wake up at 05:00 any more, but some times wake
up at times like 05:50, 06:15, 06:30 or 06:45, and it is hard to put
the awake one to bed again without disturbing and waking the rest.
And I understand perfectly well that they fail to sleep until 07:00
some times, as there is no way for them to know if it is before or
after the magic moment without coming and asking us parents.
But yesterday I came up with a method to solve this problem. It
involve home automation. A few years ago I bought a
Am I the only one who's disappointed with the route Mozilla's taking and left wondering what the direction is? First they
For the second year in a row, I've led the team that organized video
at FOSDEM. This year, most things went pretty smoothly; more so than
last year. We definitely learned from some of our mistakes, and although
I can't say that everything went better than it did last year,
after having done a first look at things I can certainly say that
overall, the result is better now than it was last year.
Our setup was very similar to what it was 




After 27 hours of travel, I'm finally back from my
first 
