Bazaar


Sections | Installing the Game | Playing the Game | Competition Hub | Server Administration | Extending Armagetron Advanced | Development Docs


Bazaar(bzr) and how we use it

This is work in progress and has not yet been approved by management. Hold your horses.

What it is

Bazaar(bzr) is a distributed version control system in the spirit of arch, git, darcs or mercurial. It allows more flexible workflows than SVN, especially when contributions from outside of the core development team enter the picture. Bazaar allows you to keep an arbitrary number of copies of a project's code with full version history, and lets you move changes from one copy to another without going over a central server.

What we're doing with it

Our main source repository for long term history and releases still is managed with SVN at SourceForge, but our current development trunk and feature development branches that originate from it (and will be eventually merged back) are managed with Bazaar.

Tools you need

To fetch development branches or the trunk using Bazaar, you need Bazaar. You should make yourself familiar with the basic documentation.

To contribute back, we recommend you "rebase" your work before we integrate it, if possible; this makes all integration conflicts happen to you, and not the poor merging operator. You'll need the bzr-rebase plugin for that. Alternatively (rebase is somewhat picky and doesn't work most of the time), you can of course supply an already pre-merged branch with conflicts resolved.

To take over the merging operator duty and manage the two way syncing of the Bazaar branches and SVN, you'll need the bzr-svn plugin and its somewhat difficult dependencies. Difficult unless you run Ubuntu, then you get everything you need apart from the plugin itself. Lucky bastard.

Branch storage

Currently, we're using Launchpad as the primary high performance host for the bzr branches. We have a project and a team registered, and you can browse our main branches. Each branch detail page has instructions what you need to point your bzr at to fetch it and to commit to it.

Mirrors (well, the originals, actually) of the branches that are synced with SVN are available here; the -work branches are the ones mirrored to launchpad, the -sync branches are the hopefully identical copyes that get synced with SVN.

You are encouraged to create your own mirrors of these branches and publish them for others to fetch and to note the location here.

Workflow

In the following, we assume your username at launchpad is john.doe, and you want to work at our trunk branch; the URL to the writable branch then is bzr+ssh://john.doe@bazaar.launchpad.net/~armagetronad-dev/armagetronad/trunk-armagetronad-work. If you're just interested in read only access, you can use the read only URL http://bazaar.launchpad.net/~armagetronad-dev/armagetronad/trunk-armagetronad-work instead. If you want to access a branch maintained by a single developer named jane.doe, replace ~armagetronad-dev with ~jane.doe; just check the branch details on launchpad. We'll abbreviate the URL you're going to use as <URL>, because we're lazy typers.

Distributed, shmistributed. I just want to work on the mainline or someone else's development branch. Is there no simple way?

There is. You can use bzr in a mode where it behaves like SVN; in this mode, you store no local history, and all operations like commits and log queries go to the remote server. Fetching a local copy of a branch in this way is called a "checkout". Just do

bzr checkout <URL> --lightweight

and then use the checkout like an SVN checkout, just replacing 'svn' with 'bzr'. Noteworthy differences:

  • in bzr, moves are primitive operations, usable with "bzr mv a b", while in svn, copies are primitive.
  • to delete a file in svn, you need to explicitly remove it with "svn remove"; in bzr, all files deleted on the filesystem are considered deleted. Take care not to delete files from source control by accident.

Without the --lightweight, you will fetch the complete history, and read operations on it will no longer go to the remote server. Commits will still go directly to the remote branch. There is a quirk with the launchpad bzr branches, however: directly checking out a branch via its writable URL fails, you have to do the following. Fetch the read-only URL and the writeable URL and do

bzr checkout <read only URL>
cd <checkout>
bzr switch <writable URL>

Anyway, with checkouts, you don't have to worry about managing the branch. If bzr refuses a commit, just do

 bzr update

resolve any conflicts, and try again, just like you did with SVN.

Read the official Launchpad docs here.

Alternative: Work Branches

The other way to work with bzr is to use its distributed nature. You fetch a complete copy of a branch for local work:

bzr branch <URL>
cd <branch>

There, you do your work; bzr's commands are virtually identical to those of svn, you can add, remove and move files and directories. Use "bzr ignore" to tell bzr to ignore certain files. Use "bzr commit" to record changes.

