~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_update.py

  • Committer: Patch Queue Manager
  • Date: 2013-05-23 10:35:23 UTC
  • mfrom: (6574.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20130523103523-2wt6jmauja1n1vdt
(jameinel) Merge bzr/2.5 into trunk. (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 by Canonical Ltd
2
 
# -*- coding: utf-8 -*-
3
 
 
 
1
# Copyright (C) 2006-2011 Canonical Ltd
 
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
6
5
# the Free Software Foundation; either version 2 of the License, or
7
6
# (at your option) any later version.
8
 
 
 
7
#
9
8
# This program is distributed in the hope that it will be useful,
10
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
11
# GNU General Public License for more details.
13
 
 
 
12
#
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
16
 
18
17
 
19
18
"""Tests for the update command of bzr."""
20
19
 
21
 
 
22
 
from bzrlib.tests import TestSkipped
23
 
from bzrlib.tests.blackbox import ExternalBase
24
 
from bzrlib.workingtree import WorkingTree
25
 
 
26
 
 
27
 
class TestUpdate(ExternalBase):
 
20
import os
 
21
 
 
22
from bzrlib import (
 
23
    branch,
 
24
    bzrdir,
 
25
    osutils,
 
26
    tests,
 
27
    workingtree,
 
28
    )
 
29
from bzrlib.tests.script import ScriptRunner
 
30
 
 
31
 
 
32
class TestUpdate(tests.TestCaseWithTransport):
28
33
 
29
34
    def test_update_standalone_trivial(self):
30
 
        self.runbzr("init")
31
 
        out, err = self.runbzr('update')
32
 
        self.assertEqual('Tree is up to date at revision 0.\n', err)
 
35
        self.make_branch_and_tree('.')
 
36
        out, err = self.run_bzr('update')
 
37
        self.assertEqual(
 
38
            'Tree is up to date at revision 0 of branch %s\n' % self.test_dir,
 
39
            err)
 
40
        self.assertEqual('', out)
 
41
 
 
42
    def test_update_quiet(self):
 
43
        self.make_branch_and_tree('.')
 
44
        out, err = self.run_bzr('update --quiet')
 
45
        self.assertEqual('', err)
 
46
        self.assertEqual('', out)
 
47
 
 
48
    def test_update_standalone_trivial_with_alias_up(self):
 
49
        self.make_branch_and_tree('.')
 
50
        out, err = self.run_bzr('up')
 
51
        self.assertEqual('Tree is up to date at revision 0 of branch %s\n'
 
52
                         % self.test_dir,
 
53
                         err)
33
54
        self.assertEqual('', out)
34
55
 
35
56
    def test_update_up_to_date_light_checkout(self):
36
57
        self.make_branch_and_tree('branch')
37
 
        self.runbzr('checkout --lightweight branch checkout')
38
 
        out, err = self.runbzr('update checkout')
39
 
        self.assertEqual('Tree is up to date at revision 0.\n', err)
 
58
        self.run_bzr('checkout --lightweight branch checkout')
 
59
        out, err = self.run_bzr('update checkout')
 
60
        self.assertEqual('Tree is up to date at revision 0 of branch %s\n'
 
61
                         % osutils.pathjoin(self.test_dir, 'branch'),
 
62
                         err)
40
63
        self.assertEqual('', out)
41
64
 
42
65
    def test_update_up_to_date_checkout(self):
43
66
        self.make_branch_and_tree('branch')
44
 
        self.run_bzr('checkout', 'branch', 'checkout')
45
 
        out, err = self.run_bzr('update', 'checkout')
46
 
        self.assertEqual('Tree is up to date at revision 0.\n', err)
47
 
        self.assertEqual('', out)
 
67
        self.run_bzr('checkout branch checkout')
 
68
        sr = ScriptRunner()
 
69
        sr.run_script(self, '''
 
70
$ bzr update checkout
 
71
2>Tree is up to date at revision 0 of branch .../branch
 
72
''')
48
73
 
49
74
    def test_update_out_of_date_standalone_tree(self):
50
75
        # FIXME the default format has to change for this to pass
51
76
        # because it currently uses the branch last-revision marker.
52
 
        raise TestSkipped('default format too old')
53
77
        self.make_branch_and_tree('branch')
54
78
        # make a checkout
55
 
        self.runbzr('checkout --lightweight branch checkout')
 
79
        self.run_bzr('checkout --lightweight branch checkout')
56
80
        self.build_tree(['checkout/file'])
57
 
        self.runbzr('add checkout/file')
58
 
        self.runbzr('commit -m add-file checkout')
 
81
        self.run_bzr('add checkout/file')
 
82
        self.run_bzr('commit -m add-file checkout')
59
83
        # now branch should be out of date
60
 
        out,err = self.runbzr('update branch')
61
 
        self.assertEqual('Updated to revision 1.\n', out)
62
 
        self.assertEqual('', err)
63
 
        self.failUnlessExists('branch/file')
 
84
        out,err = self.run_bzr('update branch')
 
85
        self.assertEqual('', out)
 
86
        self.assertEqualDiff("""+N  file
 
87
All changes applied successfully.
 
88
Updated to revision 1 of branch %s
 
89
""" % osutils.pathjoin(self.test_dir, 'branch',),
 
90
                         err)
 
91
        self.assertPathExists('branch/file')
64
92
 
65
93
    def test_update_out_of_date_light_checkout(self):
66
94
        self.make_branch_and_tree('branch')
67
95
        # make two checkouts
68
 
        self.runbzr('checkout --lightweight branch checkout')
69
 
        self.runbzr('checkout --lightweight branch checkout2')
 
96
        self.run_bzr('checkout --lightweight branch checkout')
 
97
        self.run_bzr('checkout --lightweight branch checkout2')
70
98
        self.build_tree(['checkout/file'])
71
 
        self.runbzr('add checkout/file')
72
 
        self.runbzr('commit -m add-file checkout')
 
99
        self.run_bzr('add checkout/file')
 
100
        self.run_bzr('commit -m add-file checkout')
73
101
        # now checkout2 should be out of date
74
 
        out,err = self.runbzr('update checkout2')
75
 
        self.assertEqual('All changes applied successfully.\n'
76
 
                         'Updated to revision 1.\n',
 
102
        out,err = self.run_bzr('update checkout2')
 
103
        self.assertEqualDiff('''+N  file
 
104
All changes applied successfully.
 
105
Updated to revision 1 of branch %s
 
106
''' % osutils.pathjoin(self.test_dir, 'branch',),
77
107
                         err)
78
108
        self.assertEqual('', out)
79
109
 
80
110
    def test_update_conflicts_returns_2(self):
81
111
        self.make_branch_and_tree('branch')
82
112
        # make two checkouts
83
 
        self.runbzr('checkout --lightweight branch checkout')
 
113
        self.run_bzr('checkout --lightweight branch checkout')
84
114
        self.build_tree(['checkout/file'])
85
 
        self.runbzr('add checkout/file')
86
 
        self.runbzr('commit -m add-file checkout')
87
 
        self.runbzr('checkout --lightweight branch checkout2')
 
115
        self.run_bzr('add checkout/file')
 
116
        self.run_bzr('commit -m add-file checkout')
 
117
        self.run_bzr('checkout --lightweight branch checkout2')
88
118
        # now alter file in checkout
89
119
        a_file = file('checkout/file', 'wt')
90
120
        a_file.write('Foo')
91
121
        a_file.close()
92
 
        self.runbzr('commit -m checnge-file checkout')
 
122
        self.run_bzr('commit -m checnge-file checkout')
93
123
        # now checkout2 should be out of date
94
124
        # make a local change to file
95
125
        a_file = file('checkout2/file', 'wt')
96
126
        a_file.write('Bar')
97
127
        a_file.close()
98
 
        out,err = self.runbzr('update checkout2', retcode=1)
99
 
        self.assertEqual(['1 conflicts encountered.',
100
 
                          'Updated to revision 2.'],
101
 
                         err.split('\n')[1:3])
102
 
        self.assertContainsRe(err, 'Text conflict in file\n')
 
128
        out,err = self.run_bzr('update checkout2', retcode=1)
 
129
        self.assertEqualDiff(''' M  file
 
130
Text conflict in file
 
131
1 conflicts encountered.
 
132
Updated to revision 2 of branch %s
 
133
''' % osutils.pathjoin(self.test_dir, 'branch',),
 
134
                         err)
103
135
        self.assertEqual('', out)
104
136
 
105
137
    def test_smoke_update_checkout_bound_branch_local_commits(self):
106
138
        # smoke test for doing an update of a checkout of a bound
107
139
        # branch with local commits.
108
 
        self.make_branch_and_tree('master')
 
140
        master = self.make_branch_and_tree('master')
 
141
        master.commit('first commit')
109
142
        # make a bound branch
110
 
        self.run_bzr('checkout', 'master', 'child')
 
143
        self.run_bzr('checkout master child')
111
144
        # check that out
112
 
        self.run_bzr('checkout', '--lightweight', 'child', 'checkout')
 
145
        self.run_bzr('checkout --lightweight child checkout')
 
146
        # get an object form of the checkout to manipulate
 
147
        wt = workingtree.WorkingTree.open('checkout')
113
148
        # change master
114
149
        a_file = file('master/file', 'wt')
115
150
        a_file.write('Foo')
116
151
        a_file.close()
117
 
        self.run_bzr('add', 'master')
118
 
        self.run_bzr('commit', '-m', 'add file', 'master')
 
152
        master.add(['file'])
 
153
        master_tip = master.commit('add file')
119
154
        # change child
120
155
        a_file = file('child/file_b', 'wt')
121
156
        a_file.write('Foo')
122
157
        a_file.close()
123
 
        self.run_bzr('add', 'child')
124
 
        self.run_bzr('commit', '--local', '-m', 'add file_b', 'child')
 
158
        # get an object form of child
 
159
        child = workingtree.WorkingTree.open('child')
 
160
        child.add(['file_b'])
 
161
        child_tip = child.commit('add file_b', local=True)
125
162
        # check checkout
126
163
        a_file = file('checkout/file_c', 'wt')
127
164
        a_file.write('Foo')
128
165
        a_file.close()
129
 
        self.run_bzr('add', 'checkout')
 
166
        wt.add(['file_c'])
130
167
 
131
168
        # now, update checkout ->
132
169
        # get all three files and a pending merge.
133
 
        self.run_bzr('update', 'checkout')
134
 
        wt = WorkingTree.open('checkout')
135
 
        self.assertNotEqual([], wt.pending_merges())
136
 
        self.failUnlessExists('checkout/file')
137
 
        self.failUnlessExists('checkout/file_b')
138
 
        self.failUnlessExists('checkout/file_c')
 
170
        out, err = self.run_bzr('update checkout')
 
171
        self.assertEqual('', out)
 
172
        self.assertEqualDiff("""+N  file_b
 
173
All changes applied successfully.
 
174
+N  file
 
175
All changes applied successfully.
 
176
Updated to revision 2 of branch %s
 
177
Your local commits will now show as pending merges with 'bzr status', and can be committed with 'bzr commit'.
 
178
""" % osutils.pathjoin(self.test_dir, 'master',),
 
179
                         err)
 
180
        self.assertEqual([master_tip, child_tip], wt.get_parent_ids())
 
181
        self.assertPathExists('checkout/file')
 
182
        self.assertPathExists('checkout/file_b')
 
183
        self.assertPathExists('checkout/file_c')
139
184
        self.assertTrue(wt.has_filename('file_c'))
 
185
 
 
186
    def test_update_with_merges(self):
 
187
        # Test that 'bzr update' works correctly when you have
 
188
        # an update in the master tree, and a lightweight checkout
 
189
        # which has merged another branch
 
190
        master = self.make_branch_and_tree('master')
 
191
        self.build_tree(['master/file'])
 
192
        master.add(['file'])
 
193
        master.commit('one', rev_id='m1')
 
194
 
 
195
        self.build_tree(['checkout1/'])
 
196
        checkout_dir = bzrdir.BzrDirMetaFormat1().initialize('checkout1')
 
197
        checkout_dir.set_branch_reference(master.branch)
 
198
        checkout1 = checkout_dir.create_workingtree('m1')
 
199
 
 
200
        # Create a second branch, with an extra commit
 
201
        other = master.bzrdir.sprout('other').open_workingtree()
 
202
        self.build_tree(['other/file2'])
 
203
        other.add(['file2'])
 
204
        other.commit('other2', rev_id='o2')
 
205
 
 
206
        # Create a new commit in the master branch
 
207
        self.build_tree(['master/file3'])
 
208
        master.add(['file3'])
 
209
        master.commit('f3', rev_id='m2')
 
210
 
 
211
        # Merge the other branch into checkout
 
212
        os.chdir('checkout1')
 
213
        self.run_bzr('merge ../other')
 
214
 
 
215
        self.assertEqual(['o2'], checkout1.get_parent_ids()[1:])
 
216
 
 
217
        # At this point, 'commit' should fail, because we are out of date
 
218
        self.run_bzr_error(["please run 'bzr update'"],
 
219
                           'commit -m merged')
 
220
 
 
221
        # This should not report about local commits being pending
 
222
        # merges, because they were real merges
 
223
        out, err = self.run_bzr('update')
 
224
        self.assertEqual('', out)
 
225
        self.assertEqualDiff('''+N  file3
 
226
All changes applied successfully.
 
227
Updated to revision 2 of branch %s
 
228
''' % osutils.pathjoin(self.test_dir, 'master',),
 
229
                         err)
 
230
        # The pending merges should still be there
 
231
        self.assertEqual(['o2'], checkout1.get_parent_ids()[1:])
 
232
 
 
233
    def test_readonly_lightweight_update(self):
 
234
        """Update a light checkout of a readonly branch"""
 
235
        tree = self.make_branch_and_tree('branch')
 
236
        readonly_branch = branch.Branch.open(self.get_readonly_url('branch'))
 
237
        checkout = readonly_branch.create_checkout('checkout',
 
238
                                                   lightweight=True)
 
239
        tree.commit('empty commit')
 
240
        self.run_bzr('update checkout')
 
241
 
 
242
    def test_update_with_merge_merged_to_master(self):
 
243
        # Test that 'bzr update' works correctly when you have
 
244
        # an update in the master tree, and a [lightweight or otherwise]
 
245
        # checkout which has merge a revision merged to master already.
 
246
        master = self.make_branch_and_tree('master')
 
247
        self.build_tree(['master/file'])
 
248
        master.add(['file'])
 
249
        master.commit('one', rev_id='m1')
 
250
 
 
251
        self.build_tree(['checkout1/'])
 
252
        checkout_dir = bzrdir.BzrDirMetaFormat1().initialize('checkout1')
 
253
        checkout_dir.set_branch_reference(master.branch)
 
254
        checkout1 = checkout_dir.create_workingtree('m1')
 
255
 
 
256
        # Create a second branch, with an extra commit
 
257
        other = master.bzrdir.sprout('other').open_workingtree()
 
258
        self.build_tree(['other/file2'])
 
259
        other.add(['file2'])
 
260
        other.commit('other2', rev_id='o2')
 
261
 
 
262
        # Merge the other branch into checkout -  'start reviewing a patch'
 
263
        checkout1.merge_from_branch(other.branch)
 
264
        self.assertEqual(['o2'], checkout1.get_parent_ids()[1:])
 
265
 
 
266
        # Create a new commit in the master branch - 'someone else lands its'
 
267
        master.merge_from_branch(other.branch)
 
268
        master.commit('f3', rev_id='m2')
 
269
 
 
270
        # This should not report about local commits being pending
 
271
        # merges, because they were real merges (but are now gone).
 
272
        # It should perhaps report on them.
 
273
        out, err = self.run_bzr('update', working_dir='checkout1')
 
274
        self.assertEqual('', out)
 
275
        self.assertEqualDiff('''All changes applied successfully.
 
276
Updated to revision 2 of branch %s
 
277
''' % osutils.pathjoin(self.test_dir, 'master',),
 
278
                         err)
 
279
        # The pending merges should still be there
 
280
        self.assertEqual([], checkout1.get_parent_ids()[1:])
 
281
 
 
282
    def test_update_dash_r(self):
 
283
        master = self.make_branch_and_tree('master')
 
284
        os.chdir('master')
 
285
        self.build_tree(['./file1'])
 
286
        master.add(['file1'])
 
287
        master.commit('one', rev_id='m1')
 
288
        self.build_tree(['./file2'])
 
289
        master.add(['file2'])
 
290
        master.commit('two', rev_id='m2')
 
291
 
 
292
        sr = ScriptRunner()
 
293
        sr.run_script(self, '''
 
294
$ bzr update -r 1
 
295
2>-D  file2
 
296
2>All changes applied successfully.
 
297
2>Updated to revision 1 of .../master
 
298
''')
 
299
        self.assertPathExists('./file1')
 
300
        self.assertPathDoesNotExist('./file2')
 
301
        self.assertEquals(['m1'], master.get_parent_ids())
 
302
 
 
303
    def test_update_dash_r_outside_history(self):
 
304
        """Ensure that we can update -r to dotted revisions.
 
305
        """
 
306
        master = self.make_branch_and_tree('master')
 
307
        self.build_tree(['master/file1'])
 
308
        master.add(['file1'])
 
309
        master.commit('one', rev_id='m1')
 
310
 
 
311
        # Create a second branch, with extra commits
 
312
        other = master.bzrdir.sprout('other').open_workingtree()
 
313
        self.build_tree(['other/file2', 'other/file3'])
 
314
        other.add(['file2'])
 
315
        other.commit('other2', rev_id='o2')
 
316
        other.add(['file3'])
 
317
        other.commit('other3', rev_id='o3')
 
318
 
 
319
        os.chdir('master')
 
320
        self.run_bzr('merge ../other')
 
321
        master.commit('merge', rev_id='merge')
 
322
 
 
323
        # Switch to o2. file3 was added only in o3 and should be deleted.
 
324
        out, err = self.run_bzr('update -r revid:o2')
 
325
        self.assertContainsRe(err, '-D\s+file3')
 
326
        self.assertContainsRe(err, 'All changes applied successfully\.')
 
327
        self.assertContainsRe(err, 'Updated to revision 1.1.1 of branch .*')
 
328
 
 
329
        # Switch back to latest
 
330
        out, err = self.run_bzr('update')
 
331
        self.assertContainsRe(err, '\+N\s+file3')
 
332
        self.assertContainsRe(err, 'All changes applied successfully\.')
 
333
        self.assertContainsRe(err, 'Updated to revision 2 of branch .*')
 
334
 
 
335
    def test_update_dash_r_in_master(self):
 
336
        # Test that 'bzr update' works correctly when you have
 
337
        # an update in the master tree,
 
338
        master = self.make_branch_and_tree('master')
 
339
        self.build_tree(['master/file1'])
 
340
        master.add(['file1'])
 
341
        master.commit('one', rev_id='m1')
 
342
 
 
343
        self.run_bzr('checkout master checkout')
 
344
 
 
345
        # add a revision in the master.
 
346
        self.build_tree(['master/file2'])
 
347
        master.add(['file2'])
 
348
        master.commit('two', rev_id='m2')
 
349
 
 
350
        os.chdir('checkout')
 
351
        sr = ScriptRunner()
 
352
        sr.run_script(self, '''
 
353
$ bzr update -r revid:m2
 
354
2>+N  file2
 
355
2>All changes applied successfully.
 
356
2>Updated to revision 2 of branch .../master
 
357
''')
 
358
 
 
359
    def test_update_show_base(self):
 
360
        """bzr update support --show-base
 
361
 
 
362
        see https://bugs.launchpad.net/bzr/+bug/202374"""
 
363
 
 
364
        tree=self.make_branch_and_tree('.')
 
365
 
 
366
        f = open('hello','wt')
 
367
        f.write('foo')
 
368
        f.close()
 
369
        tree.add('hello')
 
370
        tree.commit('fie')
 
371
 
 
372
        f = open('hello','wt')
 
373
        f.write('fee')
 
374
        f.close()
 
375
        tree.commit('fee')
 
376
 
 
377
        #tree.update() gives no such revision, so ...
 
378
        self.run_bzr(['update','-r1'])
 
379
 
 
380
        #create conflict
 
381
        f = open('hello','wt')
 
382
        f.write('fie')
 
383
        f.close()
 
384
 
 
385
        out, err = self.run_bzr(['update','--show-base'],retcode=1)
 
386
 
 
387
        # check for conflict notification
 
388
        self.assertContainsString(err,
 
389
                                  ' M  hello\nText conflict in hello\n1 conflicts encountered.\n')
 
390
        
 
391
        self.assertEqualDiff('<<<<<<< TREE\n'
 
392
                             'fie||||||| BASE-REVISION\n'
 
393
                             'foo=======\n'
 
394
                             'fee>>>>>>> MERGE-SOURCE\n',
 
395
                             open('hello').read())
 
396
 
 
397
    def test_update_checkout_prevent_double_merge(self):
 
398
        """"Launchpad bug 113809 in bzr "update performs two merges"
 
399
        https://launchpad.net/bugs/113809"""
 
400
        master = self.make_branch_and_tree('master')
 
401
        self.build_tree_contents([('master/file', 'initial contents\n')])
 
402
        master.add(['file'])
 
403
        master.commit('one', rev_id='m1')
 
404
 
 
405
        checkout = master.branch.create_checkout('checkout')
 
406
        lightweight = checkout.branch.create_checkout('lightweight',
 
407
                                                      lightweight=True)
 
408
 
 
409
        # time to create a mess
 
410
        # add a commit to the master
 
411
        self.build_tree_contents([('master/file', 'master\n')])
 
412
        master.commit('two', rev_id='m2')
 
413
        self.build_tree_contents([('master/file', 'master local changes\n')])
 
414
 
 
415
        # local commit on the checkout
 
416
        self.build_tree_contents([('checkout/file', 'checkout\n')])
 
417
        checkout.commit('tree', rev_id='c2', local=True)
 
418
        self.build_tree_contents([('checkout/file',
 
419
                                   'checkout local changes\n')])
 
420
 
 
421
        # lightweight 
 
422
        self.build_tree_contents([('lightweight/file',
 
423
                                   'lightweight local changes\n')])
 
424
 
 
425
        # now update (and get conflicts)
 
426
        out, err = self.run_bzr('update lightweight', retcode=1)
 
427
        self.assertEqual('', out)
 
428
        # NB: these conflicts are actually in the source code
 
429
        self.assertFileEqual('''\
 
430
<<<<<<< TREE
 
431
lightweight local changes
 
432
=======
 
433
checkout
 
434
>>>>>>> MERGE-SOURCE
 
435
''',
 
436
                             'lightweight/file')
 
437
 
 
438
        # resolve it
 
439
        self.build_tree_contents([('lightweight/file',
 
440
                                   'lightweight+checkout\n')])
 
441
        self.run_bzr('resolve lightweight/file')
 
442
 
 
443
        # check we get the second conflict
 
444
        out, err = self.run_bzr('update lightweight', retcode=1)
 
445
        self.assertEqual('', out)
 
446
        # NB: these conflicts are actually in the source code
 
447
        self.assertFileEqual('''\
 
448
<<<<<<< TREE
 
449
lightweight+checkout
 
450
=======
 
451
master
 
452
>>>>>>> MERGE-SOURCE
 
453
''',
 
454
                             'lightweight/file')
 
455
 
 
456
 
 
457
    def test_no_upgrade_single_file(self):
 
458
        """There's one basis revision per tree.
 
459
 
 
460
        Since you can't actually change the basis for a single file at the
 
461
        moment, we don't let you think you can.
 
462
 
 
463
        See bug 557886.
 
464
        """
 
465
        self.make_branch_and_tree('.')
 
466
        self.build_tree_contents([('a/',),
 
467
            ('a/file', 'content')])
 
468
        sr = ScriptRunner()
 
469
        sr.run_script(self, '''
 
470
            $ bzr update ./a
 
471
            2>bzr: ERROR: bzr update can only update a whole tree, not a file or subdirectory
 
472
            $ bzr update ./a/file
 
473
            2>bzr: ERROR: bzr update can only update a whole tree, not a file or subdirectory
 
474
            $ bzr update .
 
475
            2>Tree is up to date at revision 0 of branch ...
 
476
            $ cd a
 
477
            $ bzr update .
 
478
            2>bzr: ERROR: bzr update can only update a whole tree, not a file or subdirectory
 
479
            # however, you can update the whole tree from a subdirectory
 
480
            $ bzr update
 
481
            2>Tree is up to date at revision 0 of branch ...
 
482
            ''')