Using Git and Subversion
After reading Richard Paul’s about using git on a subversion repository, I always wanted to give it a try. I don’t regret so far. Git handles branches and merging very well and I haven’t seen any weird thing such “obstruction” or “tree conflicts”.
This is my recipe to use git on a subversion repository from bash, also inspired on this very good article “Effectively using Git with Subversion” and completed by reading a lot.
How to use git on subversion
1.- Clone Subversion repository on your local computer using git
Git is a distributed version control system. Distributed means that every machine has a copy of the repository. In order to use Git on a Subversion repository you need to clone the svn repository on your machine: trunk, branches and tags.
git-svn clone -s http://example.com/my_subversion_repo local_dir
Notice that you should point to the root of the subversion repository, not to trunk. This was one of my problems in the begining.
The option -s means “I have the standard svn layout”, trunk, branches and tags.
You might want to add your svn ignore files:
git-svn show-ignore > .gitignore
2.- Create a story branch and use it
Once you have your git repository cloned from subversion you can start working. I normally create a “story branch” like this:
git checkout -b story_branch
You can see git branches using this command:
Or all git and subversion branches:
git branch -a
If you only want to work on a svn branch, just checkout the remote branch like this:
git checkout remote/svnbranch
This does not mean you are working on the remote repo, you are still working on your local copy. Once you finish your work, you have to send your changes to subversion. Keep reading.
3.- Staging and committing changes
Before committing your changes you need to “stage” them. Git has an intermediate area called “stage” and only commits files stored in the stage. Think about it as a mail outbox.
Before staging files you might need to know which ones have been changed. This command will tell you which files have been changed or created but untracked:
In order to “stage” the files you want to commit, run this command:
git add path/to/file
If you just want to stage all modified files (but not deleted) just run:
git add .
Adds all files (changed and removed)
git add -u .
Run git status again to verify that all the files you want to commit are in the stage area and then commit:
This will start your editor (vi for example) so you can enter a commit message. Remember that a good commit message should have:
- A title summarizing what’s been done, ideally containing the issue number from your project tracking application (Jira for example)
- A blank line
- A thorough description if necessary
If you want to skip the editor just run:
git commit -m "message"
4.- Get other developer changes into your branch (update)
Many times, other developers commit changes before you finish your task. If you want to incorporate other developers changes, first commit your changes, then rebase:
git svn rebase
This command is awesome! It just merges down changes from the original branch into your local branch. In other words, if someone modifies the remote ‘subversion trunk’ and your ‘git story branch’ was forked from your ‘git master branch’ (which is a copy of trunk), git will fetch those changes from svn trunk and will merge them into your ‘git story branch’. The documentation explains this command very well.
Updating without having to commit
Sometimes it isn’t reasonable since your changes are not yet ready to be committed (you haven’t finished/tested/improved your work). But don’t worry, git has a native solution also for this problem, just follow these steps:
- put aside your changes using the command: git-stash
- update your working copy using: git-svn rebase as usual
- take back your changes typing: git-stash apply
- clear “the stash” typing: git-stash clear
5.- Reverting uncommitted changes
In git this is called “reset”.
git reset --hard HEAD
I don’t understand completely how this command works yet but as far as I understand it moves the index of changes to the previous state.
6.- Reverting committed changes
git revert HEAD
This will create a new commit which undoes the change in HEAD
7.- Merging branch
Once you finish your task on your local ‘story branch’, you’ll probably want to merge it up into ‘master’. Change to the branch master first:
git checkout master
Rebase possible changes made on subversion trunk:
git svn rebase
git merge story_branch
This will try to run a “fast forward” merge by default, in other words, it will incorporate each commit on the ‘story branch’ and master will look as if no branch had existed before. I don’t like this because if you want to check the history you don’t have a way of knowing in which the branch was merged down into master.
My preferred option is “no fast forward”:
git merge --no-ff -m "commit message"
This does exactly the same as fast forward but it also generates an empty commit message so you can see in which commit the branch was merged. Besides, when you send your changes to svn you will see only one commit which looks very clean.
8.- Solving conflicts
This is just a question of editing the conflict, add it to the stage area and commit.
9.- Send your changes to subversion
git svn dcommit
10.- Amending commit messages
I had problems sending my changes to svn the first time because we are using pre-commit hooks and I forgot to include my issue number in the commit message. In order to modify commit messages, first I need to know the commit hash id:
And then I run the following command:
git rebase --interactive $parent_of_flawed_commit
Be aware you have to use the commit parent hash id.
An editor will come up, with a list of all commits since the one you gave.
- Change pick to reword (or on old versions of Git, to edit) in front of any commits you want to fix.
- Once you save, git will replay the listed commits.
Git will drop back you into your editor for every commit you said you want to reword, and into the shell for every commit you wanted to edit. If you’re in the shell:
- Change the commit in any way you like.
- git commit –amend
- git rebase –continue
11.- Get new branches from subversion
If you need to update your cloned version of subversion repository, just run:
git svn fetch
Final step: convince all your colleagues to use git and move to it! 😉