The big difference to SVN is that all these operations only modify your local copy of the branch. To publish your work, you'll need to get it back to the remote branch. Use

 bzr push <URL>

for that the first time; the next time, you'll only need to use

 bzr push

If bzr tells you that the branches have diverged, you have two choices:

Merge vs. Rebase

The one way is to merge the changes from the remote branch into yours. This puts all changes that happened in the remote branch into your local branch as an additional change. Do

 bzr merge
 (resolve conflicts)
 bzr commit
 bzr push

The other way is to reorder the changes in your local branch to match the order in the remote branch, with your changes coming last. Do

 bzr rebase
 bzr pull
 bzr push

You'll need the "rebase" plugin mentioned earlier for this.

The end result is effectively the same; both the changes in the remote branch that happened since your last pull and your changes will be in both branches. However, with "bzr merge", your changes will be first in the history, while with "bzr rebase", the remote changes will be first. Obviously, the result of "bzr rebase" is more correct, and should be picked whenever possible. In the following cases, you should use "bzr merge" instead:

  • the remote branch is NOT a mainline branch (trunk, 0.2.8), but a development or hack branch.
  • your local branch is not just your private work branch, but a branch you publish and others merge from.

In both cases, repeated "bzr rebase" causes repeated conflict possibilities and duplication of changes. We don't want that.

So, what happens if you use "bzr merge" and push the result back to a mainline branch to integrate it into SVN? Nothing terrible, the sync scripts will notice the change of order in the history and correct it with a merge themselves. The following is a log example where a bzr user merged the change "first change to A from SVN" into his branch after committing the "added B in bzr" change to it:

------------------------------------------------------------------------
r7 | manuel | 2008-02-10 16:29:13 +0100 (Sun, 10 Feb 2008) | 17 lines
Automatic merging of commits that would change history order:
   ------------------------------------------------------------
   revno: 2.1.2
   committer: Manuel Moos <z-man@users.sf.net>
   branch nick: A-trunk-work
   timestamp: Sun 2008-02-10 14:45:13 +0100
   message:
     merging in bzr:
       manuel 2008-02-10 first change to A from SVN
   ------------------------------------------------------------
   revno: 2.1.1
   committer: Manuel Moos <z-man@users.sf.net>
   branch nick: A-trunk-work
   timestamp: Sun 2008-02-10 14:43:48 +0100
   message:
     added B in bzr
------------------------------------------------------------------------
r5 | manuel | 2008-02-10 14:42:15 +0100 (Sun, 10 Feb 2008) | 2 lines
 second change to A on svn
------------------------------------------------------------------------
r4 | manuel | 2008-02-10 14:41:44 +0100 (Sun, 10 Feb 2008) | 2 lines
 first change to A from SVN

If the bzr user had done multiple commits, they'd all be collapsed into one commit to SVN.

There also is a third way, but it shares mostly the disadvantages of the other two :) You can

# get a new copy of the remote branch
bzr branch <URL> tomerge
cd tomerge
# merge your changes into that branch
bzr merge ../<your branch>
(resolve conflicts)
bzr commit
# push the merge to your branch
bzr push ../<your branch>
# push your branch back
cd ../<your branch>
bzr push <URL>

It's complicated, and the resulting commit looks pretty much exactly like the one you'll get with the other merge method.

Development or hack branches

Whenever you want to do some work you won't be able to finish in one go, you should consider branching a development branch off the current mainline or the current stabilization branch. The same holds if you are not a team member, but want to work on your own code modification of arma and want to keep it up to date with current development, make it easy for others to fetch your changes without getting tons of conflicts, and maybe submit it for integration later.

Creation

To create a development branch of <URL>, pick a local name <name> for it and do

bzr branch <URL> <name>
cd <name>

then, you can still work as if you had an SVN checkout, but this time, changes will stay local on your hard disk and will not get committed immediately.

Publishing

