8
from bzrlib.selftest import TestCaseInTempDir, TestCase
6
from bzrlib.tests import TestCaseInTempDir, TestCase
9
7
from bzrlib.branch import ScratchBranch, Branch
10
8
from bzrlib.errors import (NotBranchError, NotVersionedError,
11
9
WorkingTreeNotRevision, BzrCommandError)
12
10
from bzrlib.inventory import RootEntry
13
11
import bzrlib.inventory as inventory
14
from bzrlib.osutils import file_kind, rename, sha_file
12
from bzrlib.osutils import file_kind, rename, sha_file, pathjoin, mkdtemp
15
13
from bzrlib import changeset
16
14
from bzrlib.merge_core import (ApplyMerge3, make_merge_changeset,
17
15
BackupBeforeChange, ExecFlagMerge, WeaveMerge)
140
138
def get_file_sha1(self, file_id):
141
139
return sha_file(file(self.full_path(file_id), "rb"))
143
142
class MergeBuilder(object):
144
143
def __init__(self):
145
self.dir = tempfile.mkdtemp(prefix="BaZing")
146
self.base = MergeTree(os.path.join(self.dir, "base"))
147
self.this = MergeTree(os.path.join(self.dir, "this"))
148
self.other = MergeTree(os.path.join(self.dir, "other"))
144
self.dir = mkdtemp(prefix="BaZing")
145
self.base = MergeTree(pathjoin(self.dir, "base"))
146
self.this = MergeTree(pathjoin(self.dir, "this"))
147
self.other = MergeTree(pathjoin(self.dir, "other"))
150
149
self.cset = changeset.Changeset()
151
150
self.cset.add_entry(changeset.ChangesetEntry("0",
152
151
changeset.NULL_ID, "./."))
153
153
def get_cset_path(self, parent, name):
155
155
assert (parent is None)
157
return os.path.join(self.cset.entries[parent].path, name)
157
return pathjoin(self.cset.entries[parent].path, name)
159
159
def add_file(self, id, parent, name, contents, mode):
160
160
self.base.add_file(id, parent, name, contents, mode)
366
366
builder.add_file("3", "0", "name5", "hello3", 0755)
367
367
builder.change_name("3", this="name6")
368
368
cset = builder.merge_changeset(ApplyMerge3)
369
self.assert_(cset.entries["2"].is_boring())
370
self.assert_(cset.entries["1"].name == "name1")
371
self.assert_(cset.entries["1"].new_name == "name2")
372
self.assert_(cset.entries["3"].is_boring())
369
self.failUnless(cset.entries["2"].is_boring())
370
self.assertEqual(cset.entries["1"].name, "name1")
371
self.assertEqual(cset.entries["1"].new_name, "name2")
372
self.failUnless(cset.entries["3"].is_boring())
373
373
for tree in (builder.this, builder.other, builder.base):
374
self.assert_(tree.dir != builder.dir and
375
tree.dir.startswith(builder.dir))
374
self.assertNotEqual(tree.dir, builder.dir)
375
self.assertStartsWith(tree.dir, builder.dir)
376
376
for path in tree.inventory_dict.itervalues():
377
377
fullpath = tree.abs_path(path)
378
self.assert_(fullpath.startswith(tree.dir))
379
self.assert_(not path.startswith(tree.dir))
380
self.assert_(os.path.exists(fullpath))
378
self.assertStartsWith(fullpath, tree.dir)
379
self.failIf(path.startswith(tree.dir))
380
self.failUnless(os.path.lexists(fullpath))
381
381
builder.apply_changeset(cset)
382
382
builder.cleanup()
383
383
builder = MergeBuilder()
537
537
def test_trivial_star_merge(self):
538
538
"""Test that merges in a star shape Just Work."""
539
from bzrlib.add import smart_add_tree, add_reporter_null
539
from bzrlib.add import smart_add_tree
540
540
from bzrlib.clone import copy_branch
541
541
from bzrlib.merge import merge
542
542
# John starts a branch
543
543
self.build_tree(("original/", "original/file1", "original/file2"))
544
544
branch = Branch.initialize("original")
545
545
tree = WorkingTree('original', branch)
546
smart_add_tree(tree, ["original"], True, add_reporter_null)
546
smart_add_tree(tree, ["original"])
547
547
tree.commit("start branch.", verbose=False)
548
548
# Mary branches it.
549
549
self.build_tree(("mary/",))
634
634
self.assert_(os.path.lexists('a/file.moved'))
635
635
self.assertEqual(a.working_tree().pending_merges(), [b.last_revision()])
637
def test_merge_deleted_conflicts(self):
639
a = Branch.initialize('a')
640
file('a/file', 'wb').write('contents\n')
641
a.working_tree().add('file')
642
a.working_tree().commit('a_revision', allow_pointless=False)
644
self.run_bzr('branch', 'a', 'b')
647
a.working_tree().commit('removed file', allow_pointless=False)
648
file('b/file', 'wb').write('changed contents\n')
650
b.working_tree().commit('changed file', allow_pointless=False)
651
merge(['a', -1], ['a', 1], this_dir='b')
652
self.failIf(os.path.lexists('b/file'))
637
654
def test_merge_metadata_vs_deletion(self):
638
655
"""Conflict deletion vs metadata change"""
653
670
b_wt.commit('exec a')
654
671
merge(['b', -1], ['b', 0], this_dir='a')
655
672
self.assert_(os.path.exists('a/file'))
674
def test_merge_swapping_renames(self):
676
a = Branch.initialize('a')
677
file('a/un','wb').write('UN')
678
file('a/deux','wb').write('DEUX')
679
a_wt = a.working_tree()
685
b_wt = b.working_tree()
686
b_wt.rename_one('un','tmp')
687
b_wt.rename_one('deux','un')
688
b_wt.rename_one('tmp','deux')
690
merge(['b', -1],['b', 1],this_dir='a')
691
self.assert_(os.path.exists('a/un'))
692
self.assert_(os.path.exists('a/deux'))
693
self.assertFalse(os.path.exists('a/tmp'))
694
self.assertEqual(file('a/un').read(),'DEUX')
695
self.assertEqual(file('a/deux').read(),'UN')
697
def test_merge_delete_and_add_same(self):
699
a = Branch.initialize('a')
700
file('a/file', 'wb').write('THIS')
701
a_wt = a.working_tree()
706
b_wt = b.working_tree()
709
file('b/file', 'wb').write('THAT')
712
merge(['b', -1],['b', 1],this_dir='a')
713
self.assert_(os.path.exists('a/file'))
714
self.assertEqual(file('a/file').read(),'THAT')
716
def test_merge_rename_before_create(self):
717
"""rename before create
719
This case requires that you must not do creates
720
before move-into-place:
731
a = Branch.initialize('a')
732
file('a/foo', 'wb').write('A/FOO')
733
a_wt = a.working_tree()
735
a_wt.commit('added foo')
738
b_wt = b.working_tree()
739
b_wt.rename_one('foo', 'bar')
740
file('b/foo', 'wb').write('B/FOO')
742
b_wt.commit('moved foo to bar, added new foo')
743
merge(['b', -1],['b', 1],this_dir='a')
745
def test_merge_create_before_rename(self):
746
"""create before rename, target parents before children
748
This case requires that you must not do move-into-place
749
before creates, and that you must not do children after
761
a = Branch.initialize('a')
762
file('a/foo', 'wb').write('A/FOO')
763
a_wt = a.working_tree()
765
a_wt.commit('added foo')
768
b_wt = b.working_tree()
771
b_wt.rename_one('foo', 'bar/foo')
772
b_wt.commit('created bar dir, moved foo into bar')
773
merge(['b', -1],['b', 1],this_dir='a')
775
def test_merge_rename_to_temp_before_delete(self):
776
"""rename to temp before delete, source children before parents
778
This case requires that you must not do deletes before
779
move-out-of-the-way, and that you must not do children
791
a = Branch.initialize('a')
793
file('a/foo/bar', 'wb').write('A/FOO/BAR')
794
a_wt = a.working_tree()
797
a_wt.commit('added foo/bar')
800
b_wt = b.working_tree()
801
b_wt.rename_one('foo/bar', 'bar')
804
b_wt.commit('moved foo/bar to bar, deleted foo')
805
merge(['b', -1],['b', 1],this_dir='a')
807
def test_merge_delete_before_rename_to_temp(self):
808
"""delete before rename to temp
810
This case requires that you must not do
811
move-out-of-the-way before deletes:
823
a = Branch.initialize('a')
824
file('a/foo', 'wb').write('A/FOO')
825
file('a/bar', 'wb').write('A/BAR')
826
a_wt = a.working_tree()
829
a_wt.commit('added foo and bar')
832
b_wt = b.working_tree()
835
b_wt.rename_one('bar', 'foo')
836
b_wt.commit('deleted foo, renamed bar to foo')
837
merge(['b', -1],['b', 1],this_dir='a')