A safe way to keep a github and svn repository in sync
My current project requires me to share code with another team who use svn while my team are on github. To keep commits up to date I have to keep both version control systems in sync so that merges are easy. After some experimentation and failures I have worked out a relatively safe way to let the two coexist without any nasty conflicts. There is varied documentation on the web on how to do this e.g on github help and stackoverflow.
It is generally a bad thing to allow github and svn push changes into the same repo. And scary things can happen to the history, which I found out the hard way (luckily git rebase and reset are real lifesavers).
Git is built on the concept of a local repository which is kept in sync with one or more remote repositories. As far as the svn connection works, git treats it as another remote repository with a difference in the way it syncs with the local repo.
My local git repo is set up with two remotes - one is svn the other is github. To keep the two worlds safe I will make two branches. One tracks only the svn remote and the other tracks only the github remote. Then I treat the two branches as if they were separate forks. So I do not pull from another remote onto a branch but I use git-merge instead.
Setting Up
I start with a git repo that has a github origin and I create a branch for the work that will be tracked on github and shared with the svn branch - this is a normal git branch or it could be master.
git branch mygitbranch git checkout mygitbranch git push origin mygitbranch
Separately, I have an svn repo with the same version of the source files as github.
Now, I create the svn-tracking branch as a non-tracked branch in my local git repo:
git branch --no-track mysvnbranch <id of very first commit> git checkout mysvnbranch
Next connect to the svn repo, pull the source into this branch and force the svn repo changes to be the only changes in this branch.
git svn init https://my.svnrepo.org/svn/repository/whatever/ -s git svn fetch git reset --hard remotes/trunk
So my tree now looks something like this (with the tracked remote in bracket):
_.___ master (remotes/origin/master) |._ mygitbranch (remotes/origin/mygitbranch) _.__._ mysvnbranch (remotes/trunk)
Merging
Down the road, there are changes in the github-tracked branch and I need to sync these to the svn repo. e.g.
git checkout mygitbranch git pull origin mygitbranch _.___ master (remotes/origin/master) |__._.__._ mygitbranch (remotes/origin/mygitbranch) _.__._ mysvnbranch (remotes/trunk)
Switch to the svn tracked branch, merge the differences with the github tracked branch and commit the changes. But also remember to rebase on to the svn changes first:
git checkout mysvnbranch git svn rebase (need to fetch and rebase any changes that were made in svn) git merge origin/mygitbranch git mergetool (if there are conflicts that cannot be automatically resolved) git commit git svn dcommit
So the branches will now look like this:
_.___ master (remotes/origin/master) |__._.__._ mygitbranch (remotes/origin/mygitbranch) _.__.________\._ mysvnbranch (remotes/trunk)
And similarly for the reverse case:
git checkout mygitbranch git pull origin mygitbranch git merge remotes/trunk git commit git push origin mygitbranch
Th point here is that the svn-tracked branch will only ever track the svn remote. It is possible to push mysvnbranch to github but the danger is that it will receive other pushes and that leads to the problem of keeping two incompatible histories in sync.
