Tips and Tricks

You've come a long way! You know the basics, how to work with branches, and how to use Bazaar to collaborate with others. Now I'll show you a collection of tips and tricks that will help you fix mistakes and handle common situations.


Bazaar is remarkably easy to use, but you might have some questions about specific problems or scenarios. In this final part of the tutorial, I'll show you a collection of tips and tricks that will help you correct problems you may run into and some techniques for common tasks.

You don't need to read all of these tips and tricks— you can come back to this page as situations arise.

Putting the Wrong Directory Under Version Control

The bzr init command turns a directory into a versioned branch. You can turn any directory into a versioned branch by calling bzr init inside that directory. If you accidentally put the wrong directory under version control, you can remove it's history by simply deleting it's .bzr subdirectory.

$ rm -r .bzr

Adding the Wrong Files

The bzr add command adds files to version control. If you add a file you don't want to track, you can remove it with bzr remove.

$ bzr add foo.c
$ bzr remove --keep foo.c

This will remove the file from version control. It will not delete the file with the --keep option. Without the --keep option, the file will be backed up.

Looking at Older Versions of Files

To view an old version of a file, you can use bzr cat to view the old state directly or to write a copy to a new file:

$ bzr cat -r1 cake.txt
My Awesome Chocolate Cake Recipe
$ bzr cat -r1 cake.txt > /tmp/cake.r1.txt

If you just want to see differences between versions of files, use bzr diff.

$ bzr diff -r1..2 cake.txt
=== modified file 'cake.txt'
--- cake.txt	2015-12-19 20:06:17 +0000
+++ cake.txt	2015-12-20 00:28:08 +0000
@@ -1,1 +1,14 @@
-My Awesome Chocolate Cake Recipe
\ No newline at end of file
+My Awesome Chocolate Cake Recipe
+
+  Ingredients
+
+  2   cups all-purpose flour
+  2   cups sugar
+  1   cup cocoa
...

Undoing Recent Changes in Your Working Tree

Say you're editing code and trying out some ideas. You decide you're going down the wrong path and just want to put things back to the way they were the last time you committed. You can put all the files in your tree back to their last recorded state with bzr revert.

$ bzr revert

Calling bzr revert with no arguments will undo changes in every file. you can undo changes in a single file by specifying it:

$ bzr revert foo.java

You may want to call bzr status to see a list of which files changed since your last commit or bzr diff to see how the content has changed.

Undoing a Commit

Sometimes we make a mistake in a commit. Often the mistake is entering a bad commit message or forgetting to add a needed file to version control. You can undo the last commit with bzr uncommit.

Uncommit one or more committed revisions.
$ bzr commit -m"fixed speling error in Stuff class"
Committing to: /home/fmccann/project/
modified stuff.py
Committed revision 19.
$ bzr uncommit
19 Fred McCann	2015-12-24
      fixed speling error in Stuff class

The above revision(s) will be removed.
Uncommit these revisions? ([y]es, [n]o): yes
You can restore the old tip by running:
  bzr pull . -r revid:fred@bzrinit.com-20131224165455-n2k4e5v2u973g4hs
$ bzr commit -m"fixed spelling error in Stuff class"
Committing to: /home/fmccann/project/
modified stuff.py
Committed revision 19.

Notice that Bazaar does not destroy the uncommitted revision. If you need to get that revision back, you can use the revision id, but it will disappear from the log. Also, bzr uncommit affects only your branch. If you've shared the revision with anyone else before you've uncommitted it, it will still be a part of their history.

If you want to uncommit more than one revision at once, you can specify a revision number to uncommit back to:

$ bzr commit -m"fixed speling error in Stuff class"
Committing to: /home/fmccann/project/
modified stuff.py
Committed revision 19.
$ bzr uncommit -r17
19 Fred McCann	2015-12-24
      fixed spelling error in Stuff class

18 Fred McCann	2015-12-24
      implemented solution to the halting problem. Srsly.

The above revision(s) will be removed.
Uncommit these revisions? ([y]es, [n]o): yes
You can restore the old tip by running:
  bzr pull . -r revid:fred@bzrinit.com-20131224170346-6ej41t0fseffcx00
