Git and SVN together

Ever wonder if you can use git and svn to manage the same codebase? In this demonstration I check out a project from SVN, initialize a git repository within that SVN repository, and push it to GitLab, which is basically a self-hosted GitHub instance. Git doesn't notice svn, and svn doesn't notice git. Update from one and commit to the other!

Pre-reqs

In my instance GitLab was already set up somewhere and a user had been created with permissions to create a new project. It may be worth noting that for GitLab to be set up somewhere correctly, a UNIX user needs to be created with appropriate permissions. In these examples (and I'm guessing this is a convention for GitLab) that UNIX user is named git.

Let's put a SVN repository on GitLab!

Create an empty project on GitLab. Then I set up SSH keys. In other words, I already had a private key on my Windows PC that lived in C:\Users\stephen\.ssh\private_key.ppk. Note that this is a PuTTY private key. I used PuttyGen to convert it into an OpenSSH private key since Git on Windows prefers to use that form of a private key. I named this file id_rsa and stuck it in the same directory as the .ppk file.

I put my public key onto GitLab.

I then verified I could SSH to the GitLab server from my Windows PC by opening up the Git Bash and typing

$ ssh -vT git@gitlab.company.intra

That command shows helpful debugging information such as what private keys it's attempting to use.

Once that was all verified, I performed Git global setup (this is all in Git Bash on my Windows PC)

git config --global user.name "Stephen"
git config --global user.email "stephens@company.com"

And then created a local (on my Windows PC) git repository.

mkdir test_project
cd test_project
git init
touch README
git add README
git commit -m 'First commit'

And pushed it to GitLab

git remote add origin git@gitlab.company.intra:testproject/test_project.git
git push -u origin master

On GitLab you can see this initial commit and the empty README file.

Get your code from SVN

Leaving the Git Bash window open I opened up a second window... The good ol' windows command prompt. I have SVN installed on my Windows PC. I can verify this by running svn --version in the windows command prompt.

I then checked out the existing SVN repository.

(in Windows command prompt)
cd test_project
svn checkout http://build.company.intra:8001/svn/repo1/webapp-projects/project-parent/trunk

In the Git Bash window you can run a git status to see all the new untracked files Git noticed. We don't want Git to notice the SVN files and directories though. To make Git ignore all those .svn directories

(in Git Bash)
cd test_project
touch .gitignore

This just creates an empty file. I opened .gitignore in a text editor and added one line: .svn and saved it. Run git status once more and you should no longer see any .svn directories.

Let's commit everything to Git (including the .gitignore file).

(in Git Bash)
git add .
git status (notice the untracked files are now tracked and staged for commit)
git commit -m 'First commit of all files from SVN'
git push -u origin master

You should now see all your code on GitLab and none of the .svn directories.

Almost done. The last step is to get SVN to ignore the .git directory and the .gitignore file. Create a text file in your project directory ignorelist.txt with two lines

.git
.gitignore
README.md

And save that file.

(In Windows command line)
svn propset svn:ignore -F ignorelist.txt .

If you run svn status it should only complain about the ignorelist.txt file. Go ahead and delete ignorelist.txt now. The next time you run svn status it should be all be blissfully unaware of Git and the empty README file you had created.

Or, in picture form (my test_project in these photos is called allocation):

If you run git status in Git Bash it should say everything's all good and be blissfully unaware of SVN.

Some thoughts on this process

One thing I noticed while ensuring Git ignores SVN and SVN ignores Git is that SVN likes to store a .svn inside every directory whereas Git likes to store a .git only at the root directory.

Git makes it really intuitive and easy to ignore files or directories. You edit one text file that accepts different easy-to-understand syntax. The documentation regarding Git's ignore took just a minute to read and figure out. On the other hand, SVN's ignore features were very confusing to me and their documentation didn't help much. I had to consult this StackOverflow question and this blog post or this blog post. Seems like SVN's documentation needed documentation.

One thing this guide didn't cover is keeping track of all the SVN history and any branches or tags in SVN. We just simply copied the trunk of SVN into a new Git repository. If you look in Git, you won't see any of SVN's history. This was acceptable to our team, but may not be acceptable to other teams.

There is a git svn command. Read about it here. This does something differently (the second paragraph there is very helpful). The TL;DR is that it lets you use Git locally (say on your Windows PC) but at the end of the day commit to a SVN repository.

This means you can do local branching and merging, use the staging area, use rebasing and cherry-picking, and so on, while your collaborators continue to work in their dark and ancient ways.

But note that that is different than what we've done here. In this case, we have both SVN repository and a Git repository. We can commit to either. Which comes to another issue...

How often should you commit, and to which repository?

This is a tough question. My team likes SVN and we have 1-2 years of commit messages and versions of code saved there. I think for now I'll continue to consider SVN as the canonical repository but try to push to Git on a weekly (or daily?) basis so the Git repository stays up to date. When the day comes that we want to all use Git, we'll already have it set up!

We can also use Git to perform fast branches and experiments. Features that we want to keep around can be merged into master on Git and then committed to the canonical SVN repository.