Recently I’ve been using bzr-svn when I’m working with subversion repositories; its a bridge between a local bzr repository and a remote subversion one. I travel fairly frequently and the pain of being disconnected from the server, unable to diff or log, and then either unpicking everything I’ve done or sending a monster commit with the message “Things Lorna did in the last 2 days” is just tedious and annoying. Possibly more tedious and annoying for the rest of the team than me even, so a better solution is more than welcome!
Some time ago I blogged about starting to use bzr-svn but its taken me a while to get past those first steps. Having the repo locally is so fast to use, and the speedy diff and log functionality had me completely sold straight away. I’ve been mildly annoyed by bzr squashing my commits though, meaning that I’m still doing a single monster commit to subversion when I come back online after being gone for a few days.
Today, with some help from the very lovely people in the #bzr channel on freenode, I found out how to preserve my commit history when sending the changes back to subversion from bzr-svn. The bzr-svn user guide recommends a particular set of commands, but this includes merging your changes into the mirror of SVN. Even in a standard bzr branch, this would show in the logs as a single, combined commit.
Push, Don’t Merge
The key to retaining the commit history is to push changes from the branch, rather than merging into the trunk mirror. To make this clearer, I’ve shown an example. The SVN is checked out into lorna-trunk and I’m making changes in the lorna-branch directory, including adding the db directory and the hello.php file.
$ bzr commit -m "initialising database files and hello.php"
Committing to: /home/lorna/data/personal/publish/tek10/svn_vs_distributed/bzr-svn-example/lorna-repo/lorna-branch/
added db
added hello.php
added db/setup.sql
Committed revision 2.
$ bzr push ../lorna-trunk/
All changes applied successfully.
Pushed up to revision 2.
No matter how many times you commit, when you push, all your changes will be sent to subversion as individual commits in the same way. This will really help me next time I’m offline for a little while!
When There Are Changes In Subversion
Charmingly, while answering my questions to get me this far, the #bzr channel inhabitants then immediately explained to me that to handle changes in subversion, I’d have to rebase my branch before I could push my changes. This is because you can only push to a branch that is in sync with where yours was when you started making changes. If you try to push to subversion when there are changes in it, you will see this error:
bzr: ERROR: These branches have diverged. See "bzr help diverged-branches" for more information.
All I needed to do was to run bzr update in the mirror, and then rebase my branch onto that. At first my system didn’t recognise the rebase command, but this was because I needed to install the bzr-rebase package (called bzr-rewrite in newer versions but bzr-rebase in mine, Ubuntu 9.10 Karmic Koala). Rebasing was easy to do and brings the changes from the repo into your working branch. Here are the commands and how the output looked for me (with shortened paths to make this more readable):
lorna@taygete:~/.../lorna-branch$ cd ../lorna-trunk/
lorna@taygete:~/.../lorna-trunk$ bzr update
+N readme
All changes applied successfully.
Updated to revision 3.
lorna@taygete:~/.../lorna-trunk$ cd ../lorna-branch/
lorna@taygete:~/.../lorna-branch$ bzr rebase ../lorna-trunk/
All changes applied successfully.
Committing to: /home/lorna/.../lorna-branch/
modified hello.php
Committed revision 4.
lorna@taygete:~/.../lorna-branch$ bzr push ../lorna-trunk/
All changes applied successfully.
Pushed up to revision 4.
I haven’t had a lot of experience with using this in difficult situations with complex branching or conflicts yet, if you have any tips to add though, a comment would be excellent :)