$ bzr revert
 M  stuff.py 

Uncommitting doesn't affect the working tree, so you have to call bzr revert after uncommitting several revisions. In general, you're probably better off making a new commit with a reverted state than you are uncommitting several revisions.

Undoing an Uncommit

To undo an uncommit, you have to restore an abandoned head. A head is a revision that is the latest revision in a list of parent-child revisions. Every branch has a head, which is the most recent revision. When you uncommit a revision, it creates an abandoned head.

Assume we uncommitted a change as we did in Undoing a Commit.

$ bzr commit -m"fixed speling error in Stuff class"
Committing to: /home/fmccann/project/
modified stuff.py
Committed revision 19.
$ bzr uncommit
19 Fred McCann	2015-12-24
      fixed speling error in Stuff class

The above revision(s) will be removed.
Uncommit these revisions? ([y]es, [n]o): yes
You can restore the old tip by running:
  bzr pull . -r revid:fred@bzrinit.com-20131224165455-n2k4e5v2u973g4hs

The head revision of the branch used to be revision 19. The head is where we append new revisions. When we uncommitted revision 19, 18 became the new head. The former revision 19 is still in the repository, and it's parent revision is still 18, but it has been abandoned.

To get the uncommitted revision back, we need to pull it back with it's unique revision identifier, since it no longer has a revision number. When we executed the uncommit, Bazaar gave us the revision identifier and the command needed to restore it.

$ bzr pull . -r revid:fred@bzrinit.com-20131224165455-n2k4e5v2u973g4hs
 M  stuff.py
All changes applied successfully.
Now on revision 19.

After the pull, the abandoned revision is set back to the active head of the branch and it's again revision number 19 in the branch.

Show all revisions in a repository not having descendants.

If you forgot to jot down the unique revision id of the uncommitted revision, you can use the bzr heads command, which is provided by the bzrtools plugin.

$ bzr heads --dead-only
HEAD: revision-id: revid:fred@bzrinit.com-20131224165455-n2k4e5v2u973g4hs (dead)
  committer: Fred McCann <fred@bzrinit.com>
  branch nick: fred
  timestamp: Tue 2015-12-24 19:31:51 -0500
  message:
    fixed speling error in Stuff class

Committing Only Parts of your Working Tree

By default, the bzr commit command records all changes in your working tree as a new revision in your branch. This is almost always what you want, which is why it's the default behavior.

If you only want to commit specific files into a revision, you can specify them in the bzr commit command:

$ bzr commit src/SpanningTree.c src/SpanningTree.h

Any uncommitted changes will still remain in your working tree after a "selective" commit.

Hiding a "Messy" Series of Commits

Let's say I just created a new branch for a project and started working on some code. After an hour or so, I have a bunch of commits:

~$ bzr init project
~$ cd project
...
project$ bzr log --short
  7 Fred McCann	2015-12-24
    OK, all tests really work now.

  6 Fred McCann	2015-12-24
    OK, all tests are passing now. Srsly.

  5 Fred McCann	2015-12-24
    Ugh spelled ISBN WRONG again.

  4 Fred McCann	2015-12-24
    Function doesn't handle empty ISBN strings. Fixed.

  3 Fred McCann	2015-12-24
    Spelled ISBN IBSN. Duh.

  2 Fred McCann	2015-12-24
    Added ISBN support to library module

  1 Fred McCann	2015-12-22
    initial import

A lot of my commits are small fixes and goofs that I don't necessarily want to see. Rather than resorting to uncommitting changes or other more drastic options, I can take advantage of Bazaar's nested logs and "bundle" all these changes into a single revision.

Step one is to branch my project into a feature branch, only taking the revisions before the ones I want to bundle:

project$ cd ..
~$ bzr branch project isbn -r1
Branched 1 revision.

Step two is to merge all of the changes into the feature branch:

~$ cd isbn/
isbn$ bzr merge ../project
 M  library.pl
