~bzr-pqm/bzr/bzr.dev

2255.2.217 by Martin Pool
docs
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
17
import os
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
18
from StringIO import StringIO
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
19
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
20
from bzrlib import (
21
    conflicts,
22
    merge as _mod_merge,
23
    option,
24
    )
974.1.56 by aaron.bentley at utoronto
Added merge test
25
from bzrlib.branch import Branch
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
26
from bzrlib.builtins import _merge_helper
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
27
from bzrlib.conflicts import ConflictList, TextConflict
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
28
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
29
from bzrlib.merge import transform_tree, merge_inner
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
30
from bzrlib.osutils import pathjoin, file_kind
1534.4.28 by Robert Collins
first cut at merge from integration.
31
from bzrlib.revision import common_ancestor
32
from bzrlib.tests import TestCaseWithTransport
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
33
from bzrlib.trace import (enable_test_log, disable_test_log)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
34
from bzrlib.workingtree import WorkingTree
35
36
37
class TestMerge(TestCaseWithTransport):
974.1.56 by aaron.bentley at utoronto
Added merge test
38
    """Test appending more than one revision"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
39
974.1.56 by aaron.bentley at utoronto
Added merge test
40
    def test_pending(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
41
        wt = self.make_branch_and_tree('.')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
42
        rev_a = wt.commit("lala!")
43
        self.assertEqual([rev_a], wt.get_parent_ids())
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
44
        _merge_helper([u'.', -1], [None, None])
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
45
        self.assertEqual([rev_a], wt.get_parent_ids())
974.1.80 by Aaron Bentley
Improved merge error handling and testing
46
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
47
    def test_undo(self):
48
        wt = self.make_branch_and_tree('.')
49
        wt.commit("lala!")
50
        wt.commit("haha!")
51
        wt.commit("blabla!")
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
52
        _merge_helper([u'.', 2], [u'.', 1])
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
53
974.1.80 by Aaron Bentley
Improved merge error handling and testing
54
    def test_nocommits(self):
55
        self.test_pending()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
56
        wt2 = self.make_branch_and_tree('branch2')
2598.5.6 by Aaron Bentley
Fix trailing whitespace
57
        self.assertRaises(NoCommits, _merge_helper, ['branch2', -1],
974.1.80 by Aaron Bentley
Improved merge error handling and testing
58
                          [None, None])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
59
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
60
61
    def test_unrelated(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
62
        wt2 = self.test_nocommits()
63
        wt2.commit("blah")
2598.5.6 by Aaron Bentley
Fix trailing whitespace
64
        self.assertRaises(UnrelatedBranches, _merge_helper, ['branch2', -1],
974.1.80 by Aaron Bentley
Improved merge error handling and testing
65
                          [None, None])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
66
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
67
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
68
    def test_merge_one_file(self):
69
        """Do a partial merge of a tree which should not affect tree parents."""
1645.1.1 by Aaron Bentley
Implement single-file merge
70
        wt1 = self.make_branch_and_tree('branch1')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
71
        tip = wt1.commit('empty commit')
1645.1.1 by Aaron Bentley
Implement single-file merge
72
        wt2 = self.make_branch_and_tree('branch2')
73
        wt2.pull(wt1.branch)
74
        file('branch1/foo', 'wb').write('foo')
75
        file('branch1/bar', 'wb').write('bar')
76
        wt1.add('foo')
77
        wt1.add('bar')
78
        wt1.commit('add foobar')
79
        os.chdir('branch2')
2530.3.1 by Martin Pool
Cleanup old variations on run_bzr in the test suite
80
        self.run_bzr('merge ../branch1/baz', retcode=3)
81
        self.run_bzr('merge ../branch1/foo')
1645.1.1 by Aaron Bentley
Implement single-file merge
82
        self.failUnlessExists('foo')
83
        self.failIfExists('bar')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
84
        wt2 = WorkingTree.open('.') # opens branch2
85
        self.assertEqual([tip], wt2.get_parent_ids())
1908.6.9 by Robert Collins
Fix status to not use pending_merges.
86
        
974.1.88 by Aaron Bentley
Set a pending_merge if the merge base is forced to revno 0
87
    def test_pending_with_null(self):
1551.8.25 by Aaron Bentley
Fix deprecated use of pending_merges
88
        """When base is forced to revno 0, parent_ids are set"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
