90
89
out, err = self.run_bzr('branches b')
91
90
self.assertEqual(" orig\n thiswasa\n", out)
92
91
self.assertEqual('', err)
93
out, err = self.run_bzr('branch a file:b,branch=orig', retcode=3)
92
out,err = self.run_bzr('branch a file:b,branch=orig', retcode=3)
94
93
self.assertEqual('', out)
96
95
'brz: ERROR: Already a branch: "file:b,branch=orig".\n', err)
98
97
def test_from_colocated(self):
99
98
"""Branch from a colocated branch into a regular branch."""
101
tree = self.example_branch('b/a', format='development-colo')
102
tree.controldir.create_branch(name='somecolo')
99
tree = self.example_branch('a', format='development-colo')
100
tree.bzrdir.create_branch(name='somecolo')
103
101
out, err = self.run_bzr('branch %s,branch=somecolo' %
104
local_path_to_url('b/a'))
105
self.assertEqual('', out)
106
self.assertEqual('Branched 0 revisions.\n', err)
107
self.assertPathExists('a')
109
def test_from_name(self):
110
"""Branch from a colocated branch into a regular branch."""
112
tree = self.example_branch('b/a', format='development-colo')
113
tree.controldir.create_branch(name='somecolo')
114
out, err = self.run_bzr('branch -b somecolo %s' %
115
local_path_to_url('b/a'))
116
self.assertEqual('', out)
117
self.assertEqual('Branched 0 revisions.\n', err)
118
self.assertPathExists('a')
102
local_path_to_url('a'))
103
self.assertEqual('', out)
104
self.assertEqual('Branched 0 revisions.\n', err)
105
self.assertPathExists("somecolo")
120
107
def test_branch_broken_pack(self):
121
108
"""branching with a corrupted pack file."""
221
208
shared_repo.set_make_working_trees(True)
223
210
def make_shared_tree(path):
224
shared_repo.controldir.root_transport.mkdir(path)
211
shared_repo.bzrdir.root_transport.mkdir(path)
225
212
controldir.ControlDir.create_branch_convenience('repo/' + path)
226
213
return WorkingTree.open('repo/' + path)
227
214
tree_a = make_shared_tree('a')
228
215
self.build_tree(['repo/a/file'])
229
216
tree_a.add('file')
230
tree_a.commit('commit a-1', rev_id=b'a-1')
231
with open('repo/a/file', 'ab') as f:
232
f.write(b'more stuff\n')
233
tree_a.commit('commit a-2', rev_id=b'a-2')
217
tree_a.commit('commit a-1', rev_id='a-1')
218
f = open('repo/a/file', 'ab')
219
f.write('more stuff\n')
221
tree_a.commit('commit a-2', rev_id='a-2')
235
223
tree_b = make_shared_tree('b')
236
224
self.build_tree(['repo/b/file'])
237
225
tree_b.add('file')
238
tree_b.commit('commit b-1', rev_id=b'b-1')
226
tree_b.commit('commit b-1', rev_id='b-1')
240
self.assertTrue(shared_repo.has_revision(b'a-1'))
241
self.assertTrue(shared_repo.has_revision(b'a-2'))
242
self.assertTrue(shared_repo.has_revision(b'b-1'))
228
self.assertTrue(shared_repo.has_revision('a-1'))
229
self.assertTrue(shared_repo.has_revision('a-2'))
230
self.assertTrue(shared_repo.has_revision('b-1'))
244
232
# Now that we have a repository with shared files, make sure
245
233
# that things aren't copied out by a 'branch'
246
234
self.run_bzr('branch repo/b branch-b')
247
235
pushed_tree = WorkingTree.open('branch-b')
248
236
pushed_repo = pushed_tree.branch.repository
249
self.assertFalse(pushed_repo.has_revision(b'a-1'))
250
self.assertFalse(pushed_repo.has_revision(b'a-2'))
251
self.assertTrue(pushed_repo.has_revision(b'b-1'))
237
self.assertFalse(pushed_repo.has_revision('a-1'))
238
self.assertFalse(pushed_repo.has_revision('a-2'))
239
self.assertTrue(pushed_repo.has_revision('b-1'))
253
241
def test_branch_hardlink(self):
254
242
self.requireFeature(HardlinkFeature)
303
291
self.example_branch('a')
304
292
# existing dir with similar files but no .brz dir
305
293
self.build_tree_contents([('b/',)])
306
self.build_tree_contents([('b/hello', b'bar')]) # different content
307
self.build_tree_contents([('b/goodbye', b'baz')]) # same content
294
self.build_tree_contents([('b/hello', 'bar')]) # different content
295
self.build_tree_contents([('b/goodbye', 'baz')])# same content
308
296
# fails without --use-existing-dir
309
out, err = self.run_bzr('branch a b', retcode=3)
297
out,err = self.run_bzr('branch a b', retcode=3)
310
298
self.assertEqual('', out)
311
299
self.assertEqual('brz: ERROR: Target directory "b" already exists.\n',
313
301
# force operation
314
302
self.run_bzr('branch a b --use-existing-dir')
315
303
# check conflicts
316
304
self.assertPathExists('b/hello.moved')
317
305
self.assertPathDoesNotExist('b/godbye.moved')
318
306
# we can't branch into branch
319
out, err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
307
out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
320
308
self.assertEqual('', out)
321
309
self.assertEqual('brz: ERROR: Already a branch: "b".\n', err)
360
348
def test_branch_fetches_all_tags(self):
361
349
builder = self.make_branch_builder('source')
362
source, rev1, rev2 = fixtures.build_branch_with_non_ancestral_rev(
364
source.tags.set_tag('tag-a', rev2)
350
source = fixtures.build_branch_with_non_ancestral_rev(builder)
351
source.tags.set_tag('tag-a', 'rev-2')
365
352
source.get_config_stack().set('branch.fetch_tags', True)
366
353
# Now source has a tag not in its ancestry. Make a branch from it.
367
354
self.run_bzr('branch source new-branch')
368
355
new_branch = branch.Branch.open('new-branch')
369
356
# The tag is present, and so is its revision.
370
self.assertEqual(rev2, new_branch.tags.lookup_tag('tag-a'))
371
new_branch.repository.get_revision(rev2)
373
def test_branch_with_nested_trees(self):
374
orig = self.make_branch_and_tree('source', format='development-subtree')
375
subtree = self.make_branch_and_tree('source/subtree')
376
self.build_tree(['source/subtree/a'])
378
subtree.commit('add subtree contents')
379
orig.add_reference(subtree)
380
orig.set_reference_info('subtree', subtree.branch.user_url)
381
orig.commit('add subtree')
383
self.run_bzr('branch source target')
385
target = WorkingTree.open('target')
386
target_subtree = WorkingTree.open('target/subtree')
387
self.assertTreesEqual(orig, target)
388
self.assertTreesEqual(subtree, target_subtree)
390
def test_branch_with_nested_trees_reference_unset(self):
391
orig = self.make_branch_and_tree('source', format='development-subtree')
392
subtree = self.make_branch_and_tree('source/subtree')
393
self.build_tree(['source/subtree/a'])
395
subtree.commit('add subtree contents')
396
orig.add_reference(subtree)
397
orig.commit('add subtree')
399
self.run_bzr('branch source target')
401
target = WorkingTree.open('target')
402
self.assertRaises(errors.NotBranchError, WorkingTree.open, 'target/subtree')
404
def test_branch_with_nested_trees_no_recurse(self):
405
orig = self.make_branch_and_tree('source', format='development-subtree')
406
subtree = self.make_branch_and_tree('source/subtree')
407
self.build_tree(['source/subtree/a'])
409
subtree.commit('add subtree contents')
410
orig.add_reference(subtree)
411
orig.commit('add subtree')
413
self.run_bzr('branch --no-recurse-nested source target')
415
target = WorkingTree.open('target')
416
self.addCleanup(subtree.lock_read().unlock)
417
basis = subtree.basis_tree()
418
self.addCleanup(basis.lock_read().unlock)
419
self.assertRaises(errors.NotBranchError, WorkingTree.open, 'target/subtree')
357
self.assertEqual('rev-2', new_branch.tags.lookup_tag('tag-a'))
358
new_branch.repository.get_revision('rev-2')
422
361
class TestBranchStacked(tests.TestCaseWithTransport):
435
374
def assertRevisionsInBranchRepository(self, revid_list, branch_path):
436
375
repo = branch.Branch.open(branch_path).repository
437
376
self.assertEqual(set(revid_list),
438
repo.has_revisions(revid_list))
377
repo.has_revisions(revid_list))
440
379
def test_branch_stacked_branch_not_stacked(self):
441
380
"""Branching a stacked branch is not stacked by default"""
442
381
# We have a mainline
443
382
trunk_tree = self.make_branch_and_tree('target',
445
384
trunk_tree.commit('mainline')
446
385
# and a branch from it which is stacked
447
386
branch_tree = self.make_branch_and_tree('branch',
449
388
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
450
389
# with some work on it
451
work_tree = trunk_tree.branch.controldir.sprout(
452
'local').open_workingtree()
390
work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
453
391
work_tree.commit('moar work plz')
454
392
work_tree.branch.push(branch_tree.branch)
455
393
# branching our local branch gives us a new stacked branch pointing at
457
395
out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
458
396
self.assertEqual('', out)
459
397
self.assertEqual('Branched 2 revisions.\n',
461
399
# it should have preserved the branch format, and so it should be
462
400
# capable of supporting stacking, but not actually have a stacked_on
463
401
# branch configured
464
402
self.assertRaises(errors.NotStacked,
465
controldir.ControlDir.open('newbranch').open_branch().get_stacked_on_url)
403
controldir.ControlDir.open('newbranch').open_branch().get_stacked_on_url)
467
405
def test_branch_stacked_branch_stacked(self):
468
406
"""Asking to stack on a stacked branch does work"""
469
407
# We have a mainline
470
408
trunk_tree = self.make_branch_and_tree('target',
472
410
trunk_revid = trunk_tree.commit('mainline')
473
411
# and a branch from it which is stacked
474
412
branch_tree = self.make_branch_and_tree('branch',
476
414
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
477
415
# with some work on it
478
work_tree = trunk_tree.branch.controldir.sprout(
479
'local').open_workingtree()
416
work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
480
417
branch_revid = work_tree.commit('moar work plz')
481
418
work_tree.branch.push(branch_tree.branch)
482
419
# you can chain branches on from there
483
420
out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
484
421
self.assertEqual('', out)
485
422
self.assertEqual('Created new stacked branch referring to %s.\n' %
486
branch_tree.branch.base, err)
423
branch_tree.branch.base, err)
487
424
self.assertEqual(branch_tree.branch.base,
488
branch.Branch.open('branch2').get_stacked_on_url())
425
branch.Branch.open('branch2').get_stacked_on_url())
489
426
branch2_tree = WorkingTree.open('branch2')
490
427
branch2_revid = work_tree.commit('work on second stacked branch')
491
428
work_tree.branch.push(branch2_tree.branch)
490
class TestSmartServerBranching(tests.TestCaseWithTransport):
492
def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
493
self.setup_smart_server_with_call_log()
494
t = self.make_branch_and_tree('from')
495
for count in range(9):
496
t.commit(message='commit %d' % count)
497
self.reset_smart_call_log()
498
out, err = self.run_bzr(['branch', self.get_url('from'),
499
self.get_url('target')])
500
# This figure represent the amount of work to perform this use case. It
501
# is entirely ok to reduce this number if a test fails due to rpc_count
502
# being too low. If rpc_count increases, more network roundtrips have
503
# become necessary for this use case. Please do not adjust this number
504
# upwards without agreement from bzr's network support maintainers.
505
self.assertLength(2, self.hpss_connections)
506
self.assertLength(33, self.hpss_calls)
507
self.expectFailure("branching to the same branch requires VFS access",
508
self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
510
def test_branch_from_trivial_branch_streaming_acceptance(self):
511
self.setup_smart_server_with_call_log()
512
t = self.make_branch_and_tree('from')
513
for count in range(9):
514
t.commit(message='commit %d' % count)
515
self.reset_smart_call_log()
516
out, err = self.run_bzr(['branch', self.get_url('from'),
518
# This figure represent the amount of work to perform this use case. It
519
# is entirely ok to reduce this number if a test fails due to rpc_count
520
# being too low. If rpc_count increases, more network roundtrips have
521
# become necessary for this use case. Please do not adjust this number
522
# upwards without agreement from bzr's network support maintainers.
523
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
524
self.assertLength(10, self.hpss_calls)
525
self.assertLength(1, self.hpss_connections)
527
def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
528
self.setup_smart_server_with_call_log()
529
t = self.make_branch_and_tree('trunk')
530
for count in range(8):
531
t.commit(message='commit %d' % count)
532
tree2 = t.branch.bzrdir.sprout('feature', stacked=True
534
local_tree = t.branch.bzrdir.sprout('local-working').open_workingtree()
535
local_tree.commit('feature change')
536
local_tree.branch.push(tree2.branch)
537
self.reset_smart_call_log()
538
out, err = self.run_bzr(['branch', self.get_url('feature'),
540
# This figure represent the amount of work to perform this use case. It
541
# is entirely ok to reduce this number if a test fails due to rpc_count
542
# being too low. If rpc_count increases, more network roundtrips have
543
# become necessary for this use case. Please do not adjust this number
544
# upwards without agreement from bzr's network support maintainers.
545
self.assertLength(15, self.hpss_calls)
546
self.assertLength(1, self.hpss_connections)
547
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
549
def test_branch_from_branch_with_tags(self):
550
self.setup_smart_server_with_call_log()
551
builder = self.make_branch_builder('source')
552
source = fixtures.build_branch_with_non_ancestral_rev(builder)
553
source.get_config_stack().set('branch.fetch_tags', True)
554
source.tags.set_tag('tag-a', 'rev-2')
555
source.tags.set_tag('tag-missing', 'missing-rev')
556
# Now source has a tag not in its ancestry. Make a branch from it.
557
self.reset_smart_call_log()
558
out, err = self.run_bzr(['branch', self.get_url('source'), 'target'])
559
# This figure represent the amount of work to perform this use case. It
560
# is entirely ok to reduce this number if a test fails due to rpc_count
561
# being too low. If rpc_count increases, more network roundtrips have
562
# become necessary for this use case. Please do not adjust this number
563
# upwards without agreement from bzr's network support maintainers.
564
self.assertLength(10, self.hpss_calls)
565
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
566
self.assertLength(1, self.hpss_connections)
568
def test_branch_to_stacked_from_trivial_branch_streaming_acceptance(self):
569
self.setup_smart_server_with_call_log()
570
t = self.make_branch_and_tree('from')
571
for count in range(9):
572
t.commit(message='commit %d' % count)
573
self.reset_smart_call_log()
574
out, err = self.run_bzr(['branch', '--stacked', self.get_url('from'),
576
# XXX: the number of hpss calls for this case isn't deterministic yet,
577
# so we can't easily assert about the number of calls.
578
#self.assertLength(XXX, self.hpss_calls)
579
# We can assert that none of the calls were readv requests for rix
580
# files, though (demonstrating that at least get_parent_map calls are
581
# not using VFS RPCs).
582
readvs_of_rix_files = [
583
c for c in self.hpss_calls
584
if c.call.method == 'readv' and c.call.args[-1].endswith('.rix')]
585
self.assertLength(1, self.hpss_connections)
586
self.assertLength(0, readvs_of_rix_files)
587
self.expectFailure("branching to stacked requires VFS access",
588
self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
554
591
class TestRemoteBranch(TestCaseWithSFTPServer):
557
594
super(TestRemoteBranch, self).setUp()
558
595
tree = self.make_branch_and_tree('branch')
559
self.build_tree_contents([('branch/file', b'file content\n')])
596
self.build_tree_contents([('branch/file', 'file content\n')])
561
598
tree.commit('file created')