All changes applied successfully.
isbn$ bzr commit -m"Implement ISBN support"
Committing to: /home/fmccann/isbn/
modified library.pl
Committed revision 2.

Step three is to push the changes back to the project branch:

isbn$ bzr push ../project/
All changes applied successfully.
Pushed up to revision 2.

That's it! The "messy" revisions have been bundled into a single merge revision.

isbn$ cd ../project
project$ bzr log --short
  2 Fred McCann	2015-12-24 [merge]
    Implement ISBN support

  1 Fred McCann	2015-12-24
    initial import
project$ bzr log -n0 --short
  2 Fred McCann	2015-12-24 [merge]
    Implement ISBN support

        1.1.6 Fred McCann	2015-12-24
              OK, all tests really work now.

        1.1.5 Fred McCann	2015-12-24
              OK, all tests are passing now. Srsly.

        1.1.4 Fred McCann	2015-12-24
              Ugh spelled ISBN WRONG again.

        1.1.3 Fred McCann	2015-12-24
              Function doesn't handle empty ISBN strings. Fixed.

        1.1.2 Fred McCann	2015-12-24
              Spelled ISBN IBSN. Duh.

        1.1.1 Fred McCann	2015-12-24
              Added ISBN support to library module

  1 Fred McCann	2015-12-24
    initial import

In Bazaar, history is immutable and trying to rewrite it is a bad idea. However, Bazaar's excellent merge tracking and hierarchical logs makes it easy to "tidy" up history safely without losing any information.

A good strategy is to work in feature branches rather than directly in your main branch so this sort of bundling is planned from the beginning. As you can see, bundling after the fact isn't very difficult.

Recommitting a Previous Version of a File

Let's say you've been hacking on AppDelegate.m and you've figured out that you introduced a serious bug in revision 16, and you just want to get it back to the way it used to be. You want to get the last good working state of the file and commit it.

$ bzr revert -r15 AppDelegate.m
 M  AppDelegate.m 
$ bzr commit -m"Reverting AppDelegate to r15"
Committing to: /home/fmccann/project/
modified AppDelegate.m
Committed revision 21.

You could also revert the entire project by calling bzr revert -r15 without specifying a file and committing the entire tree. This is often a better option than bzr uncommit because it keeps all of your revisions in the branch history.

Changing a Tag

If you created a tag with the wrong revision, you can reassociate the tag with the --force option to bzr tag.

$ bzr tag -r2 v0.1
Created tag v0.1.
$ bzr tag -r4 v0.1 --force
Updated tag v0.1.

It's also possible to remove tags entirely.

$ bzr tag v0.1 --delete
Deleted tag v0.1.

Searching the Log

You can perform basic searches of the log with the --match option to the log command. Be sure to specify a value for nesting to see nested logs.

$ bzr log --match multiply --match add -n0
------------------------------------------------------------
revno: 1.2.4
committer: Charlie Harvey <charlie@bzrinit.com>
branch nick: us-2
timestamp: Sun 2015-12-22 14:44:30 -0500
message:
  Implemented multiply and divide
------------------------------------------------------------
revno: 1.2.3
committer: Fred McCann <fred@bzrinit.com>
branch nick: us-2
timestamp: Sun 2015-12-22 14:31:44 -0500
message:
  Implemented add/subtract

The --match option can handle regular expressions too. See the bzr log documentation for more information.

Listing Files Modified in a Revision

Sometimes you want to see a list of files that were added, modified, or deleted in a revision. Using the verbose option of bzr log will show you which files were touched.

$ bzr log -r 1.2.3 -v
------------------------------------------------------------
revno: 1.2.3
committer: Fred McCann <fred@bzrinit.com>
branch nick: us-2
timestamp: Sun 2015-12-22 14:31:44 -0500
message:
  Implemented add/subtract
modified:
  src/calc.rb

Finding the Revision that Most Recently Changed a File

You can see the log for a single file by specifying the name of the file for bzr log. You can also use the limit (-l) option to see the the single most recent change.