89
        wt2 = self.test_unrelated()
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
90
        wt1 = WorkingTree.open('.')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
91
        br1 = wt1.branch
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
92
        br1.fetch(wt2.branch)
1390 by Robert Collins
pair programming worx... merge integration and weave
93
        # merge all of branch 2 into branch 1 even though they 
94
        # are not related.
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
95
        self.assertRaises(BzrCommandError, _merge_helper, ['branch2', -1],
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
96
                          ['branch2', 0], reprocess=True, show_base=True)
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
97
        _merge_helper(['branch2', -1], ['branch2', 0], reprocess=True)
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
98
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
99
            wt1.get_parent_ids())
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
100
        return (wt1, wt2.branch)
974.1.89 by Aaron Bentley
Fixed merging with multiple roots, by using null as graph root.
101
102
    def test_two_roots(self):
103
        """Merge base is sane when two unrelated branches are merged"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
104
        wt1, br2 = self.test_pending_with_null()
105
        wt1.commit("blah")
106
        last = wt1.branch.last_revision()
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
107
        self.assertEqual(common_ancestor(last, last, wt1.branch.repository), last)
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
108
109
    def test_create_rename(self):
110
        """Rename an inventory entry while creating the file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
111
        tree =self.make_branch_and_tree('.')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
112
        file('name1', 'wb').write('Hello')
113
        tree.add('name1')
114
        tree.commit(message="hello")
115
        tree.rename_one('name1', 'name2')
116
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
117
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
118
119
    def test_layered_rename(self):
