Looking at git (Linus's distributed SCM) and finally grokking proper svn branch-trunk merge workflow
It looks like how git works is, every developer has their own repository, which only they have write access to. Then git makes it very easy to merge ("pull") from other people's repositories. So instead of pointing your svn client at the central repository and using 'svn update' to get changes from everyone, you 'git pull' changes from other people as required.
To give others access to your repository, you can have a remote mirror of your repository that you push changes to using 'git push', which pushes changes using SSH.
Alternatively you can use it (mostly) like cvs or svn, using 'git push' to push your local commits to a shared remote repository.
In other news, I finally figured out how to *properly* do a branch-to-trunk merge in Subversion. Way easier than expected. Until today I believed that you had to diff and patch to do this, but it turns out 'svn merge' isn't limited to just merging changes between two revisions of a branch; it lets you diff between branches as well.
Step 1: Fully merge changes from the trunk into your branch. So say if you branched at r100 and both the trunk (svn URL $svn/trunk) and branch (svn URL $svn/branches/mybranch) have changes, you do something like:
- find the HEAD revision (let's say it's 200).
- in the branch working dir:
svn up svn merge -r100:200 $svn/trunk (fix up conflicts as required) svn commit -m "merged -r100:200 from trunk" (this will make r201)
Step 2: Use svn merge to apply the current trunk→branch diff onto the trunk:
- in the trunk working dir:
svn up svn merge $svn/trunk $svn/branches/mybranch . svn commit -m "merged to r201 from mybranch" (this will make r202)
One nice thing about all this is that you have already fixed all the conflicts in the branch, so you should be able to commit straight after merging into the trunk. If you get conflicts there, something is screwed up (maybe someone committed between your trunk→branch merge and your branch→trunk merge), and you should stop and figure out what went wrong.
The limitation of course is that you need to fully merge from the trunk to the branch before doing this, so it's not amenable to cherry-picking. This is fine for me, though, as I like to work in a branch for a while, then when I'm happy, merge it into the trunk and delete the branch.
If you want to keep working in the branch after doing the merge, you can do so. Just remember that you merged everything into the trunk in r202, so your next trunk→branch merge should look like this:
svn merge -r202:HEAD $svn/trunk .
(if you didn't do the merge, you would be specifying -r200:HEAD, but if you do that after all this it'll try to put all your branch changes into the branch again, which will fail miserably.)
'course, if you were using git, you'd probably just pull back and forth between the repositories, or do some other sort of magic branch merge within a repository :)