Thursday, November 12, 2009

git svn checkout

git-svn checkouts are pretty simple, but here's a reference anyway:

Checking out the SVN tree within GIT
$ mkdir git-svn-project
$ cd git-svn-project
$ git svn init https://svn.server.url/repos/svn-project
$ git svn fetch

Staying up-to-date with upstream SVN commits
$ git svn rebase

Commiting back to SVN
$ git commit -a
$ git svn dcommit

git-svn and failed svn commit hooks

The workflow of using GIT with SVN can be a steep learning curve. After the easy part of getting an SVN checkout within GIT, you could end up in a situation where an SVN pre-commit hook fails, leaving your in a bit of a muddle.

The solution to this may not be immediately obvious, so it's necessary to understand what GIT is doing under the hood.

When you have a git-svn checkout, git maintains the svn repository state in a remote branch. You work within your local branch and commit changes locally. When you're ready to commit back to SVN you'd normally just do a "git svn dcommit".

If you make some local git changes and commit locally, then do the dcommit that is rejected by a pre-commit hook, then normally in SVN you would fix the error locally and re-try your commit. In GIT the commits have been separately checked-in locally, so GIT will try to commit each change separately to SVN - but this won't work because the first local commit was rejected by SVN.

The solution is to create a new git branch, forked from the current branch just before your rejected commit. To do this you would first want to look at "git log" to get the commit hash from git, then create your new branch and change to it:

$ git log
# find the commit hash you're after
$ git branch temporary_branch 68b8976ba0944
$ git checkout temporary_branch
$ git merge --squash dd7354fcd397 7f5e78f7e737ed4 5e07bf3c6f5c15
$ git svn dcommit

You'll then want to go back to your local master git branch, and likely clean up after yourself:
$ git checkout master
$ git svn rebase
$ git reset --hard HEAD
$ git branch -D temprorary_branch

Disclaimer: You'll want to check the last "reset --hard" and "branch -D" commands do lose anything before running them. I.e. don't do anything here without understanding it first!