120
        """Rename both child and parent at same time"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
121
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
122
        os.mkdir('dirname1')
123
        tree.add('dirname1')
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
124
        filename = pathjoin('dirname1', 'name1')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
125
        file(filename, 'wb').write('Hello')
126
        tree.add(filename)
127
        tree.commit(message="hello")
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
128
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
129
        tree.rename_one(filename, filename2)
130
        tree.rename_one('dirname1', 'dirname2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
131
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
132
133
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
134
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
135
        tree_a =self.make_branch_and_tree('a')
136
        tree_a.commit(message="hello")
137
        dir_b = tree_a.bzrdir.sprout('b')
138
        tree_b = dir_b.open_workingtree()
139
        tree_a.commit(message="hello again")
140
        log = StringIO()
141
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
142
                    this_tree=tree_b, ignore_zero=True)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
143
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
144
        self.failUnless('All changes applied successfully.\n' not in log)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
145
        tree_b.revert([])
146
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
147
                    this_tree=tree_b, ignore_zero=False)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
148
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
149
        self.failUnless('All changes applied successfully.\n' in log)
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
150
151
    def test_merge_inner_conflicts(self):
152
        tree_a = self.make_branch_and_tree('a')
153
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
154
        merge_inner(tree_a.branch, tree_a, tree_a, this_tree=tree_a)
1551.7.13 by Aaron Bentley
Switched from actual, expected to expected, actual, for John.
155
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
156
157
    def test_rmdir_conflict(self):
158
        tree_a = self.make_branch_and_tree('a')
159
        self.build_tree(['a/b/'])
160
        tree_a.add('b', 'b-id')
161
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
162
        # basis_tree() is only guaranteed to be valid as long as it is actually
163
        # the basis tree. This mutates the tree after grabbing basis, so go to
164
        # the repository.
165
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
166
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
167
        self.build_tree(['a/b/c'])
168
        tree_a.add('b/c')
169
        tree_a.commit('added c')
170
        os.rmdir('z/b')
171
        tree_z.commit('removed b')
172
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
173
        self.assertEqual([
174
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
175
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
176
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
177
        merge_inner(tree_a.branch, tree_z.basis_tree(), base_tree,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
178
                    this_tree=tree_a)
179
        self.assertEqual([
180
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
181
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
182
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
183
2100.3.29 by Aaron Bentley
Get merge working initially
184
    def test_nested_merge(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
185
        tree = self.make_branch_and_tree('tree',
186
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
187
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
188
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
189
        sub_tree.set_root_id('sub-tree-root')
190
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
191
        sub_tree.add('file')
192
        sub_tree.commit('foo')
193
        tree.add_reference(sub_tree)
194
        tree.commit('set text to 1')
195
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
196
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
197
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
198
        # and merge the changes from the diverged subtree into the containing
199
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
200
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
201
        tree.merge_from_branch(tree2.branch)
202
        self.assertFileEqual('text2', 'tree/sub-tree/file')
203
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
204
    def test_merge_with_missing(self):
205
        tree_a = self.make_branch_and_tree('tree_a')
206
        self.build_tree_contents([('tree_a/file', 'content_1')])
207
        tree_a.add('file')
208
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
209
        # basis_tree() is only guaranteed to be valid as long as it is actually
210
        # the basis tree. This mutates the tree after grabbing basis, so go to
211
        # the repository.
212
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
213
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
214
        self.build_tree_contents([('tree_a/file', 'content_2')])
215
        tree_a.commit('commit other')
216
        other_tree = tree_a.basis_tree()
217
        os.unlink('tree_b/file')
218
        merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b)
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
219
220
    def test_merge_kind_change(self):
221
        tree_a = self.make_branch_and_tree('tree_a')
222
        self.build_tree_contents([('tree_a/file', 'content_1')])
223
        tree_a.add('file', 'file-id')
224
        tree_a.commit('added file')
225
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
226
        os.unlink('tree_a/file')
227
        self.build_tree(['tree_a/file/'])
228
        tree_a.commit('changed file to directory')
229
        tree_b.merge_from_branch(tree_a.branch)
230
        self.assertEqual('directory', file_kind('tree_b/file'))
231
        tree_b.revert([])
232
        self.assertEqual('file', file_kind('tree_b/file'))
233
        self.build_tree_contents([('tree_b/file', 'content_2')])
234
        tree_b.commit('content change')
235
        tree_b.merge_from_branch(tree_a.branch)
236
        self.assertEqual(tree_b.conflicts(),
237
                         [conflicts.ContentsConflict('file',
238
                          file_id='file-id')])
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
239
    
240
    def test_merge_type_registry(self):
241
        merge_type_option = option.Option.OPTIONS['merge-type']
242
        self.assertFalse('merge4' in [x[0] for x in 
243
                        merge_type_option.iter_switches()])
244
        registry = _mod_merge.get_merge_type_registry()
245
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
246
                               'time-travelling merge')
247
        self.assertTrue('merge4' in [x[0] for x in 
248
                        merge_type_option.iter_switches()])
249
        registry.remove('merge4')
250
        self.assertFalse('merge4' in [x[0] for x in 
251
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
252
1551.16.3 by Aaron Bentley
Rename test case
253
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
254
        tree_a = self.make_branch_and_tree('A')
255
        tree_a.lock_write()
256
        self.addCleanup(tree_a.unlock)
257
        self.build_tree(['A/a'])
258
        tree_a.add('a')
259
        tree_a.commit('1', rev_id='rev-1')
260
        tree_a.flush()
261
        tree_a.rename_one('a', 'b')
262
        tree_a.commit('2')
263
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
264
        tree_b = bzrdir_b.open_workingtree()
265
        tree_b.lock_write()
266
        self.addCleanup(tree_b.unlock)
267
        os.unlink('B/a')
268
        tree_b.commit('3')
269
        try:
270
            tree_b.merge_from_branch(tree_a.branch)
271
        except AttributeError:
272
            self.fail('tried to join a path when name was None')
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
273
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
274
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis(self):
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
275
        tree_a = self.make_branch_and_tree('a')
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
276
        self.build_tree(['a/file_1', 'a/file_2'])
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
277
        tree_a.add(['file_1'])
278
        tree_a.commit('commit 1')
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
279
        tree_a.add(['file_2'])
280
        tree_a.commit('commit 2')
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
281
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
282
        tree_b.rename_one('file_1', 'renamed')
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
283
        _merge_helper(['b', None], ['b', -1], this_dir='a')
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
284
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])