Reconciling cat and dog - the most productive git-svn
setup
I would like to present productive and effective setup for the git-svn
bridge which removes most of the obstacles and fixes some problems which occur with this bridged approach.
Configuration
Before we start - one remark: if you installed git
on your machine first time ever, please remember about setting up proper user, email and one-more-thing just for convinience:
~ $ git config --global user.name "Your Name Here"
~ $ git config --global user.email "your_email@example.com"
~ $ git config --global credential.helper cache
Starting
At first, you need to clone
(or checkout
in SVN terminology) repository. You can do in three different ways:
- First way (2nd line) checkouts repository with a standard SVN layout (
trunk
,branches
,tags
) and associates branches, tags andtrunk
withgit
master
. - Second way (5th line) checkouts whole repository as it is.
- Third way (starts in 8th line) is really an expansion for
git-svn clone
.
1
2
3
4
5
6
7
8
9
10
11
# Standard layout.
~ $ git svn clone -s $SVN_REPOSITORY_ROOT_URL
# Non-standard layout.
~ $ git svn clone $SVN_REPOSITORY_ROOT_URL
# 'git svn clone ...' is basically a shortcut for these commands:
~ $ mkdir REPOSITORY
~ $ cd REPOSITORY
~ $ git svn init $SVN_REPOSITORY_TRUNK_URL .
~ $ git svn fetch -r HEAD
Updating and commiting
Besides pull
and push
(or update
and commit
in SVN terminology) everything works like in classical git
.
First line represents svn update
command, second - series of svn commit
commands with messages collected inside local git
repository.
1
2
~ $ git svn rebase
~ $ git svn dcommit
Ignores
If you cannot store your .gitignore
file in the SVN repository you can exclude these files locally:
~ $ git svn show-ignore >> .git/info/exclude
But .gitignore
file can be very convenient - you can easily share exclusions with other members of the team which also use this bridged approach. Moreover, this command is really slow for bigger repositories, so that is another advantage of having this file.
Branches
If your repository does not have standard layout you can still easily associate SVN branch in your .git/config
by adding new svn-remote
section:
[svn-remote "sample_branch"]
url = https://svn_repository/branches/sample_branch
fetch = :refs/remotes/sample_branch
Then you should run (and develop the habit of running):
~ $ git svn fetch --fetch-all
As the last step, you need to checkout
new branch:
~ $ git checkout -b sample_branch remotes/sample_branch
After that your branch will be available like normal git
branch. Remember that your trunk
is actually a git
master
branch.
Removing empty directories
Regarding the git-svn
bridge, dangling empty directories are my nightmare. Fortunately, someone thought about it and we can enable deleting empty directories on commit (globally via git-config
or on demand just for certain commit):
~ $ git config svn.rmdir true
~ $ git svn dcommit --rmdir
Problems
There are still a few problems with the newest SVN clients for such combination. The most annoying is assertion … failed related to the renaming operation. This error looks like this example:
~ $ git svn dcommit
Committing to http://...
C path/to/file/a.js => other/path/to/file/b.js
assertion "svn_fspath__is_canonical(child_fspath)" failed: file "dirent_uri.c", line 2502, function: svn_fspath__skip_ancestor
At first glance you may think that the only (and the worst possible - lost information and mess in history) option is to split your commit into two. Happily, you can perform your commit normally but you need to turn off rename detection:
~ $ git svn dcommit -C1 -l1
Unfortunately you will still commit two changes, this time in one batch (as a deletion the old file and creation file with the new name), instead of just a file rename, so you will still loose information in the process.
To avoid this completely the only option is to downgrade SVN client to the latest version on 1.7.X
branch.
Credits
Big thanks to @skremiec for undeceiving me in some cases and pointing out svn.rmdir
option .