13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22
from bzrlib import (
28
from bzrlib.conflicts import (
27
from bzrlib.conflicts import ContentsConflict, TextConflict, PathConflict
28
from bzrlib import errors
29
from bzrlib.errors import (NotBranchError, NotVersionedError,
30
WorkingTreeNotRevision, BzrCommandError, NoDiff3)
31
from bzrlib import inventory
33
32
from bzrlib.merge import (
39
from bzrlib.osutils import getcwd, pathjoin
38
from bzrlib.osutils import (file_kind, getcwd, pathjoin, rename,
41
from bzrlib import progress
40
42
from bzrlib.transform import TreeTransform
41
from bzrlib.tests import TestCaseWithTransport, TestSkipped
43
from bzrlib.tests import TestCaseWithTransport, TestCase, TestSkipped
42
44
from bzrlib.workingtree import WorkingTree
45
47
class MergeBuilder(object):
47
48
def __init__(self, dir=None):
48
49
self.dir = osutils.mkdtemp(prefix="merge-test", dir=dir)
49
50
self.tree_root = generate_ids.gen_root_id()
51
52
path = pathjoin(self.dir, name)
53
wt = controldir.ControlDir.create_standalone_workingtree(path)
54
wt = bzrlib.bzrdir.BzrDir.create_standalone_workingtree(path)
54
55
# the tests perform pulls, so need a branch that is writeable.
56
57
wt.set_root_id(self.tree_root)
101
92
wt.commit('branch commit')
103
if wt.branch.last_revision_info()[0] != 2:
94
if len(wt.branch.revision_history()) != 2:
104
95
raise AssertionError()
105
96
self.this.branch.fetch(self.other.branch)
106
97
other_basis = self.other.branch.basis_tree()
107
if this_revision_tree:
108
self.this.commit('message')
109
this_tree = self.this.basis_tree()
111
this_tree = self.this
112
merger = merge_type(this_tree, self.this, self.base, other_basis,
113
interesting_ids=interesting_ids, do_merge=False,
114
this_branch=self.this.branch, **kwargs)
98
merger = merge_type(self.this, self.this, self.base, other_basis,
99
interesting_ids=interesting_ids, **kwargs)
100
return merger.cooked_conflicts
117
102
def list_transforms(self):
118
103
return [self.this_tt, self.base_tt, self.other_tt]
120
105
def selected_transforms(self, this, base, other):
121
pairs = [(this, self.this_tt), (base, self.base_tt),
106
pairs = [(this, self.this_tt), (base, self.base_tt),
122
107
(other, self.other_tt)]
123
108
return [(v, tt) for (v, tt) in pairs if v is not None]
135
120
tt.cancel_versioning(trans_id)
136
121
tt.set_executability(None, trans_id)
138
def add_dir(self, file_id, parent, name, this=True, base=True, other=True):
139
for option, tt in self.selected_transforms(this, base, other):
141
parent_id = tt.trans_id_file_id(parent)
142
tt.new_directory(name, parent_id, file_id)
123
def add_dir(self, file_id, parent, name):
124
for tt in self.list_transforms():
125
parent_id = tt.trans_id_file_id(parent)
126
tt.new_directory(name, parent_id, file_id)
144
128
def change_name(self, id, base=None, this=None, other=None):
145
for val, tt in ((base, self.base_tt), (this, self.this_tt),
129
for val, tt in ((base, self.base_tt), (this, self.this_tt),
146
130
(other, self.other_tt)):
482
465
tree.merge_from_branch(mary_tree.branch)
483
466
self.assertEqual("John\n", open("original/file1", "rt").read())
484
467
self.assertEqual("Mary\n", open("original/file2", "rt").read())
486
469
def test_conflicts(self):
487
471
wta = self.make_branch_and_tree('a')
488
self.build_tree_contents([('a/file', 'contents\n')])
473
file('a/file', 'wb').write('contents\n')
490
475
wta.commit('base revision', allow_pointless=False)
491
d_b = wta.branch.bzrdir.clone('b')
492
self.build_tree_contents([('a/file', 'other contents\n')])
476
d_b = a.bzrdir.clone('b')
477
b = d_b.open_branch()
478
file('a/file', 'wb').write('other contents\n')
493
479
wta.commit('other revision', allow_pointless=False)
494
self.build_tree_contents([('b/file', 'this contents contents\n')])
480
file('b/file', 'wb').write('this contents contents\n')
495
481
wtb = d_b.open_workingtree()
496
482
wtb.commit('this revision', allow_pointless=False)
497
483
self.assertEqual(1, wtb.merge_from_branch(wta.branch))
498
self.assertPathExists('b/file.THIS')
499
self.assertPathExists('b/file.BASE')
500
self.assertPathExists('b/file.OTHER')
484
self.assert_(os.path.lexists('b/file.THIS'))
485
self.assert_(os.path.lexists('b/file.BASE'))
486
self.assert_(os.path.lexists('b/file.OTHER'))
502
488
self.assertEqual(1, wtb.merge_from_branch(wta.branch,
503
489
merge_type=WeaveMerger))
504
self.assertPathExists('b/file')
505
self.assertPathExists('b/file.THIS')
506
self.assertPathExists('b/file.BASE')
507
self.assertPathExists('b/file.OTHER')
509
def test_weave_conflicts_not_in_base(self):
510
builder = self.make_branch_builder('source')
511
builder.start_series()
513
# A base revision (before criss-cross)
515
# B C B does nothing, C adds 'foo'
517
# D E D and E modify foo in incompatible ways
519
# Merging will conflict, with C as a clean base text. However, the
520
# current code uses A as the global base and 'foo' doesn't exist there.
521
# It isn't trivial to create foo.BASE because it tries to look up
522
# attributes like 'executable' in A.
523
builder.build_snapshot('A-id', None, [
524
('add', ('', 'TREE_ROOT', 'directory', None))])
525
builder.build_snapshot('B-id', ['A-id'], [])
526
builder.build_snapshot('C-id', ['A-id'], [
527
('add', ('foo', 'foo-id', 'file', 'orig\ncontents\n'))])
528
builder.build_snapshot('D-id', ['B-id', 'C-id'], [
529
('add', ('foo', 'foo-id', 'file', 'orig\ncontents\nand D\n'))])
530
builder.build_snapshot('E-id', ['C-id', 'B-id'], [
531
('modify', ('foo-id', 'orig\ncontents\nand E\n'))])
532
builder.finish_series()
533
tree = builder.get_branch().create_checkout('tree', lightweight=True)
534
self.assertEqual(1, tree.merge_from_branch(tree.branch,
536
merge_type=WeaveMerger))
537
self.assertPathExists('tree/foo.THIS')
538
self.assertPathExists('tree/foo.OTHER')
539
self.expectFailure('fail to create .BASE in some criss-cross merges',
540
self.assertPathExists, 'tree/foo.BASE')
541
self.assertPathExists('tree/foo.BASE')
490
self.assert_(os.path.lexists('b/file'))
491
self.assert_(os.path.lexists('b/file.THIS'))
492
self.assert_(not os.path.lexists('b/file.BASE'))
493
self.assert_(os.path.lexists('b/file.OTHER'))
543
495
def test_merge_unrelated(self):
544
496
"""Sucessfully merges unrelated branches with no common names"""
545
497
wta = self.make_branch_and_tree('a')
547
with file('a/a_file', 'wb') as f: f.write('contents\n')
499
file('a/a_file', 'wb').write('contents\n')
548
500
wta.add('a_file')
549
501
wta.commit('a_revision', allow_pointless=False)
550
502
wtb = self.make_branch_and_tree('b')
552
with file('b/b_file', 'wb') as f: f.write('contents\n')
504
file('b/b_file', 'wb').write('contents\n')
553
505
wtb.add('b_file')
554
506
b_rev = wtb.commit('b_revision', allow_pointless=False)
555
507
wta.merge_from_branch(wtb.branch, b_rev, 'null:')
556
self.assertTrue(os.path.lexists('a/b_file'))
508
self.assert_(os.path.lexists('a/b_file'))
557
509
self.assertEqual([b_rev], wta.get_parent_ids()[1:])
559
511
def test_merge_unrelated_conflicting(self):
560
512
"""Sucessfully merges unrelated branches with common names"""
561
513
wta = self.make_branch_and_tree('a')
563
with file('a/file', 'wb') as f: f.write('contents\n')
515
file('a/file', 'wb').write('contents\n')
565
517
wta.commit('a_revision', allow_pointless=False)
566
518
wtb = self.make_branch_and_tree('b')
568
with file('b/file', 'wb') as f: f.write('contents\n')
520
file('b/file', 'wb').write('contents\n')
570
522
b_rev = wtb.commit('b_revision', allow_pointless=False)
571
523
wta.merge_from_branch(wtb.branch, b_rev, 'null:')
572
self.assertTrue(os.path.lexists('a/file'))
573
self.assertTrue(os.path.lexists('a/file.moved'))
524
self.assert_(os.path.lexists('a/file'))
525
self.assert_(os.path.lexists('a/file.moved'))
574
526
self.assertEqual([b_rev], wta.get_parent_ids()[1:])
576
528
def test_merge_deleted_conflicts(self):
577
529
wta = self.make_branch_and_tree('a')
578
with file('a/file', 'wb') as f: f.write('contents\n')
530
file('a/file', 'wb').write('contents\n')
580
532
wta.commit('a_revision', allow_pointless=False)
581
533
self.run_bzr('branch a b')
582
534
os.remove('a/file')
583
535
wta.commit('removed file', allow_pointless=False)
584
with file('b/file', 'wb') as f: f.write('changed contents\n')
536
file('b/file', 'wb').write('changed contents\n')
585
537
wtb = WorkingTree.open('b')
586
538
wtb.commit('changed file', allow_pointless=False)
587
539
wtb.merge_from_branch(wta.branch, wta.branch.last_revision(),
588
540
wta.branch.get_rev_id(1))
589
self.assertFalse(os.path.lexists('b/file'))
541
self.failIf(os.path.lexists('b/file'))
591
543
def test_merge_metadata_vs_deletion(self):
592
544
"""Conflict deletion vs metadata change"""
593
545
a_wt = self.make_branch_and_tree('a')
594
with file('a/file', 'wb') as f: f.write('contents\n')
546
file('a/file', 'wb').write('contents\n')
596
548
a_wt.commit('r0')
597
549
self.run_bzr('branch a b')
620
572
b_wt.commit('r1', rev_id='r1')
621
573
self.assertEqual(0, a_wt.merge_from_branch(b_wt.branch,
622
574
b_wt.branch.last_revision(), b_wt.branch.get_rev_id(1)))
623
self.assertPathExists('a/un')
624
self.assertTrue('a/deux')
575
self.failUnlessExists('a/un')
576
self.failUnless('a/deux')
625
577
self.assertFalse(os.path.exists('a/tmp'))
626
578
self.assertEqual(file('a/un').read(),'DEUX')
627
579
self.assertEqual(file('a/deux').read(),'UN')
629
581
def test_merge_delete_and_add_same(self):
630
582
a_wt = self.make_branch_and_tree('a')
631
with file('a/file', 'wb') as f: f.write('THIS')
583
file('a/file', 'wb').write('THIS')
633
585
a_wt.commit('r0')
634
586
self.run_bzr('branch a b')
635
587
b_wt = WorkingTree.open('b')
636
588
os.remove('b/file')
637
589
b_wt.commit('r1')
638
with file('b/file', 'wb') as f: f.write('THAT')
590
file('b/file', 'wb').write('THAT')
640
592
b_wt.commit('r2')
641
593
a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
642
594
b_wt.branch.get_rev_id(1))
643
self.assertTrue(os.path.exists('a/file'))
595
self.assert_(os.path.exists('a/file'))
644
596
self.assertEqual(file('a/file').read(),'THAT')
646
598
def test_merge_rename_before_create(self):
647
599
"""rename before create
649
601
This case requires that you must not do creates
650
602
before move-into-place:
773
725
def test_from_revision_ids(self):
774
726
this, other = self.set_up_trees()
775
727
self.assertRaises(errors.NoSuchRevision, Merger.from_revision_ids,
728
progress.DummyProgress(), this, 'rev2b')
777
729
this.lock_write()
778
730
self.addCleanup(this.unlock)
779
merger = Merger.from_revision_ids(None, this,
731
merger = Merger.from_revision_ids(progress.DummyProgress(), this,
780
732
'rev2b', other_branch=other.branch)
781
733
self.assertEqual('rev2b', merger.other_rev_id)
782
734
self.assertEqual('rev1', merger.base_rev_id)
783
merger = Merger.from_revision_ids(None, this,
735
merger = Merger.from_revision_ids(progress.DummyProgress(), this,
784
736
'rev2b', 'rev2a', other_branch=other.branch)
785
737
self.assertEqual('rev2a', merger.base_rev_id)
787
739
def test_from_uncommitted(self):
788
740
this, other = self.set_up_trees()
789
merger = Merger.from_uncommitted(this, other, None)
741
merger = Merger.from_uncommitted(this, other, progress.DummyProgress())
790
742
self.assertIs(other, merger.other_tree)
791
743
self.assertIs(None, merger.other_rev_id)
792
744
self.assertEqual('rev2b', merger.base_rev_id)