Skip to content

Instantly share code, notes, and snippets.

@epicserve
Created September 15, 2011 17:17
Show Gist options
  • Save epicserve/1219858 to your computer and use it in GitHub Desktop.
Save epicserve/1219858 to your computer and use it in GitHub Desktop.
Convert SVN Repositories to Git Repositories

Convert SVN Repositories to Git Repositories

This guide on how to convert an SVN repository to a git repository was mostly taken from John Albin Wilkins post on Converting a Subversion repository to Git.

1. Retrieve a list of all Subversion committers

$ svn log -q https://svn.example.com/repository_name | \
awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); \
print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt

That will grab all the log messages, pluck out the usernames, eliminate any duplicate usernames, sort the usernames and place them into a "authors-transform.txt” file. Now edit each line in the file. For example, convert:

username = username <username>

into this:

username = Firstname Lastname <[email protected]>

2. Clone the Subversion repository using git-svn

git svn clone [SVN repo URL] --no-metadata -A authors-transform.txt --stdlayout ~/temp

3. Convert svn:ignore properties to .gitignore

If your svn repo was using svn:ignore properties, you can easily convert this to a .gitignore file using:

cd ~/temp
git svn show-ignore > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'

4. Push repository to a bare git repository

First, create a bare repository and make its default branch match svn’s "trunk” branch name.

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

cd ~/temp
git remote add bare ~/new-bare.git
git config remote.bare.push 'refs/remotes/*:refs/heads/*'
git push bare

You can now safely delete the ~/temp repository.

5. Rename "trunk" branch to "master"

Your main development branch will be named "trunk” which matches the name it was in Subversion. You’ll want to rename it to Git’s standard "master” branch using:

cd ~/new-bare.git
git branch -m trunk master

6. Clean up branches and tags

git-svn makes all of Subversions tags into very-short branches in Git of the form "tags/name”. You’ll want to convert all those branches into actual Git tags using:

cd ~/new-bare.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

7. Move bare repository to central remote repository

Example of how to move your local bare repository to a gitolite repository:

mv new-bare.git repository_name.git
tar czvf repository_name.git.tar.gz repository_name.git/
scp repository_name.git.tar.gz remote_host:
ssh remote_host
tar xzvf repository_name.git.tar.gz
sudo chown -R git:staff repository_name.git/
cd repository_name.git/
find . -type f -exec chmod go= {} \;  # remove group and world permissions
find . -type d -exec chmod go= {} \;  # remove group and world permissions
cd ../
mv repository_name.git /Users/git/repositories/

8. Clone new local copy

mv old-svn-copy old-svn-copy.backup
git clone git@remote_host:repository_name.git

List all unversioned files from your old local svn repository and copy them to the new local git repository:

cd old-svn-copy.backup
git clean -dXn  # Using this command because the old copy was a git-svn clone
cp example-file.txt ../repository_name/  # copy all files and directories from the list that you need in the new local git repository

You can now move the local svn copy backup to your trash. It might be a good idea not to empty your trash until your sure everything is working correctly.

9. Done.

@ertankucukoglu
Copy link

Hello,

Thanks for the tutorial. My svn repository was in same system as my new git. So I follow instructions until step 6.

After that, I tried to clone my main repository to my PC and I got warning and no files are cloned.
warning: remote HEAD refers to nonexistent ref, unable to checkout.

That warning gone after I modify ~/new-bare.git/HEAD file as following:
ref: refs/heads/master

Thanks & regards,
Ertan

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