I have beem using git for quite some time now, mainly git-svn. Now I want to convince my colleagues to switch from svn to git. But unfortunaly the precondition is that the svn repository keeps on living quite some time. So I searched for an solution and came up with the book:
Jon Loeliger's "Version Control with Git". I bought it and it is really good but I don't fully understand the guide to set up a git svn gatekeeper repo.
In Chapter 16, he describes a situation in which there is a Subversion repository, and at least a couple users that want to be using Git. He proposes a single "gatekeeper" git repository which is the only interface to subversion. After git svn cloneing the subversion repo (with --prefix=svn/), all the branches are then pushed to a bare repository (git push ../svn-bare.git 'refs/remotes/svn/:refs/heads/svn/', and other git users are told to clone this repo, which now contains local branches of all the svn remotes.
This part works and I think I fully understand it. But I don't get the next part:
If a developer that clones the bare repository pushes changes back from his repo to the bare repository and then I dcommit this in the bare repo to svn, the commits the user pushed are lost for good reason because of the replaced commits git-svn creates. Or am I wrong? How does this work?
The book says
Then, to merge back to subversion, in the gatekeeper repo, you do
git checkout svn/trunk (or other branch - this is checking out a detached head as svn/trunk is a remote) git merge --no-ff new-feature git svn dcommit
How can I checkout a branch in a bare repository? I don't think this works
This results in a merge commit on a detached head, and then the modified commit (after the git-svn-id line is added) is put on the real svn/trunk branch.
What is meant by real svn/trunk ?
The commit on the detached head is "worse than redundant. Using it for anything else eventually results in conflicts. So, just forget about that commit. If you haven't put it on a branch in the first place, it's that much easier to forget" (Jon Loeliger).
I'm a little confused. Has someone a better explanation for creating a git svn gatekeeper repo? I have searched the web and this site but I haven't found anything that seems suitable for me.
I'm so tired of wasting so many time with svn branching and merging, when collaborating with my colleagues.
Yes it does: you simply clone the bare repo locally, making a non-bare repo in the process, where you can checkout/create (again locally) as many branch as you want.
A bare repo is needed as an upstream repo where to push to. (see "
git push
only for bare repositories?")But in order to push anything to it, i.e for the other developers to push their changes in non-svn branches back to the gatekeeper repo, said other developer has to clone that bare repo first, make all the relevant modifications to the local copy, and push back to the bare repo.
Plus, you can setup some hook on that bare repo in order to validate your push: see "Hooks for git-svn".
Then to
dcommit
, the gatekeeper also clone that gatekeeper repo, from which he/she will:svn
' being the name of a remote repo), like 'svn/trunk
' for instancegit-svn dcommit
So to recap:
I don't think you should ever push changes back to the bare repo. I've got an example setup here that you could try out:
http://blog.tfnico.com/2010/10/gitsvn-5-centralized-git-svn-mirror.html
In my setup (which I've been employing for 3-4 months without any problems), changes should always "flow" through the SVN repository. I don't really understand this gatekeeper technique..
I have tried to automate the gatekeeper setup described by Jon Loeliger and got it working. He starts out very detailed about what steps to perform, but the part 'Merging Back into Subversion' is rather short. I have tried different setups with git-svn, also followed the excellent presentations/examples given by Thomas Ferris Nicolaisen and have used his example projects (with modifications) for testing out the 'gatekeeper setup':
Step 4 is not described by Jon Loeliger but I guess that's what he ment.
When it's time for merging back to subversion do:
Now we can follow the steps from the book:
My problem with this setup (and we have been warned earlier in the book) is that the history is squashed:
Now consider this alternative for merging back into subversion:
Now the commit-history is intact:
In order for this setup to work we need to use the 'git svn reset' command, or else the dcommit will fail the second time, because git-svn is confused about the current revision, and is behind (to same revision as when we created the bare-repo). This is probably because we used rebase, which in turn is necessary to get a nice linear history in subversion.
The big question is: What does 'git svn reset ' really do?
Is "forward reseting" a legitimate use of 'git svn reset' in this case?