Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Migrates multiple SVN repos to Git, without anything fancy (no Ruby, no dependencies, no issues with Cygwin paths). Works with GitHub or any Git repo.
Migrates multiple SVN repos to Git, without anything fancy (no Ruby, no dependencies, no issues
with Cygwin paths). SVN tags are created as Git tags and properly pushed to the Git repo. To run:
1) Edit run-authors.sh to have your SVN repos. Run it to get an authors.txt file.
2) Edit the authors.txt to have the names and emails if you like. You must use GitHub user email
addresses if you want contributions to be associated with GitHub accounts.
3) Edit run-convert.sh to have your SVN repos and project name (for local temp directories). Run it.
4) Optionally, for each repo run this command to identify the largest 1000 files:
cd repo.git
join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -1000 | sort) | sort -k3 -n
Then run BFG Repo Cleaner to delete files that are too large:
https://rtyley.github.io/bfg-repo-cleaner/
java -jar bfg.jar --strip-blobs-bigger-than 100M repo.git
cd repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
5) Create each Git repo on the server: git init --bare reponame.git
Or if creating new repos on GitHub, don't populate them with a readme or license.
Push to server using your repo URL:
cd repo.git
git push --mirror --follow-tags ssh://your.com/url/repo.git
6) Done! Isn't Git fun!
cp authors.txt authors.temp
svn log -q $1 | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u >> authors.temp
cat authors.temp | sort -u > authors.txt
rm authors.temp
svn_url=$1;
name=$2;
echo "Cloning SVN repository to $name.svn... $svn_url"
rm -rf $name.svn
git svn clone $svn_url --no-metadata -A authors.txt --stdlayout $name.svn
cd $name.svn
echo "Creating .gitignore file..."
git svn show-ignore --id=origin/trunk > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'
echo "Initializing Git repository... $name.git"
cd ..
rm -rf $name.git
git init --bare $name.git
cd $name.git
git symbolic-ref HEAD refs/heads/trunk
echo "Pushing to Git repository... $name.git"
cd ../$name.svn
git remote add bare ../$name.git
git config remote.bare.push 'refs/remotes/origin/*:refs/heads/*'
git push bare
echo "Renaming trunk to master..."
cd ../$name.git
git branch -m trunk master
echo "Converting SVN tag branches to Git tags..."
git for-each-ref --format='%(refname)' refs/heads/tags | cut -d / -f 4 |
while read ref
do
git tag -a "$ref" -m "Tag: $ref" "refs/heads/tags/$ref";
git branch -D "tags/$ref";
done
echo "Done!"
rm authors.txt
sh authors.sh http://kryo.googlecode.com/svn
sh authors.sh http://kryonet.googlecode.com/svn
sh authors.sh http://minlog.googlecode.com/svn
sh authors.sh http://reflectasm.googlecode.com/svn
sh authors.sh http://jsonbeans.googlecode.com/svn
sh authors.sh http://yamlbeans.googlecode.com/svn
sh authors.sh http://tablelayout.googlecode.com/svn
sh authors.sh http://reflectasm.googlecode.com/svn
sh authors.sh http://wildcard.googlecode.com/svn
sh authors.sh http://scar.googlecode.com/svn
sh convert.sh http://reflectasm.googlecode.com/svn reflectasm
sh convert.sh http://kryo.googlecode.com/svn kryo
sh convert.sh http://minlog.googlecode.com/svn minlog
sh convert.sh http://kryonet.googlecode.com/svn kryonet
sh convert.sh http://reflectasm.googlecode.com/svn reflectasm
sh convert.sh http://jsonbeans.googlecode.com/svn jsonbeans
sh convert.sh http://yamlbeans.googlecode.com/svn yamlbeans
sh convert.sh http://table-layout.googlecode.com/svn tablelayout
sh convert.sh http://wildcard.googlecode.com/svn wildcard
sh convert.sh http://scar.googlecode.com/svn scar

C-Duv commented Dec 12, 2013

Thanks, your scripts were very handy.
Had some issue with git svn show-ignore that failed: fixed it by using --id trunk argument.

Also had special needs (no GitHub, preserve empty directories, add a develop branch) so I've improved them.
If that's of any help to anyone, here they are: https://github.com/C-Duv/sysadmin-scripts/tree/master/gitlab/svn2gitlab

Owner

NathanSweet commented Nov 14, 2016

Glad it was helpful. Doing this again, I also found show-ignore failing. I ended up needing git svn show-ignore --id=origin/trunk. Thanks for the tip!

I also found git push bare on Windows didn't work from a command prompt, but did from a Cygwin prompt (that was a huge WTF). Lastly I found I needed git config remote.bare.push 'refs/remotes/origin/*:refs/heads/*' (note the added "origin").

Both changes have been made to the gist above.

All this worked without changes back when I made the Gist initially. Git is ridiculous!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment