You are a Git user. Unfortunately for you, your team’s codebase is stored in a Subversion repository. Much of the deploy code and all of the team’s workflow depends on this Svn based repository. If a conversion to a Git repository ever happens, it could be quite some time away. What do you do?
Git Svn to the rescue
One of the many wonderful things about Git is that it allows you to use much of your typical Git workflow on top of a Subversion repository. Of course, it is not a 1:1 match, and there are some caveats. But using Git’s Svn tools can make certain aspects of working with Svn more dynamic and, frankly, bearable. It can also be the perfect set of tools if you are planning to transition your team from Subversion to Git, allowing them to learn the git workflow without completely taking off their Svn training wheels.
Where to begin
For the sake of simplicity, let’s say your team works exclusively out of the Trunk of your Svn repo. What would your workflow look like? Here’s what mine looks like:
- Grab the latest files
- Start a new branch task branch
- Do Work! in task branch
- local commit
- local commit
- local commit
- merge task branch into master branch
- Update to latest from Svn
- Commit to Svn repository
- GOTO 2
Let’s explore each of these in some greater detail.
1. Grab the latest files
This is the obvious place to start. It’s pretty simple.
~$ git svn clone http://my-project.com/path/to/trunk my_project
2. Start a new branch task branch
The importance of this step may not be so obvious, but it really does help to keep your project code clean. I like to think of my master branch as a holy portal to the Svn Trunk. Whenever possible I like to avoid doing ANY coding in it. Instead all of my work is done in separate task branches. This way I can have many concurrent tasks and projects going on within the codebase without dirtying the Trunk. Changes are merged into the master and therefore the Trunk, only when they are complete.
my_project $ git checkout -b task_1234 Switched to a new branch 'task_1234'
-b flag simply creates a new branch with the given name.
3. Do Work!
Here you do what you get paid to do. Lay down fat patches of code while sipping your Yerba Mate and looking cool. Periodically as you find it necessary to document / save your progress through task #1234, you will commit your changes. Since you are using Git now, these changes will be committed locally. Nobody else will know about them until you push the lot of them to the server. First lets take a look at the files we have modified.
my_project $ git status # On branch task_time # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: foo/bar.rb # modified: foo/baz.rb # no changes added to commit (use "git add" and/or "git commit -a")
Notice that it says ‘Changes not staged for commit’. Git will not assume you want to commit anything, until you tell it to. To make sure you get those modified files staged for commit, you must use the
git add command. You can add the files individually:
my_project $ git add foo/bar.rb foo/baz.rb
or all at once:
my_project $ git add .
Now you commit:
my_project $ git commit -m "Very helpful commit message about all the things I did."
You can optionally skip
adding the files and tell git to include all modified files automatically with the
-a flag, if you want:
my_project $ git commit -am "Very helpful commit message about all the things I did."
4. Merge task branch into master branch
Now you’ve finished task 1234. It’s almost time to push all of your hard work onto the server so everyone can enjoy it. First you
checkout the master branch and merge your task branch into it.
my_project $ git checkout master Switched to branch 'master' my_project $ git merge task_1234 Updating d3f90e3..8fc94aa Fast-forward foo/bar.rb | 10 ++++++++++ foo/baz.rb | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-)
Now master has been updated with all of your work on the task_1234 branch.
5. Update to latest from Svn
This helps you avoid conflicts and makes sure you’re always up to date before committing.
my_project $ git svn rebase
6. Commit to Svn Repository
Now you can cross your fingers and send in your code.
my_project $ git svn dcommit
7. GOTO 2
Now that you’ve impressed everybody with your ingenious coding prowess, it’s time to do it again. For good measure, you’ll start by deleting your task branch since you’re no longer going to use it.
my_project $ git branch -D task_1234
And that’s it. Now go to step 2 and repeat the process.
Parallel task branches
What happens, though, if you’re in the middle of task 1234 and another task comes along that you have to attend to RIGHT NOW, but you’re not quite ready to release your code for task 1234? It’s pretty simple. You start a new task branch. But remember, you don’t want this new task branch tainted with your code from branch task_1234, so you’ll want to create it from the master branch.
my_project $ git checkout master Switched to branch 'master' my_project $ git checkout -b hotfix Switched to a new branch 'hotfix'
When you’re done with hotfix, merge it back into the trunk,
git svn dcommit it, then checkout your task_1234 branch again to resume your normal work. Unfortunately, now your code for task_1234 is slightly out of sync with your master branch. To fix this, you use the
git rebase command.
my_project $ git checkout task_1234 Switched to branch 'task_1234' my_project $ git rebase master
Now your hotfix changes have been added to your task_1234 work.
Adapting to your new workflow
This article is obviously not an exhaustive explaination of Git’s functionality. Honestly, it’s almost certainly nowhere near “best practices”. It should be enough, however, to get you started. Sure, you will run into issues and, as is always the case, merging conflicts will get pretty annoying, especially with your new set of unfamiliar tools. Google is your friend though and, without a doubt, somebody on Stackexchange will have had the same problems as you.