To publish your branch on launchpad, select a nice name for it. A good naming convention would be to remove the -work suffix all of the mainline branches have, and replace it with the name of your feature. So, for example, if you want to add flying cylces to the trunk (name trunk-armagetronad-work, URL bzr+ssh://john.doe@bazaar.launchpad.net/~armagetronad-dev/armagetronad/trunk-armagetronad-work), you would name your branch trunk-armagetronad-flyingcycles, and your URL would be bzr+ssh://john.doe@bazaar.launchpad.net/~armagetronad-dev/armagetronad/trunk-armagetronad-flyingcycles. Let's call this URL <URL2>.

To publish your branch, you simply do

bzr push <URL2> --remember

from within your branch. The --remember is important; in case you had pushed to somewhere else before, the next push command would go to that old location. Z-Man accidentally committed the Pig Sty Patch to the main 0.2.8 branch that way.

To publish updates to your branch, you'll only have to do

bzr push

from then on.

Keeping up to date

It is a good idea to make a backup (a simple copy, or publishing it) of your branch before you do this.

To keep your branch up to date with changes on the mainline, you can do

bzr merge
(resolve conflicts)
bzr commit

in regular intervals. During this process, you may encounter conflicts. Resolve them, then mark them as resolved using "bzr resolved <filename>".

Merging back to the mainline

If it has been decided that a small development branch is ready to be integrated into the mainline, get it up to date one last time:

bzr merge
bzr commit

Then then push the changes back:

bzr push <mainline URL>

All the changes from your branch will appear as one huge merge in SVN.

If the branch contains many changes and/or multiple merges from the mainline, instead of the above procedure, the following slightly more complicated one is preferred, It will give the poor bzr-svn script less of a headache; it won't reshuffle the mainline history, and the script will not have to change it back.

 bzr branch <mainline URL> merge
 cd merge
 bzr merge ../<your development branch>
 (resolve conflicts)
 bzr commit
 bzr push <mainline URL>

Integrating changes

To integrate changes done by someone into a branch maintained by you, you should make one local copy of each of these branches, let's call them A and B. A is your branch, B is the branch containing changes to be integrated. Of course, A and B should not be your only copies of the branches.

You then do

cd A
bzr pull ../B

and hopefully, if the maintainer of B did his rebasings/merging as he should, that's it, and you can republish your branch A. If not, you'll have to merge:

cd A
bzr merge ../B
(resolve conflicts)
bzr commit

Switching the base branch

NOTE: This does not yet work for 0.2.8 to the trunk. The 0.2.8 branch was started in CVS and merged back incrementally using SVN, this procedure here can't work.

If a development branch was based on a stabilization branch, say 0.3.1, but has been rejected for integration there (say, it was too late), you can just move it to the trunk with

bzr merge <URL_OF_TRUNK>
bzr pull --remember <URL_OF_TRUNK>

From then on, you'll receive all the changes from the trunk.

Merging bugfixes

NOTE: This does not yet work for 0.2.8 to the trunk. The 0.2.8 branch was started in CVS and merged back incrementally using SVN, this procedure here can't work.

Say TRUNK is a local copy of a trunk branch, and BRANCH is a stabilization branch (say 0.3.1) branching from it, changes from BRANCH can be merged into TRUNK with bzr using

cd TRUNK
bzr merge ../BRANCH
(resolve conflicts)
bzr commit
bzr push <URL of TRUNK>

When editing the commit message, please copy the merge metainformation that you see there into the commit message. SVN does not store the metainfo, so the only way to keep it for us to read is to put it into the commit message.

What you absolutely should NOT do

Is actually an operation in SVN. You should not revert the history of a whole module, like

svn co <svnroot>/trunk
cd trunk
svn rm armagetronad
svn commit -m "destroyed"
svn cp <svnroot>/trunk/armagetronad -r <some earlier revision> .
svn commit -m "resurrected"

This will alter SVN history and confuse the sync script, causing it to fail (a good thing, the alternative would be that it would merge the changes you just have reverted back into SVN in a new commit.) The same operation on subdirectories, say armagetronad/src, should be fine and safe, though.

Likewise, you should avoid correcting mistakes in bzr using

bzr uncommit
bzr push --overwrite

This has no effect unless the changes you uncommitted have not yet been synced to SVN. The changes you remove will just be recommitted from the SVN copy.

To fix small errors, just commit a reverting change instead. For larger screwups, notify the other team members with submit access (shouting on IRC and the forum) that they should not pull in your changes or uncommit and revert them if they already did, and ask the merge manager to undo your change in bzr and SVN at the same time.


Sections | Installing the Game | Playing the Game | Competition Hub | Server Administration | Extending Armagetron Advanced | Development Docs