$ bzr log test/calc_test.rb -l1
------------------------------------------------------------
revno: 3 [merge]
committer: Charlie Harvey <charlie@bzrinit.com>
branch nick: iteration-1
timestamp: Sun 2015-12-22 14:54:45 -0500
message:
  US-2: Implement basic arithmetic functions

Finding Developers that Altered Parts of a File

Many development teams have a no code ownership policy, meaning that anyone is free to work on any part of the code. This is common in agile development teams.

Shows which developer modified lines in a file. Also shows which revisions the changes were committed in.

If you want to modify a piece of code and no one "owns" a particular file, it might not be clear who to talk to if you have any questions about the code you're about to modify. Bazaar has a command, bzr annotate, that will let you see which developer modified which parts of a file, and the revisions in which parts of the file were changed.

$ bzr annotate src/calc.rb
1.2.3 fred@bz | require 'bigdecimal'
              |
1.2.1 charlie | class Calc
              |
1.2.3 fred@bz |   def initialize
              |     @acc = bd(0)
              |   end
              |
              |   def add(val)
              |     @acc += bd(val)
              |     @acc.to_f
              |   end
              |
              |   def sub(val)
              |     @acc -= bd(val)
              |     @acc.to_f
              |   end
              |
1.2.4 charlie |   def mul(val)
              |     @acc *= bd(val)
              |     @acc.to_f
              |   end
              |
              |   def div(val)
              |     raise "Division by zero" if val.to_f == 0.0
              |     @acc /= bd(val)
              |     @acc.to_f
              |   end
              |
1.2.3 fred@bz |   private
              |
              |   def bd(val)
              |     BigDecimal.new(val.to_s)
              |   end
              |
1.2.1 charlie | end

If I wanted to make some changes to the div method, I can see that Charlie was the last person who worked on it, so I might want to bounce ideas off him.

Starting Work in the Wrong Branch

It's not uncommon to have many branches of the same project. Since branches in Bazaar are just directories, it's easy to know which branch you're working in, but sometimes you start changing files and only realize afterwards that you're in the wrong directory. You can transfer your uncommitted changes in your working tree to the correct branch with bzr merge.

Say you started working in the feature 12 branch, but you really meant to work in the feature 15 branch:

feature-12$ cd ../feature-15
feature-15$ bzr merge --uncommitted ../feature-12
 M  list.cpp
 M  list.h
All changes applied successfully.
feature-15$ cd ../feature-12
feature-12$ bzr revert
 M  list.cpp
 M  list.h

All the changes in 12's working tree have been moved to the feature 15 directory, and we've reverted the files in feature 12 back to the last committed state.

Showing the Revision of the Working Tree

Show version information about the working tree.

As covered in Bazaar From the Ground Up, the working tree is associated with a revision of your branch. You can change the associated revision with the bzr update command. To see what revision you're currently associated with, you can use the bzr version-info command.

$ bzr version-info
revision-id: charlie@bzrinit.com-20131222195445-qzqov4qadbcrm954
date: 2015-12-22 14:54:45 -0500
build-date: 2015-12-24 14:46:10 -0500
revno: 3
branch-nick: iteration-1
$ bzr update -r2
-D  src/calc.rb
-D  test/calc_test.rb
All changes applied successfully.
Updated to revision 2 of branch /home/fmccann/iteration-1
$ bzr version-info
revision-id: fred@bzrinit.com-20131222180823-d757w1ps4pi844by
date: 2015-12-22 13:08:23 -0500
build-date: 2015-12-24 14:46:15 -0500
revno: 2
branch-nick: iteration-1

Previewing Changes that a Pull/Push/Merge Will Make

Before performing a pull, push, or merge, you might want to see what revisions will be transferred. You can always use the bzr missing command to see how branches differ.

recipe$ bzr missing bzr+ssh://dev.example.com/srv/recipe
You have 1 extra revision:
------------------------------------------------------------
revno: 3
committer: Fred McCann <fred@bzrinit.com>
branch nick: recipe
timestamp: Fri 2015-12-20 20:29:36 -0500
message:
  added vanilla to ingredients



