SVN to GitHub How-To
- 1. Two-way mirror
- 1.1 Download SubGit
- 1.2 Configure repository
- 1.3 Install SubGit
- 1.4 Sync Git repository with GitHub
- 1.5 Fetch changes from GitHub
- 2. GitHub to SVN mirror
- 2.1 Download SubGit
- 2.2 Configure repository
- 2.3 Install SubGit
- 2.4 Sync Git repository with GitHub
- 2.5 Limitations
1. Two-way mirror
At the moment SubGit requires file-level access to Git repository which is not feasible with repositories hosted at GitHub. However, due to distributed nature of Git, one can establish reliable two-way mirror between SVN and SubGit-managed Git repository and then synchronize that Git repository with GitHub.
1.1 Download SubGit
As the first step get the latest version of SubGit from download page and unpack it. For more details and platform-specific installation information refer to SubGit book.
1.2 Configure repository
Run the following command in order to configure Git repository to mirror SVN project:
$ subgit configure --layout auto https://domain/svn/project project.git
Review and adjust Git/SVN authors mapping, you may use dynamic authors mapping replacing authors.txt with a script. Script sample could be found at project.git/subgit/samples directory:
$ edit project.git/subgit/authors.txt
Review and adjust branches mapping configuration:
$ edit project.git/subgit/config
And specify the following option there:
[svn]
...
triggerSvnPostReceive = true
...
1.3 Install SubGit
As soon as you have Git repository configured, enable Git-SVN mirror by running the following command:
$ subgit install project.git
As result SubGit performs initial import from Subversion repository to Git repository at project.git and keeps these repositories in sync.
1.4 Sync Git repository with GitHub
At this stage you have Git-SVN mirror and then you’d need to establish Git-Git mirror with GitHub repository:
$ cd project.git
$ git remote add github https://github.com/org/project
$ git push github --all --follow-tags
In order to send new commits from SubGit-managed repository to GitHub add the following user-post-receive hook and make sure it is an executable file:
$ echo 'git push --all --follow-tags github' > project.git/hooks/user-post-receive
$ chmod ug+x project.git/hooks/user-post-receive
Alternatively, you can specify only those branches you’re going to synchronize between Subversion and GitHub repositories:
git push github foo bar
Note that the user-post-receive hook gets triggered on every push to SubGit-managed repository and also every time SubGit fetches new revisions from Subversion repository as svn.triggerPostReceive option enables exactly that behavior.
1.5 Fetch changes from GitHub
In order to maintain reliable two-way mirror using setup described above, Git users have to push their changes to SubGit-managed Git repository rather than submitting changes to GitHub repository directly.
We recommend to disable write access to GitHub repository and submit any Git changes through SubGit mirror only.
However, often times it is required to synchronize changes arrived to GitHub with Subversion repository. In this case you’d need to setup a periodical job that fetches new commits from GitHub repository and applies them to SVN side of the mirror.
We do not recommend fetching new commits from GitHub repository to project.git repository directly. Instead, clone SubGit-managed Git repository to another location:
$ git clone --bare project.git clone.git
$ cd clone.git
$ git remote add github --mirror=fetch https://github.com/org/project
And then create the following executable file that synchronizes new commits arrived to GitHib with Subversion repository:
$ edit /path/to/script.sh
cd /path/to/clone.git
git fetch github
git push origin --all --follow-tags
Finally add this executable file to the cron table:
$ crontab -e
*/20 * * * * /path/to/script.sh
In this example cron job tries to synchronize GitHub and SVN repositories every 20 minutes.
Note that in case the same branch is concurrently updated from both SVN and GitHub sides, git push origin --all --follow-tags
command fails to push and synchronize new changes. This is the primary reason why Git users have to publish their changes through SubGit-managed Git repository rather than through GitHub repository.
In order to avoid possible concurrent access to the same branch from both Git and SVN sides, consider configuring SubGit mirror to fetch SVN revisions to a separate namespace:
trunk = trunk:refs/heads/svn/trunk
branches = branches/*:refs/heads/svn/*
tags = tags/*:refs/tags/svn/*
And then merge GitHub and Subversion histories manually:
$ git checkout master
$ git merge svn/trunk
$ git push origin master
2. GitHub to SVN mirror
In order to maintain read-write access to GitHub repository and still keep it in sync with Subversion repository, one may setup one-way mirror. In this case any changes submitted to GitHub repository get applied to SVN repository, however, Subversion server has to remain read-only for all SVN users.
2.1 Download SubGit
Just as in the previous example, the first step is getting the latest version of SubGit from download page and unpacking it. For more details and platform-specific installation information refer to SubGit book.
2.2 Configure repository
Run the following command in order to configure Git repository to mirror SVN project:
$ subgit configure --layout auto https://domain/svn/project project.git
Review and adjust Git/SVN authors mapping, you may use dynamic authors mapping replacing authors.txt with a script. Script sample could be found at project.git/subgit/samples directory:
$ edit project.git/subgit/authors.txt
Review and adjust branches mapping configuration:
$ edit project.git/subgit/config
2.3 Install SubGit
As soon as you have Git repository configured, enable Git-SVN mirror by running the following command:
$ subgit install project.git
As result SubGit performs initial import from Subversion repository to Git repository at project.git and keeps those repositories in sync.
2.4 Sync Git repository with GitHub
At this stage you have Git-SVN mirror and now you’d need to prepare Git repository for periodical synchronization with GitHub repository:
$ cd project.git
$ git remote add github --mirror=fetch https://github.com/org/project
Then create an executable file that fetches new changes from GitHub repository and applies them to Subversion repository:
$ edit /path/to/script.sh
cd /path/to/project.git
git fetch github
subgit fetch .
And finally add this executable to the cron table:
$ crontab -e
*/20 * * * * /path/to/script.sh
In this example cron job tries to synchronize GitHub and SVN repositories every 20 minutes.
2.5 Limitations
One-way GitHub to SVN mirror relies on the fact that no changes arrive to Subversion repository directly, every revision has to be committed to SVN repository via SubGit-managed Git repository. Here’s what happens when one commits a new revision to SVN repository directly:
-
subgit fetch
command fetches new revision from Subversion repository and applies this modification to corresponding Git branch; -
on next sync attempt
git fetch github
command overwrites that Git branch, so it matches GitHub repository; -
immediately after fetching changes from GitHub repository,
subgit fetch
command tries to apply these changes to Subversion repository and so it tries to replace SVN branch to its previous revision; in case svn.allowBranchReplacement option is enabled, SubGit deletes that SVN branch and re-creates it from its previous revision, otherwise this synchronization attempt fails with corresponding error message.
We strongly recommend to disable write access to Subversion repository and submit any SVN changes through SubGit mirror of GitHub repository.