Bazaar works transparently with Subversion—the checkout
, update
, commit
, branch
, pull
, push
, and merge
commands, all work directly with Subversion repositories. There are several advantages in working with Subversion through Bazaar:
The plugin to work with Subversion branches is named svn
, typically in a package named bzr-svn
. Confirm whether or not it is already installed in your system by using bzr plugins
. If it is not in the list, see the Installing plugins section, and follow the steps to install it.
In addition to bzr-svn
, you also need to install subvertpy
, a Python library to interface with Subversion. Install it using your operating system's package manager or pip
. A simple way to verify that both bzr-svn
and
subvertpy
are correctly installed is by creating a dummy Subversion repository using Bazaar:
$ bzr init --subversion /tmp/empty-svn-repo Initialising Subversion metadata cache in /Users/janos/.bazaar/svn-cache/2f4f2ffe-08e1-45a5-847b-c4ce217833be. Created a repository branch (format: subversion) Using shared repository: /tmp/empty-svn-repo/
The --subversion
flag is provided by the bzr-svn
plugin. Normally, the bzr init
command does not have such options.
Bazaar supports all the standard Subversion URL formats, such as the following:
http://server/path/to/branch
https://server/path/to/branch
svn://server/path/to/branch
svn+ssh://user@server/path/to/branch
file:///path/to/repo/branch
Although the generic URL formats, such as http://
, https://
, or file:///
, can be Bazaar or even other VCS, Bazaar correctly detects Subversion repositories.
Note that when using the svn+ssh://
protocol, the path to the Subversion repository must be the full absolute path, even if the repository is in the home directory of the user. And, unlike with bzr+ssh://
, the /~/
notation to indicate the user's home directory does not work; you must use the full path always.
The best way to explore how Bazaar works with Subversion branches is by playing with a local Subversion repository. If you are familiar with Subversion, you can create a repository by using svnadmin
, or you can download and unpack the following sample repository:
https://launchpad.net/bzrbook-examples/trunk/examples/+download/svn-repo.tar.gz
The svn-repo
directory inside the ZIP file contains a small Subversion repository, which will be accessible via file:///
URLs. For example, if you move the svn-repo
directory into /tmp
, it will be accessible via file:///tmp/svn-repo
. You can try some other commands, such as bzr info
or bzr log
, on it:
$ bzr info file:///tmp/svn-repo Repository branch (format: subversion) Location: shared repository: /tmp/svn-repo repository branch: /tmp/svn-repo $ bzr log file:///tmp/svn-repo/trunk --line -n0 4: gatekeeper 2012-12-02 [merge] merged from anna 3.1.3: anna 2012-12-02 added r impl 3.1.2: anna 2012-12-02 added python impl 3.1.1: janos 2012-12-02 created branch for anna 3: janos 2012-11-26 merged from mike 2: janos 2012-11-26 added readme 1: janos 2012-11-26 created standard svn layout
The examples in this section will use this repository, assuming it at the path /sandbox/svn-repo
.
Before we begin to branch or check out from Subversion, it is good to be aware of some important differences between how branches and tags work in Subversion.
A typical Subversion repository contains the following subdirectories at the repository root:
trunk
: This is the master branch, where the main development happensbranches
: This is a container directory for branchestags
: This is a container directory for tagsIn Subversion, a branch is a lightweight copy of another directory at some specific revision. Typically, it is created in the branches
directory, and it behaves like a directory. Tags are created in exactly the same way, that is, as lightweight copies of specific directories at specific revisions.
Although internally Subversion stores branches and tags efficiently, when you checkout the repository, the layout is expanded into the filesystem as regular directories, which can take a lot of disk space. In order to avoid expanding a very large directory tree with all the branches, make sure to use the right Subversion URL in the checkout and branch operations.
Keep in mind that the preceding layout is a commonly used standard, not a hard rule. It is up to the managers of the project how they organize branches and tags inside their Subversion repository. Make sure to confirm the right URL before you begin to checkout or branch.
Another important point to note is that although in Bazaar the smallest logical unit that you can checkout is a branch, in Subversion it is a subdirectory.
You can branch or checkout from
Subversion with the bzr branch
and bzr checkout
commands, or by using Bazaar Explorer as usual. But first let's create a shared repository:
$ bzr init-repo /sandbox/svn-examples Shared repository with trees (format: 2a) Location: shared repository: svn-examples $ cd /sandbox/svn-examples/
It is always a good idea to use a shared repository when working with multiple remote branches. This is especially true when working with foreign branches, due to the added overhead of translation between Bazaar and the foreign protocol.
Next, let's checkout a few branches by using bzr checkout
:
$ bzr checkout file:///sandbox/svn-repo/trunk Initialising Subversion metadata cache in /Users/janos/.bazaar/svn-cache/5260eff9-c761-4657-805e-432c3fbc2731. $ bzr checkout file:///sandbox/svn-repo/branches/mike
Notice the message after the first checkout—Initializing Subversion metadata cache
. This is an optimization by Bazaar—the Subversion plugin builds a cache of Subversion metadata in order to speed up operations when working with the same Subversion repository again in the future. A new directory is created to store the cache of each distinct Subversion repository you use, and the name of the directory corresponds to the UUID of the Subversion repository, a universally unique ID generated by Subversion when the repository was created.
Branching from Subversion works exactly in the same way as with Bazaar branches. Regardless of the manner in which you fetch a Subversion branch, the end result will be a native Bazaar branch.
Keep in mind that Bazaar branches store the complete revision history, and therefore the first checkout or branch from a Subversion repository may take a long time depending upon the size of the project and the number of commits.
When fetching a Subversion location, Bazaar preserves various metadata about the revisions, such as the following:
svn:mergeinfo
and svn:mime-type
Revision numbers in Subversion are not per-branch but per-repository. If you recall that branches in Subversion behave much like directories, this makes sense.
Although both Bazaar and Subversion increments the revision number on each commit, when fetching a subdirectory of a Subversion repository, Bazaar downloads only the revisions that affected the specified path, which is only a subset of all the revisions inside the entire Subversion repository. As a result, the revision numbers in the Bazaar branch will not be the same as in the original Subversion repository. We can confirm this by using bzr log
:
$ bzr log -r3 trunk/ ------------------------------------------------------------ revno: 3 svn revno: 6 (on /trunk) committer: janos timestamp: Mon 2012-11-26 20:50:53 +0000 message: merged from mike
The Bazaar revision number is 3
, but the Subversion revision number is 6
, because only three of the commits in Subversion affected /trunk
.
You can reference the past revisions by their original Subversion revision number by prefixing with svn:
. For example:
$ bzr log -r svn:6 trunk/ ------------------------------------------------------------ revno: 3 svn revno: 6 (on /trunk) committer: janos timestamp: Mon 2012-11-26 20:50:53 +0000 message: merged from mike
Versioned properties are a feature of Subversion that is not supported by Bazaar. In Subversion, these are used for storing all kinds of metadata associated with files, directories, and merging, such as mime-types, keywords, line-ending character, and various other purposes, and all these metadata are versioned. Bazaar will preserve versioned properties and write them back when pushing to a Subversion repository, but in general, they will be ignored.
Most importantly,
Bazaar preserves revision and file IDs, which we can see by using the --show-ids
flag of bzr log
. For example:
$ bzr log -r3 trunk/ --show-ids ------------------------------------------------------------ revno: 3 revision-id: svn-v4:5260eff9-c761-4657-805e-432c3fbc2731:trunk:6 parent: svn-v4:5260eff9-c761-4657-805e-432c3fbc2731:trunk:2 svn revno: 6 (on /trunk) committer: janos timestamp: Mon 2012-11-26 20:50:53 +0000 message: merged from mike
The revision ID is derived from the Subversion repository's UUID, the path inside the Subversion repository, and the original Subversion revision number. In this way, Bazaar can uniquely identify revisions that originated from a Subversion repository, and it also keeps track of the parent-child relationships of the revisions.
The great benefit of this is that two independent Bazaar branches created from the same Subversion location will be identical:
$ bzr branch file:///sandbox/svn-repo/trunk tmp Branched 4 revisions. $ bzr missing -d trunk/ tmp/ Branches are up to date.
This is especially important when merging branches, as it effectively prevents from merging the same revisions twice.
Updating a Bazaar branch from a Subversion parent branch works in the same way as it does with native Bazaar branches. Let's test this by branching from an older revision of a Subversion branch, and then pulling from it to bring the local branch up-to-date:
$ bzr branch -rlast:2 file:///sandbox/svn-repo/trunk feature1 Branched 3 revisions.
Our local Bazaar branch is out of date, precisely one revision behind, so let's bring it up-to-date by using bzr pull
:
$ cd feature1 $ bzr pull Using saved parent location: /sandbox/svn-repo/trunk/ +N hello.r +N hello.tcl All changes applied successfully. Now on revision 4 (svn revno: 10).
Keep in mind that the pull
command may rearrange the revisions in the local branch in the same way as it works with native Bazaar branches.
Similarly, if we had used bzr checkout
to get a Subversion branch, then we can download new revisions from the Subversion server with bzr update
, exactly as if we were working with native Bazaar branches:
$ bzr checkout -rlast:2 file:///sandbox/svn-repo/trunk checkout1 $ cd checkout1/ $ bzr up +N hello.r +N hello.tcl All changes applied successfully. Updated to revision 4 of branch /sandbox/svn-repo/trunk
Committing in a branch bound to a Subversion repository works exactly in the same way as with native Bazaar branches—changes are first committed at the remote location, and only if that is successful, the changes are committed in the local Bazaar branch. If the local branch is out of date, the commit will be rejected, and you will have to update the local branch first by using bzr update
.
When committing to a Subversion repository, Bazaar sets some metadata about the revisions to re-use later when working with those revisions again, such as the author information and other details. Bazaar stores these metadata as revision properties named with a prefix bzr:
to make it easy to filter them out if necessary. These revision properties have no effect on Subversion operations, and are only visible in the most detailed logs. If for some reason you want to prevent Bazaar from saving such data, then you cannot use bzr commit
; the only way is to unbind the branch, commit your changes locally only, and use the bzr dpush
command to push them to Subversion. In this way, the extra bzr:
properties won't be saved; the revisions will be applied on the server as if they were native Subversion commits.
Pushing to a Subversion repository works in the same way as it does with native Bazaar branches:
$ bzr branch file:///sandbox/svn-repo/trunk feature2 Branched 4 revisions. $ cd feature2 $ bzr push file:///sandbox/svn-repo/branches/feature2 Created new branch at /branches/feature2.
Be careful when using bzr push
, as it can reorder revisions to match the local history layout at the remote repository location. This is especially important when the Subversion repository is publicly available. To prevent such issues, Bazaar will refuse to perform the push if that would reorder revisions.
As with committing, Bazaar saves additional metadata to Subversion when pushing revisions. If for some reason you prefer to not save such metadata, then use bzr dpush
to push revisions instead of bzr push
. If the pushed revisions do not contain a merge from other Subversion branches, then the end result will be exactly the same.
Bazaar is very good at merging Subversion branches, thanks to a few notable key factors:
bzr-svn
correctly tracks the relationships between Subversion revisions across different branchesbzr-svn
converts Subversion branches to native Bazaar branches, ultimately the merge operation is performed between Bazaar branchesbzr remerge
Let's try it out by merging /branches/jack
into /trunk
. We already fetched the trunk with bzr checkout
earlier; now, let's get /branches/jack
and perform the merge:
$ bzr branch file:///sandbox/svn-repo/branches/jack --no-tree Branched 6 revisions. $ cd trunk/ $ bzr merge ../jack/ +N hello.py +N hello.rb All changes applied successfully.
In this example, we fetched /branches/jack
to a local Bazaar branch before merging from it, but we could have used the remote branch URL directly. However, it is always a good idea to fetch the branch first, as in this way you can re-use the branch multiple times without redownloading it again from the source repository.
Also notice that we used the --no-tree
flag to create the branch. In this way, we can save disk space, as we don't need the working tree of a branch we just want to merge from it.
Let's commit the merge:
$ bzr commit -m 'merged from jack' --author gatekeeper Committing to: /sandbox/svn-repo/trunk added hello.rb added hello.tcl Committed revision 5.
Since we fetched trunk with bzr checkout
, it is bound to the Subversion repository, and as we can see in the Committed to
line in the output, the revision is committed to the Subversion repository itself. If our trunk directory had been an unbound branch, then the merge would be committed only locally, and we could push it to Subversion with bzr push :parent
.
When committing the merge or pushing it later to Subversion, Bazaar sets the svn:mergeinfo
property used by Subversion to track merges. This is essential to let Subversion understand correctly that the commit was in fact a merge, and appear as if performed by using a native Subversion client. We can confirm this by using the svn
program, the command-line interface of Subversion:
$ svn pget svn:mergeinfo file:///sandbox/svn-repo/trunk /branches/anna:7-9 /branches/mike:3-5 /branches/jack:11-13
Indeed, the property contains the information about the merge from /branches/jack
we performed earlier.
As mentioned in the previous sections, bzr push
will write the additional revision properties to the Subversion repository. Although this behavior can be prevented by using bzr dpush
instead, in that case Bazaar will also not write svn:mergeinfo
. In this situation, you would have to add svn:mergeinfo
manually later, by using a Subversion client.
Remember that with Bazaar, you can choose from different merge algorithms, which sometimes yield better results with fewer conflicts. The bzr remerge
command is especially useful to try a different algorithm on selected files, and the --reprocess
flag may help reducing the size of conflicted areas. See Chapter 3, Using Branches, on branching and merging for a detailed explanation with examples.
Although you can merge local Bazaar branches into Subversion, there is a very important difference between Bazaar and Subversion—in Bazaar, the merged revisions are preserved and propagated to the remote location when committing or pushing the merge, but in Subversion, this is not the case.
When merging a local Bazaar branch that does not exist in the Subversion repository, the merge will be just a single commit in Subversion; the unique revisions of the branch will not be copied. If you want to preserve the revisions of the local branch in Subversion, then first you have to push that branch to a suitable location in the Subversion repository.
Let's illustrate this with an example, through the following steps:
Let's create a local branch from the trunk called feature3
and do some commits in it:
$ bzr branch trunk feature3 Branched 4 revisions. $ cd feature3/ $ echo >> hello.pl $ bzr commit -m 'meaningless change' Committing to: /sandbox/svn-examples/feature3/ modified hello.pl Committed revision 5. $ echo >> hello.sh $ bzr commit -m 'another meaningless change' Committing to: /sandbox/svn-examples/feature3/ modified hello.sh Committed revision 6.
At this point, the branch exists only locally, not in Subversion. Let's push this to Subversion before we merge it into the trunk. We can push it after we merge too, but in this way, the metadata will make more sense, as you will see later:
$ bzr push file:///sandbox/svn-repo/branches/feature3 Created new branch at /branches/feature3.
Next, let's update our trunk and merge the branch into it. In our example, the updating is unnecessary, as we know for a fact that nobody else has committed to the trunk; this is just a reminder so that you don't forget to do in a real-life situation.
$ bzr update Tree is up to date at revision 4 of branch /sandbox/svn-repo/trunk $ bzr merge ../feature3/ M hello.pl M hello.sh All changes applied successfully.
Finally, let's commit the merge. Since our trunk is bound to the Subversion repository, because we created it using bzr checkout
, the commit will be written back to Subversion immediately:
$ bzr commit -m 'merged from feature3 branch' Committing to: /sandbox/svn-repo/trunk modified hello.pl modified hello.sh Committed revision 5.
This commit, like all commits in Subversion, is a single revision including all the changes we did in our local feature3
branch. If we hadn't pushed the feature3
branch to Subversion earlier, the commits in that branch would not be preserved anywhere in Subversion. Since we did push it, the revisions are preserved, and Bazaar also created the necessary metadata to let Subversion know about the relationship between the trunk and the feature3
branch we pushed, as we can confirm with svn pget
:
$ svn pget svn:mergeinfo file:///sandbox/svn-repo/trunk /branches/mike:3-5 /branches/anna:7-9 /branches/feature3:14-15
If you want to preserve the individual commits in your local branches, remember to push the branch to Subversion before merging it into the trunk. That way, Bazaar will record the necessary metadata correctly. If you forget to perform the operations in this order, then you would have to create that metadata yourself.
You can bind to and unbind from a
Subversion repository in the same way as with native Bazaar branches. The result of bzr checkout
is a bound branch:
$ bzr info trunk/ Repository checkout (format: 2a) Location: repository checkout root: trunk checkout of branch: /sandbox/svn-repo/trunk shared repository: .
You can unbind from the Subversion location, which can be useful, for example, if the repository is temporarily inaccessible due to network problems, or if you want to commit locally only:
$ cd trunk/ $ bzr unbind $ bzr info Repository tree (format: 2a) Location: shared repository: /sandbox/svn-examples repository branch: .
When the connection is restored, or you are ready to merge your local commits into Subversion, you can bind to it again:
$ bzr bind file:///sandbox/svn-repo/trunk $ bzr update Tree is up to date at revision 4 of branch /sandbox/svn-repo/trunk
Similarly, you can bind to a Subversion location that you branched from using bzr branch:
$ bzr branch file:///sandbox/svn-repo/trunk tmp Branched 4 revisions. $ cd tmp $ bzr bind :parent
An interesting feature of bzr-svn
is that a lightweight checkout is actually a native Subversion working copy:
$ bzr checkout --lightweight file:///sandbox/svn-repo/trunk light $ ls -a light/ . .. .svn README.md hello.pl hello.py hello.r hello.sh
As you can see, instead of a .bzr
directory, there is a .svn
directory. In fact, Bazaar can work with native Subversion working copies, as if using a Subversion client.
In general, the same limitations apply to lightweight checkouts as when using native Bazaar branches—all the operations that work with the revision history will be slow. In addition, due to the overhead of the conversion between protocols, these operations will be even slower than usual.
An interesting benefit of using Bazaar to merge Subversion branches is that the branch history is easier to view in the logs, thanks to the additional metadata added by Bazaar:
Notice that we can see the merged revisions from Anna's branch—merged using Bazaar, but we cannot see the merged revisions in Mike's branch—merged using Subversion.
The plugin has the following limitations:
svn:ignore
, svn:mime-type
, svn:eol-style
, svn:keywords
, and svn:externals
. These properties are ignored in general, but carried over correctly in branch operations.svk:merge
property (used by SVK) is also set in addition to svn:mergeinfo
.For a more complete and up-to-date list of limitations, refer to the plugin's homepage:
For the most part, Bazaar works transparently with Subversion repositories. The result of a checkout or branch operation from Subversion is a native Bazaar branch, thus all your local operations will be native Bazaar operations that you are used to. However, all the interactions with the remote Subversion repository will be inevitably slower than usual, due to the translation between the protocols of these systems.
As long as you are aware of the limitations and the differences of the two systems, you can greatly benefit from the added features of Bazaar, such as the ability to create local branches and advanced merging capabilities.
Quick tips and cheat sheet:
bzr remerge
and the various merging strategiesThe up-to-date details and limitations of the plugin are documented at the following locations:
3.139.105.159