You are missing 2 revisions:
------------------------------------------------------------
revno: 4
committer: Charlie Harvey <charlie@bzrinit.com>
branch nick: charlie
timestamp: Fri 2015-12-20 20:20:24 -0500
message:
  added espresso to the cake ingredients
------------------------------------------------------------
revno: 3
committer: Charlie Harvey <charlie@bzrinit.com>
branch nick: charlie
timestamp: Fri 2015-12-20 12:57:20 -0500
message:
  added ingredients for frosting.

This will show you which revisions will be involved in a pull, push, or merge. Specifically for merges, you can use the --preview option to show a diff before actually doing a merge.

iteration-1$ bzr merge ../us-6/ --preview
=== modified file 'src/calc.rb'
--- src/calc.rb	2015-12-24 20:26:06 +0000
+++ src/calc.rb	2015-12-24 20:26:09 +0000
@@ -27,6 +27,11 @@
     @acc.to_f
   end

+  def mem
+    @mem = @acc
+    @mem.to_f
+  end
+
   private

   def bd(val)

Viewing and Changing Default Branches for Push, Pull, Merge and Send

Show information about a working tree, branch, or repository.

Bazaar will remember relationships between branches so that you don't have to specify branch locations for common operations. You can use bzr info to see these related branches:

feature-21$ bzr info
Standalone tree (format: 2a)
Location:
  branch root: .

Related branches:
    push branch: bzr+ssh://dev.example.com/srv/project/feature-21
  parent branch: bzr+ssh://dev.example.com/srv/project/trunk
  submit branch: bzr+ssh://dev.example.com/srv/project/trunk

The parent is the location the current branch was forked from. The parent is used as the default branch for pull and merge operations. The push branch is the default branch for push operations. The submit branch is used as a base of comparison to create merge directives with bzr send.

The command bzr merge, bzr push, bzr pull, and bzr send all support the --remember option. This option sets the default branch used in subsequent calls.

feature-21$ bzr merge ../trunk --remember

This call to bzr merge performs a merge as normal, but also sets the default merge branch to "../trunk". A full list of location types and aliases to reference them is available in the Bazaar documentation.

Determine if Your Branch is a Checkout

Checkouts are bound to another branch and automatically transmit committed revisions, so it's good to know if you're working in a checkout or an ordinary branch. The bzr info command will reveal what kind of branch you're working in:

$ bzr info
Checkout (format: 2a)
Location:
       checkout root: .
  checkout of branch: bzr+ssh://dev.example.com/srv/project/trunk

There are a various types of versioned directories in Bazaar:

  • Checkout: A working tree that is bound to a branch at a different location.
  • Repository Branch: A branch in a shared repository with no working tree.
  • Repository Tree: A branch in a shared repository with a working tree.
  • Shared Repository: A shared repository with branches that have no trees by default.
  • Shared Repository with Trees: A shared repository with branches that have trees by default.
  • Standalone Branch: A branch with it's own repository and no working tree.
  • Standalone Tree: A branch with a working tree and it's own repository.

The bzr info command will also tell you if you're operating in a stacked branch, meaning some of its history is stored in another location.

Show or Change Branch Nickname

All branches have a nickname that appears in log messages:

$ bzr log -l1
------------------------------------------------------------
revno: 12
committer: Fred McCann <fred@bzrinit.com>
branch nick: feature-23
timestamp: Sun 2015-12-22 14:31:44 -0500
message:
  Refactored the edge list to be circularly linked
Show or change the branch nickname.

The nickname of this branch is "feature-23". By default it is set to the name of your versioned directory, or in the case of checkouts, the parent branch nickname. You can both view and change the nickname of a branch with the bzr nick command.

$ bzr nick
feature-23
$ bzr nick "Shortest Paths"
$ bzr nick
Shortest Paths

Canceling a Merge

Unlike pulls and pushes, merges aren't completed unless they are recorded with bzr commit. To cancel a merge after it's started, call bzr revert instead of bzr commit.

$ bzr merge
$ bzr revert

Undoing a Push, Pull, or Committed Merge

After either a push or a pull, the receiving branch will have more revisions. If you want to undo these operations, you have to reset your branch to an older head revision. Assume we have a branch with two revisions:

