Since I am working on project where the code is:
- currently in an SVN repository
- will be available on GitHub to the community
- will stay in SVN for use in internal projects
As I was trying to figure out a way to have this work with people making changes on the public version on GitHub, others making changes in the private version in SVN and in most cases propagating all changes in both directions. One idea is to have some working copies which are SVN only, some which are Git only and some which are both a Git and an SVN Working Copy and can be used to propagate changes.
Setup
The structure would looks like this:
So first I created the directories:
cd ~ mkdir playground cd ~/playground rm -rf ~/playground/svn ~/playground/git ~/playground/mix mkdir ~/playground/svn ~/playground/git ~/playground/mix
Then the working copies:
git clone https://github.com/benohead/my_product_name.git ~/playground/git/my_product_name svn co --username my_user --password my_password --non-interactive http://my_private_server/svn/my_product_name ~/playground/svn/my_product_name git clone https://github.com/benohead/my_product_name.git ~/playground/mix/my_product_name svn co --username my_user --password my_password --non-interactive http://my_private_server/svn/my_product_name ~/playground/mix/my_product_name
It can be done in almost any order but for the “mix” directory, you need to first create the git clone and then checkout from svn as git will complain if the directory is not empty.
Since the files were already there when we checked out, you’ll probably have many conflicts. It’s the reason I used the –non-interactive option. Like this the checkout happens without having to handle the conflicts right now. But later on, you’ll need to handle them in order to be able to check in. So we have two solutions either keep the GitHub files or use the SVN files (i.e. revert to the repository version).
Keeping the GitHub files
If you want to keep the GitHub files i.e. have the GitHub version of the files in both the GitHub and the SVN repositories, the first idea is probably to resolve the conflict saying we want to keep the working copy e.g.:
cd ~/playground/mix/my_product_name svn resolve --accept working -R *
Unfortunately after you do this, all files will be marked for deletion. This is because the files we have in there were there before the first checkout so they are considered unversioned files. So since there are no locally modified versioned files, svn will consider that when you say that you want to keep the local copy, you actually mean you want to delete the files. So after running the previous command, if you then commit, you’ll just delete all files.
So what do we do ? Can we only keep the svn version and not the GitHub version ? Of course not. The solution is actually pretty easy.
First, revert all files in the svn working copy.
svn revert -R *
After that you have the version from SVN (not what you want) but the conflicts are all gone. Then you reset in git to get back to the versions from GitHub:
git reset --hard
Now you have no conflicts and have the version from GitHub, you only need to check it in (in SVN):
svn ci -m "Sync with GitHub"
Now both repositories are in sync and the version we kept is the one from GitHub.
Keeping the SVN files
Basically, it starts the same way:
cd ~/playground/mix/my_product_name svn revert -R *
Now, you have the version from SVN. Now if you do a diff in GitHub, you’ll see the delta between svn and GitHub:
git diff
So all you have to do is to commit the changes and push them to GitHub:
git commit -a -m "Sync with SVN" git push origin
After that you also have a conflict-free state with identical versions of the files in both repository. The only difference is that now GitHub has the same files as SVN (instead of the opposite in the previous case).
Propagating changes
Then I tested the following:
- Make a change in a Git working copy
- Commit and push to GitHub
- Pull it from GitHub into the mixed working copy
- Commit to the private SVN repo from the mixed working copy
- Update from the SVN repo to a pure svn working copy
The first step… Well, use vim, nano, notepad or anything else (guess you know how to edit a file).
Then commit and push to GitHub:
cd ~/playground/git/my_product_name git commit -a -m "test" git push origin
Then pull it from GitHub into the mixed working copy:
cd ~/playground/mix/my_product_name/ git pull origin
Then commit to the private SVN repo from the mixed working copy:
svn ci -m "test"
And finally, update from the SVN repo to a pure svn working copy:
cd ~/playground/svn/my_product_name svn up diff ~/playground/git/my_product_name/my_modified_file ~/playground/svn/my_product_name/my_modified_file
You will then see that the file in the Git clone and in the SVN working copy are identical.