When possible, it is recommended to completely migrate a Subversion repository to Git; this is quite simple to do and mostly depends on the size of the Subversion repository and the organization.
If the repository follows the standard layout as described before, a migration is only a matter of minutes.
If your Subversion repository has been used from different people, you are probably interested in preserving the commit author's name, which is true even in the new Git repository.
If you have the awk
command available (maybe using Cygwin in Windows), there is a script here that fetches all the users from Subversion logs and appends them to a text file we can use in Git while cloning to perfectly match the Subversion users, even in Git-converted commits:
$ svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt
Now we will use the authors.txt
file in the next cloning step.
To begin the migration, we have to locally clone the Subversion repository as we did before; I recommend once more adding the --stdlayout
option to preserve the branches and tags and then to add the -A
option to let Git convert commit authors
while cloning:
$ git svn clone <repo-url> --stdlayout –-prefix svn/ -A authors.txt
In case the Subversion repository has trunks, branches, and tags located in other paths (with no standard layout), Git provides you with a way to specify them with the --trunk
, --branches
, and --tags
options:
$ git svn clone <repo-url> --trunk=<trunk-folder> --branches=<branches-subfolder> --tags=<tags-subfolder>
When you fire the clone
command, remember that this operation can be time- consuming; in a repository with 1000 commits, it is not unusual to wait 15 to 30 minutes for this.
To preserve the previously ignored files in Subversion, we can append the svn:ignore
settings to the .gitignore
file:
$ git svn show-ignore >> .gitignore $ git add .gitignore $ git commit -m "Convert svn:ignore properties to .gitignore"
Now that we have a local copy of our repository, we can move it to a brand new Git repository. Here you can already use a remote repository on your server of choice, which can even be GitHub or Bitbucket, but I recommend that you use a local bare repository; we may as well do some other little adjustments (like renaming tags and branches) before pushing files to a blessed repository. So, first initialize a bare repository in a folder of your choice:
$ mkdir ReposMyGitRepo.git $ cd ReposMyGitRepo.git $ git init --bare
Now make the default branch to match the Subversion trunk
branch name:
$ git symbolic-ref HEAD refs/heads/trunk
Then add a bare
remote pointing to the bare repository just created:
$ cd SourcesMySvnRepo $ git remote add bare file:///C/Repos/MyGitRepo.git
Finally push the local cloned repository to the new bare one:
$ git push --all bare
We now have a brand new bare repository that is a perfect copy of the original Subversion repository. We can now adjust branches and tags to better fit the usual Git layout.
Now we can rename branches and tags to obtain a more Git-friendly scenario.
The Subversion main development branch is /trunk
, but in Git, as you know, we prefer to call the main branch master
; here's a way to rename it:
$ git branch -m trunk master
Subversion treats tags as branches; they are all copies of a certain trunk snapshot. In Git, on the contrary, branches and tags have a different significance.
To convert Subversion tags and branches into Git tags, the following simple script does the work:
$ 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