$ bzr log --short
  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import

After a pull, we've now got four revisions:

$ bzr pull
$ bzr log --short
  4 Fred McCann	2015-12-24
    Added method to handle bounces

  3 Fred McCann	2015-12-24
    Added method to verify DNS

  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import

To undo the pull, we want to get back to revision 2. We can do that with bzr uncommit and bzr revert.

$ bzr uncommit -r2
  3 Fred McCann	2015-12-24
  Added method to verify DNS

  4 Fred McCann	2015-12-24
  Added method to handle bounces

  The above revision(s) will be removed.
  Uncommit these revisions? ([y]es, [n]o): yes
  You can restore the old tip by running:
  bzr pull . -r revid:fred@bzrinit.com-20131225003151-sj87spn2l0mmqja7
  
$ bzr revert
 M  mail.rb
$ bzr log --short
  2 Fred McCann	2015-12-24
  Added method to check email address

  1 Fred McCann	2015-12-24
  Initial import

See Undoing a Commit for more information on bzr uncommit.

The same technique will work for a committed merge or a push operation. In the case of a push, perform this fix in the branch you've pushed to.

This technique will not work if you've performed a push or pull on divergent branches with the --overwrite option (which you really have no good excuse to ever use). Let's assume we have the same situation as before, except instead of just being behind the remote branch by two revisions, we also have an additional revision in our local branch:

$ bzr missing --short
You have 1 extra revision:
3 Fred McCann	2015-12-24
Refactor email check method to support + marks in addresses

You are missing 2 revisions:
4 Fred McCann	2015-12-24
Added method to handle bounces

3 Fred McCann	2015-12-24
Added method to verify DNS

Now we perform a pull with --overwrite:

$ bzr pull --overwrite
$ bzr log --short
  4 Fred McCann	2015-12-24
    Added method to handle bounces

  3 Fred McCann	2015-12-24
    Added method to verify DNS

  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import

Our former revision 3 has turned into an abandoned head. To undo this pull, we need to first locate the head with the bzr heads command, then perform a second pull against the local branch with the revision identifier of the old head.

$ bzr heads --dead-only
HEAD: revision-id: fred@bzrinit.com-20131225012804-tilpa8q6imvqh3lu (dead)
committer: Fred McCann <fred@bzrinit.com>
branch nick: email
timestamp: Tue 2015-12-24 20:28:04 -0500
message:
Refactor email check method to support + marks in addresses
$ bzr pull . -rrevid:fred@bzrinit.com-20131225012804-tilpa8q6imvqh3lu --overwrite
 M  mail.rb
All changes applied successfully.
Now on revision 3.
$ bzr log --short
  3 Fred McCann	2015-12-24
    Refactor email check method to support + marks in addresses

  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import

Did I mention there's no good excuse to use the --overwrite option? See Undoing an Uncommit for more information on heads and the bzr heads command.

Merging Only Specific Revisions

In Development Pipeline I discussed the idea of having a trunk branch for development and a stable branch for released code. Let's say we have a trunk branch and a stable branch. We've added two revisions in trunk since the last release:

trunk$ bzr log --short
  6 Fred McCann	2015-12-24
    Verification of pgp signatures

  5 Fred McCann	2015-12-24
    Support for multipart messages

  4 Fred McCann	2015-12-24
    Added method to handle bounces

  3 Fred McCann	2015-12-24
    Added method to verify DNS

  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import
trunk$ cd ../stable
stable$ bzr log --short
  4 Fred McCann	2015-12-24
    Added method to handle bounces

  3 Fred McCann	2015-12-24
    Added method to verify DNS

  2 Fred McCann	2015-12-24
    Added method to check email address

  1 Fred McCann	2015-12-24
    Initial import

There's a bug with our method of verifying DNS. The correct procedure would be to fix the bug in the stable branch, then merge the changes to the trunk:

stable$ bzr commit -m"Fix error in DNS Validation"
stable$ bzr log --short
  5 Fred McCann	2015-12-24 Fix error in DNS Validation

  4 Fred McCann	2015-12-24
    Added method to handle bounces
  ...
