One of the features in Bzr (0.8+) is shared repositories. This document will introduce the concept and explain their usage by showing an example. New users should read the introduction to bzr for a general overview of Bazaar.
Before we start explaining what a shared repository is, we need to understand how branches work in Bazaar. One can think of a branch as one line of development. It contains information on what your project looked like at various points in time. When you want to work on your project you start by making a checkout on your computer. The checkout will create a working tree. Whenever you make changes and want to record them, you commit a new revision to the branch. All revisions of a branch are stored inside a repository.
Suppose you are a software engineer who needs to maintain stable version of the current project foo. Work is started on a development branch to implement new features. One of the new requested features might be an improved debug capability.
You track the progress on the stable and development branch by mirroring them on your own workstation.
$ bzr branch http://bzr-project.example.com/foo.stable/ foo.stable $ bzr branch http://bzr-project.example.com/foo.dev/ foo.dev
To implement the new feature you start by branching off from the main development version.
$ bzr branch foo.dev foo.feature
You received a report from a customer who discovered a serious flaw in the released version, so you also start a branch to fix this.
$ bzr branch foo.stable foo.stable.overflow
Because all branches store all revisions and each branch is related to another branch at some version, you have a lot of duplicate revisions stored on your computer.
Wouldn't it be great if they could all share the revisions they have in common? This is where shared repositories come into play.
A shared repository is a repository which can store revisions for multiple branches. Each branch will share the repository for its revision storage.
Older versions of Bazaar were only able to store all three concepts of working tree, branch and repository in the same control directory (the .bzr directory). The format of such a control directory is called All-in-one format. In current version of bzr there is a meta directory format for the control directory, which allows Bazaar to store a subset of the concepts.
When you create a shared repository and add branches inside it, each branch will not store its revisions in the associated control directory, but will use the one in the shared repository.
You create a shared repository with
$ bzr init-repo
There are two options for creating shared repositories: with or without working trees. By specifying the --trees option at creation time, you set the default for all branches underneath to have working trees. (It follows that --no-trees sets the default for branches to not have working trees)
To make a branch become part of the shared repository, you branch to a location inside it (i.e., a subdirectory). Several examples of repository layouts are discussed on SharedRepositoryLayouts.
You can import any tree inside the shared repository with the bzr branch command or create an empty branch with bzr init.
When branching into a shared repository, make sure the source branch has a control directory in meta directory format. You can check with bzr info and, when needed, upgrade with bzr upgrade. This only concerns branches created with pre 0.8 versions of Bazaar. Newer versions use the meta directory format per default.
Shared repositories can also be used to share branches between users in a centralized development model. This will be explained later on in this tutorial, as it is a different, but related concept of sharing.
Shared Repository Example
Let's return to our example. To save disk space we create a shared repository for all branches.
$ bzr init-repo --trees foo-repo
And import the stable and development branches. Again, the feature branch will be created from the development branch.
$ cd foo-repo $ bzr branch http://bzr-project.example.com/foo.stable/ foo.stable $ bzr branch http://bzr-project.example.com/foo.dev/ foo.dev $ bzr branch foo.dev foo.feature
The commands are exactly the same as in the first example. The only difference is operating inside the directory of the shared repository. All other commands that operate on a working tree or branch will work in the exact same way as before.
$ cd foo.feature # <hacking on new feature> $ bzr commit -m "Progress on ..."
To keep the feature branch up to date with the latest development, the following commands are issued:
$ cd foo.dev $ bzr pull $ cd ../foo.feature $ bzr merge ../foo.dev $ bzr commit -m "Merge with foo.dev"
Once the feature is finished, it can be merged into the main development branch and changes pushed to a remote location. Before the merge, the development tree is synchronized with its remote location using bzr pull.
$ cd foo.dev $ bzr pull $ bzr merge ../foo.feature $ bzr commit -m "Merge new feature" $ bzr push sftp://bzr-project.example.com/srv/foo/foo.dev/
The last step could have been omitted, if a checkout of the development branch had been done.
A checkout is a working tree whose commits go into another branch. Heavyweight checkouts (the default) also have a local branch. Whenever you commit, it will first commit to the local branch and push to the master branch. If either one fails, it will look like nothing happened1. Checkouts are used to facilitate Lockstep Development.
Lightweight checkouts are similar in concept, but they have no local branch. This makes them almost the same as CVS or SVN checkouts. They are a good choice when you have fast access to the the remote branch, and a poor choice when you have slow or infrequent access to it.
Checkouts that are part of a shared repository are also referred to as repository checkouts.
An advantage of heavyweight checkouts is the ability to unbind and work locally. This makes them ideal for use on laptops. If you are temporarily off-line, you can do bzr commit --local which will stay local for just that commit. When off-line for longer periods, you can bzr unbind. All subsequent commits will be local. When a checkout is rebound to the master branch, you can synchronize revisions using bzr update.
Example Using a Heavyweight Checkout
For tracking the development branch, a checkout could have been used too. The checkout would allow easy synchronization of branches.
$ cd foo-repo $ bzr checkout sftp://bzr-project.example.com/srv/bzr/foo/foo.dev/ foo.dev
To update a checkout from the remote branch, you don't use bzr pull, but
$ bzr update
For commit to work, the branches are not allowed to have diverged, as demonstrated by the following example:
$ bzr merge ../foo.feature All changes applied successfully. $ bzr commit -m "Merge new feature" bzr: ERROR: Bound branch BzrBranch5(u'/foo.dev') is out of date with master branch BzrBranch5(u'sftp://bzr-project.example.com/srv/bzr/foo/foo.dev/'). Either unbind, update, or pass --local to commit. $ bzr update All changes applied successfully. Updated to revision 314. $ bzr commit -m "Merge new feature" Committed revision 315.
As a best practice, always update before you merge. This helps you resolve conflicts better.
Example of Lightweight Checkouts
You develop on some experimental features, which you would rather not push to the central file server. You decide to make them available through your own web server, hosted on your workstation. You create a shared repository in /srv/bzr/foo-repo with a development repository branch.
$ cd /srv/bzr $ bzr init-repo foo-repo $ cd foo-repo $ bzr branch sftp://bzr-project.example.com/srv/bzr/foo/foo.dev/ foo.dev $ bzr branch foo.dev foo.feature
Thus branches are created inside a shared repository, while lightweight checkouts are, preferably, somewhere outside the shared repository.
$ cd ~/src/foo $ bzr checkout --lightweight /srv/foo-repo/foo.feature foo.feature
Shared Repositories Without Trees
As previously mentioned, branches inside a shared repositories do not need to have a working tree. These branches are also referred to as repository branches. They are ideal for use on file servers, where one or more persons can have write (thus commit, push or merge) access. This allows you to use Bazaar for centralized revision control. But make sure to set the correct file permissions for multiple accounts. Bazaar does not (yet) have a SmartServer, so relies on file permissions for multiple users.
The word shared in shared repository refers to branches sharing a repository for revision storage, not to users sharing the same branch for publishing revisions. They can be used used for that purpose, however.
Example for Central Storage on a Server
The central server provides the stable and development branches of its foo product available through a web server (i.e., Apache) and over sftp (FTP over SSH).
Suppose the central server is hosted at bzr-project.example.com and we want to create the branches at the /srv/bzr/foo location. This is analogous to the workstation case:
$ mkdir /srv/bzr/ $ bzr init-repo /srv/bzr/foo $ bzr init /srv/bzr/foo/foo.stable $ bzr init /srv/bzr/foo/foo.dev
Note: We do not use the --trees option here. Instead of bzr init, we could have used bzr branch to import an existing branch.
Once we make the shared repository available through Apache and SSH, developers can access the branches with:
$ bzr branch http://bzr-project.example.com/foo.stable/ myfoo.stable $ bzr checkout sftp://bzr-project.example.com/srv/bzr/foo/foo.stable/ myfoo.stable
Note: The sftp transport uses locations as found on the file system of the server.
For a shared repository to be used by several users, they all need permission to read and write it. This is determined by the operating system permissions on the control files.
When Bazaar writes to control files, it tries to make their permissions consistent with existing files. Generally you will want all the users who share the repository to be in a group, and for the group to have permission to write to the directory.
On many unixes setting the permissions of the base directory to 02770 will allow the group to access the repository, and will let the group ownership be inherited when new directories are created underneath. However a bug in openssh's sftp server means this will not work with sftp access, only with bzr+ssh.
- Add more info and example on lightweight checkouts
- Advantage of shared repository without working trees:
- Does not clutter backup with trees, just committed revisions, thus smaller and well suited for incremental backups
- Makes it easy to make your repository available through a web server without working trees.
- Advantage of trees inside shared repository:
- No need to branch inside the repository and make a lightweight checkout again
- You have everything in one location
Or, in the worst case, do bzr update to correct. (1)