270
272
tree_b.merge_from_branch(tree_a.branch)
271
273
except AttributeError:
272
274
self.fail('tried to join a path when name was None')
276
def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis(self):
277
tree_a = self.make_branch_and_tree('a')
278
self.build_tree(['a/file_1', 'a/file_2'])
279
tree_a.add(['file_1'])
280
tree_a.commit('commit 1')
281
tree_a.add(['file_2'])
282
tree_a.commit('commit 2')
283
tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
284
tree_b.rename_one('file_1', 'renamed')
285
merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
286
progress.DummyProgress())
287
merger.merge_type = _mod_merge.Merge3Merger
289
self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
291
def prepare_cherrypick(self):
292
"""Prepare a pair of trees for cherrypicking tests.
294
Both trees have a file, 'file'.
295
rev1 sets content to 'a'.
298
A full merge of rev2b and rev3b into this_tree would add both 'b' and
299
'c'. A successful cherrypick of rev2b-rev3b into this_tree will add
302
this_tree = self.make_branch_and_tree('this')
303
self.build_tree_contents([('this/file', "a\n")])
304
this_tree.add('file')
305
this_tree.commit('rev1')
306
other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
307
self.build_tree_contents([('other/file', "a\nb\n")])
308
other_tree.commit('rev2b', rev_id='rev2b')
309
self.build_tree_contents([('other/file', "c\na\nb\n")])
310
other_tree.commit('rev3b', rev_id='rev3b')
311
this_tree.lock_write()
312
self.addCleanup(this_tree.unlock)
313
return this_tree, other_tree
315
def test_weave_cherrypick(self):
316
this_tree, other_tree = self.prepare_cherrypick()
317
merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
318
this_tree, 'rev3b', 'rev2b', other_tree.branch)
319
merger.merge_type = _mod_merge.WeaveMerger
321
self.assertFileEqual('c\na\n', 'this/file')
323
def test_weave_cannot_reverse_cherrypick(self):
324
this_tree, other_tree = self.prepare_cherrypick()
325
merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
326
this_tree, 'rev2b', 'rev3b', other_tree.branch)
327
merger.merge_type = _mod_merge.WeaveMerger
328
self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
330
def test_merge3_can_reverse_cherrypick(self):
331
this_tree, other_tree = self.prepare_cherrypick()
332
merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
333
this_tree, 'rev2b', 'rev3b', other_tree.branch)
334
merger.merge_type = _mod_merge.Merge3Merger
338
class TestPlanMerge(TestCaseWithMemoryTransport):
341
TestCaseWithMemoryTransport.setUp(self)
342
self.vf = knit.KnitVersionedFile('root', self.get_transport(),
344
self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
347
def add_version(self, version_id, parents, text):
348
self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
350
def add_uncommitted_version(self, version_id, parents, text):
351
self.plan_merge_vf.add_lines(version_id, parents,
352
[c+'\n' for c in text])
354
def setup_plan_merge(self):
355
self.add_version('A', [], 'abc')
356
self.add_version('B', ['A'], 'acehg')
357
self.add_version('C', ['A'], 'fabg')
358
return _PlanMerge('B', 'C', self.plan_merge_vf)
360
def setup_plan_merge_uncommitted(self):
361
self.add_version('A', [], 'abc')
362
self.add_uncommitted_version('B:', ['A'], 'acehg')
363
self.add_uncommitted_version('C:', ['A'], 'fabg')
364
return _PlanMerge('B:', 'C:', self.plan_merge_vf)
366
def test_unique_lines(self):
367
plan = self.setup_plan_merge()
368
self.assertEqual(plan._unique_lines(
369
plan._get_matching_blocks('B', 'C')),
372
def test_find_new(self):
373
plan = self.setup_plan_merge()
374
self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
375
self.assertEqual(set([0, 3]), plan._find_new('C'))
377
def test_find_new2(self):
378
self.add_version('A', [], 'abc')
379
self.add_version('B', ['A'], 'abcde')
380
self.add_version('C', ['A'], 'abcefg')
381
self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
382
my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
383
self.assertEqual(set([5, 6]), my_plan._find_new('D'))
384
self.assertEqual(set(), my_plan._find_new('A'))
386
def test_find_new_no_ancestors(self):
387
self.add_version('A', [], 'abc')
388
self.add_version('B', [], 'xyz')
389
my_plan = _PlanMerge('A', 'B', self.vf)
390
self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
392
def test_plan_merge(self):
393
self.setup_plan_merge()
394
plan = self.plan_merge_vf.plan_merge('B', 'C')
397
('unchanged', 'a\n'),
402
('unchanged', 'g\n')],
405
def test_plan_merge_uncommitted_files(self):
406
self.setup_plan_merge_uncommitted()
407
plan = self.plan_merge_vf.plan_merge('B:', 'C:')
410
('unchanged', 'a\n'),
415
('unchanged', 'g\n')],
418
def test_subtract_plans(self):
420
('unchanged', 'a\n'),
429
('unchanged', 'a\n'),
438
('unchanged', 'a\n'),
442
('unchanged', 'f\n'),
445
self.assertEqual(subtracted_plan,
446
list(_PlanMerge._subtract_plans(old_plan, new_plan)))
448
def setup_merge_with_base(self):
449
self.add_version('COMMON', [], 'abc')
450
self.add_version('THIS', ['COMMON'], 'abcd')
451
self.add_version('BASE', ['COMMON'], 'eabc')
452
self.add_version('OTHER', ['BASE'], 'eafb')
454
def test_plan_merge_with_base(self):
455
self.setup_merge_with_base()
456
plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
457
self.assertEqual([('unchanged', 'a\n'),
459
('unchanged', 'b\n'),
464
def test_plan_lca_merge(self):
465
self.setup_plan_merge()
466
plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
469
('unchanged', 'a\n'),
474
('unchanged', 'g\n')],
477
def test_plan_lca_merge_uncommitted_files(self):
478
self.setup_plan_merge_uncommitted()
479
plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
482
('unchanged', 'a\n'),
487
('unchanged', 'g\n')],
490
def test_plan_lca_merge_with_base(self):
491
self.setup_merge_with_base()
492
plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
493
self.assertEqual([('unchanged', 'a\n'),
495
('unchanged', 'b\n'),
500
def test_plan_lca_merge_with_criss_cross(self):
501
self.add_version('ROOT', [], 'abc')
502
# each side makes a change
503
self.add_version('REV1', ['ROOT'], 'abcd')
504
self.add_version('REV2', ['ROOT'], 'abce')
505
# both sides merge, discarding others' changes
506
self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
507
self.add_version('LCA2', ['REV1', 'REV2'], 'abce')
508
plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
509
self.assertEqual([('unchanged', 'a\n'),
510
('unchanged', 'b\n'),
511
('unchanged', 'c\n'),
512
('conflicted-a', 'd\n'),
513
('conflicted-b', 'e\n'),