stable$ cd ../trunk/
trunk$ bzr merge ../stable/
 M  mail.rb
Text conflict in mail.rb
1 conflicts encountered.
trunk$ bzr resolve mail.rb
trunk$ bzr log --short -n0
  7 Fred McCann	2015-12-24 [merge]
    Merge in bugfixes from stable

        4.1.1 Fred McCann	2015-12-24
              Fix error in DNS Validation

  6 Fred McCann	2015-12-24
    Verification of pgp signatures

  5 Fred McCann	2015-12-24
    Support for multipart messages

This approach works because there are no revisions in the stable branch that aren't in the trunk branch except for the fixes.

Assume that rather than fixing the bug in the stable branch first, we'd fixed the bug in the trunk branch:

trunk$ bzr log --short
  7 Fred McCann	2015-12-24
    Fix error in DNS Validation

  6 Fred McCann	2015-12-24
    Verification of pgp signatures

  5 Fred McCann	2015-12-24
    Support for multipart messages

  4 Fred McCann	2015-12-24
    Added method to handle bounces
  ...
trunk$ bzr missing ../stable/ --short
You have 3 extra revisions:
    7 Fred McCann	2015-12-24
      Fix error in DNS Validation

    6 Fred McCann	2015-12-24
      Verification of pgp signatures

    5 Fred McCann	2015-12-24
      Support for multipart messages

You can see the problem— if we were to just merge trunk into stable we'd end up releasing revisions 5 and 6 in addition to the fix. The best way to address this problem is to make your fixes in your stable branch, but if you have to, you can cherry pick the bug fix revision in the merge:

trunk$ cd ../stable/
stable$ bzr merge ../trunk/ -r6..7
 M  mail.rb
Text conflict in mail.rb
1 conflicts encountered. 
stable$ bzr resolve mail.rb
stable$ bzr commit -m"Backported DNS validation fix from trunk"
stable$ bzr log --short
  5 Fred McCann	2015-12-24
    Backported DNS validation fix from trunk

  4 Fred McCann	2015-12-24
    Added method to handle bounces

  3 Fred McCann	2015-12-24
    Added method to verify DNS
  ...

This merges all changes after revision 6 and up to revision 7— so just our bug fix revision. Cherry picking doesn't work like a normal merge. The applied revisions look like normal revisions, not a merge revision with complete sub-branch history.

In general, I'd advise against cherry picking. Good planning almost always makes this sort of merge unnecessary, but if you're in a pinch, this is how you do it.

Finding When A Bug Was Introduced

Let's say we have we're making a script that outputs the time. We get a branch of the project and notice the script doesn't work!

$ ./time.rb
./time.rb:16:in '<main>': undefined method 'nw' for Time:Class (NoMethodError)

This is not good. Let's check the log:

$ bzr log time.rb --short
  7 Fred McCann	2015-12-24
    change script to work if more than one argument is passed

  6 Fred McCann	2015-12-24
    change default pattern to %Y-%m-%d

  5 Fred McCann	2015-12-24
    modify script to show help message when called with the string 'help'

  4 Fred McCann	2015-12-24
    modify script to take an optional format string as an input

  3 Fred McCann	2015-12-24
    change time output format

  2 Fred McCann	2015-12-24
    change time output format

  1 Fred McCann	2015-12-24
    show the time

It looks like there are a bunch of changes to the script, but we really don't have any idea which revision introduced this bug. One method we could try is to use bzr revert or bzr update to pull old versions of the code out and try running the script until we find which revision introduced the bug.

Finds an interesting commit using a binary search.

A better option is to use the bzr bisect command which is provided by the Bazaar Bisect Plugin. The bzr bisect command runs a binary search on the branch history to find a revision with a certain property. In our case, we want to use it to find out when this bug was introduced.

$ bzr bisect start
$ bzr bisect yes
On revision 3 (fred@bzrinit.com-20131225025452-7duyilwrq6ax0hyi):
change time output format

The bzr bisect start command starts the binary search. We need to tell the bisect command whether or not a revision has our bug, so we start out by calling bzr bisect yes, which flags the current revision (revno 7) as having the bug.

Rather than checking each revision in turn, bisect uses a binary search and rolls us back to revision 3. We'll test to see if this revision has the bug by running the command again:

$ ./time.rb
12/24/2013 22:20
$ bzr bisect no
On revision 5 (fred@bzrinit.com-20131225025642-udhc40h5u6n749b8):
modify script to show help message when called with the string 'help'

Revision 3 works— so we'll tell bisect that it doesn't have the bug by calling bzr bisect no. Next, it rolls us back to revision 5. Let's test again:

$ ./time.rb
./time.rb:16:in '<main>': undefined method 'nw' for Time:Class (NoMethodError)
$ bzr bisect yes
On revision 4 (fred@bzrinit.com-20131225025512-crplp58zaaufozf0):
modify script to take an optional format string as an input

The bug exists in revision 5, so we call bzr bisect yes to let bisect know. Next it moves us to revision 4:

$ ./time.rb
./time.rb:16:in '<main>': undefined method 'nw' for Time:Class (NoMethodError)
$ bzr bisect yes
On revision 4 (fred@bzrinit.com-20131225025512-crplp58zaaufozf0):
modify script to take an optional format string as an input

The bug exists in revision 4 too. Notice that this time that we call bzr bisect yes and bisect moves us to revision 4 again. This means it's converged on the revision that introduced the bug. Let's test one more time and mark the failure:

$ ./time.rb
./time.rb:16:in '<main>': undefined method 'nw' for Time:Class (NoMethodError)
$ bzr bisect yes
No further bisection is possible.
On revision 4 (fred@bzrinit.com-20131225025512-crplp58zaaufozf0):
modify script to take an optional format string as an input

We've found the bug, and we didn't have to manually revert to and test every single revision until we found it!

Now that we have our answer— revision 4, we can let bisect know we're done by calling bzr bisect reset. That will put our working tree back to normal.

$ bzr bisect reset

You can use this technique to find a revision with any characteristic, not just a bug. It's also possible to automate this process with an external script to do the yes/no testing for us with bzr bisect run. See the documentation for the Bisect Plugin for more info.

Creating Command Aliases

Create, show, or remove command aliases.

Bazaar has a lot of commands, and the commands have a lot of options. If you find you're calling a certain command often, you can create an alias to save some typing. The bzr alias command will let you create aliases and view existing ones.

$ bzr alias sl="log --short"
$ bzr sl
  4 Fred McCann	2015-12-22
    Implemented add/subtract

  3 Charlie Harvey	2015-12-22 [merge]
    get up-to-date with iteration-1

  2 Charlie Harvey	2015-12-22
    Created empty Calc class and unit tests against all basic arithmetic functions

  1 Fred McCann	2015-12-21
    initial import
$ bzr alias
bzr alias sl="log --short"
$ bzr alias --remove sl
$ bzr alias

Specifying Revisions in Bazaar Commands

Revision Identifiers
Expressions that can be passed to the -r option of various commands to specify a set of revisions.

A lot of Bazaar commands take the -r option to specify a revision or a set of revisions to operate on. In this tutorial I've shown examples using a single revision number, a range of revision numbers in the form of "start..end", unique revision IDs, and tags.

There are many other options for what can be used to specify revisions including dates, branches, ancestors, and more. For a complete description of all acceptable values that can be passed to the -r option, refer to the documentation on Revision Identifiers.

Thanks for Reading!

Congratulations! You've made it all the way to the end of the tutorial. At this point you should have a pretty decent idea how to use Bazaar, and I'm sure you'll be an expert in short order.

Even though we've covered a lot of ground, Bazaar at it's core is remarkably simple, and you'll find that your day to day use involves a handful of basic commands. Once you get the hang of them, you'll have no problem customizing your use of Bazaar so that it complements any workflow.

Of course, there's always more to learn. You can browse the official documentation which covers all the commands I've shown you. You can also check out the support resources page, the official list of Bazaar tutorials, and there's even a book you can buy.

Good luck!

fin. (EOF)