/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
22
    errors,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
23
    knit,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
24
    merge as _mod_merge,
25
    option,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
26
    progress,
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
27
    transform,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
28
    versionedfile,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
29
    )
974.1.56 by aaron.bentley at utoronto
Added merge test
30
from bzrlib.branch import Branch
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
31
from bzrlib.conflicts import ConflictList, TextConflict
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
32
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
33
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
34
from bzrlib.osutils import pathjoin, file_kind
1534.4.28 by Robert Collins
first cut at merge from integration.
35
from bzrlib.revision import common_ancestor
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
36
from bzrlib.tests import TestCaseWithTransport, TestCaseWithMemoryTransport
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
37
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.
38
from bzrlib.workingtree import WorkingTree
39
40
41
class TestMerge(TestCaseWithTransport):
974.1.56 by aaron.bentley at utoronto
Added merge test
42
    """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.
43
974.1.56 by aaron.bentley at utoronto
Added merge test
44
    def test_pending(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
45
        wt = self.make_branch_and_tree('.')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
46
        rev_a = wt.commit("lala!")
47
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
48
        self.assertRaises(errors.PointlessMerge, wt.merge_from_branch,
49
                          wt.branch)
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
50
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
51
        return wt
974.1.80 by Aaron Bentley
Improved merge error handling and testing
52
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
53
    def test_undo(self):
54
        wt = self.make_branch_and_tree('.')
55
        wt.commit("lala!")
56
        wt.commit("haha!")
57
        wt.commit("blabla!")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
58
        wt.merge_from_branch(wt.branch, wt.branch.get_rev_id(2),
59
                             wt.branch.get_rev_id(1))
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
60
974.1.80 by Aaron Bentley
Improved merge error handling and testing
61
    def test_nocommits(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
62
        wt = self.test_pending()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
63
        wt2 = self.make_branch_and_tree('branch2')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
64
        self.assertRaises(NoCommits, wt.merge_from_branch, wt2.branch)
65
        return wt, wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
66
67
    def test_unrelated(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
68
        wt, wt2 = self.test_nocommits()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
69
        wt2.commit("blah")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
70
        self.assertRaises(UnrelatedBranches, wt.merge_from_branch, wt2.branch)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
71
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
72
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
73
    def test_merge_one_file(self):
74
        """Do a partial merge of a tree which should not affect tree parents."""
1645.1.1 by Aaron Bentley
Implement single-file merge
75
        wt1 = self.make_branch_and_tree('branch1')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
76
        tip = wt1.commit('empty commit')
1645.1.1 by Aaron Bentley
Implement single-file merge
77
        wt2 = self.make_branch_and_tree('branch2')
78
        wt2.pull(wt1.branch)
79
        file('branch1/foo', 'wb').write('foo')
80
        file('branch1/bar', 'wb').write('bar')
81
        wt1.add('foo')
82
        wt1.add('bar')
83
        wt1.commit('add foobar')
84
        os.chdir('branch2')
2530.3.1 by Martin Pool
Cleanup old variations on run_bzr in the test suite
85
        self.run_bzr('merge ../branch1/baz', retcode=3)
86
        self.run_bzr('merge ../branch1/foo')
1645.1.1 by Aaron Bentley
Implement single-file merge
87
        self.failUnlessExists('foo')
88
        self.failIfExists('bar')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
89
        wt2 = WorkingTree.open('.') # opens branch2
90
        self.assertEqual([tip], wt2.get_parent_ids())
1908.6.9 by Robert Collins
Fix status to not use pending_merges.
91
        
974.1.88 by Aaron Bentley
Set a pending_merge if the merge base is forced to revno 0
92
    def test_pending_with_null(self):
1551.8.25 by Aaron Bentley
Fix deprecated use of pending_merges
93
        """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.
94
        wt2 = self.test_unrelated()
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
95
        wt1 = WorkingTree.open('.')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
96
        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.
97
        br1.fetch(wt2.branch)
1390 by Robert Collins
pair programming worx... merge integration and weave
98
        # merge all of branch 2 into branch 1 even though they 
99
        # are not related.
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
100
        wt1.merge_from_branch(wt2.branch, wt2.last_revision(), 'null:')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
101
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
102
            wt1.get_parent_ids())
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
103
        return (wt1, wt2.branch)
974.1.89 by Aaron Bentley
Fixed merging with multiple roots, by using null as graph root.
104
105
    def test_two_roots(self):
106
        """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.
107
        wt1, br2 = self.test_pending_with_null()
108
        wt1.commit("blah")
109
        last = wt1.branch.last_revision()
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
110
        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
111
112
    def test_create_rename(self):
113
        """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.
114
        tree =self.make_branch_and_tree('.')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
115
        file('name1', 'wb').write('Hello')
116
        tree.add('name1')
117
        tree.commit(message="hello")
118
        tree.rename_one('name1', 'name2')
119
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
120
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
121
122
    def test_layered_rename(self):
123
        """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.
124
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
125
        os.mkdir('dirname1')
126
        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 \
127
        filename = pathjoin('dirname1', 'name1')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
128
        file(filename, 'wb').write('Hello')
129
        tree.add(filename)
130
        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 \
131
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
132
        tree.rename_one(filename, filename2)
133
        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.
134
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
135
136
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
137
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
138
        tree_a =self.make_branch_and_tree('a')
139
        tree_a.commit(message="hello")
140
        dir_b = tree_a.bzrdir.sprout('b')
141
        tree_b = dir_b.open_workingtree()
3146.4.4 by Aaron Bentley
Add write lock, so merge_inner works properly
142
        tree_b.lock_write()
143
        self.addCleanup(tree_b.unlock)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
144
        tree_a.commit(message="hello again")
145
        log = StringIO()
146
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
147
                    this_tree=tree_b, ignore_zero=True)
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' not in log)
2796.1.3 by Aaron Bentley
update new test case
150
        tree_b.revert()
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
151
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
152
                    this_tree=tree_b, ignore_zero=False)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
153
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
154
        self.failUnless('All changes applied successfully.\n' in log)
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
155
156
    def test_merge_inner_conflicts(self):
157
        tree_a = self.make_branch_and_tree('a')
158
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
159
        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.
160
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
161
162
    def test_rmdir_conflict(self):
163
        tree_a = self.make_branch_and_tree('a')
164
        self.build_tree(['a/b/'])
165
        tree_a.add('b', 'b-id')
166
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
167
        # basis_tree() is only guaranteed to be valid as long as it is actually
168
        # the basis tree. This mutates the tree after grabbing basis, so go to
169
        # the repository.
170
        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
171
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
172
        self.build_tree(['a/b/c'])
173
        tree_a.add('b/c')
174
        tree_a.commit('added c')
175
        os.rmdir('z/b')
176
        tree_z.commit('removed b')
177
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
178
        self.assertEqual([
179
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
180
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
181
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
182
        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
183
                    this_tree=tree_a)
184
        self.assertEqual([
185
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
186
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
187
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
188
2100.3.29 by Aaron Bentley
Get merge working initially
189
    def test_nested_merge(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
190
        tree = self.make_branch_and_tree('tree',
191
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
192
        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.
193
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
194
        sub_tree.set_root_id('sub-tree-root')
195
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
196
        sub_tree.add('file')
197
        sub_tree.commit('foo')
198
        tree.add_reference(sub_tree)
199
        tree.commit('set text to 1')
200
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
201
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
202
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
203
        # and merge the changes from the diverged subtree into the containing
204
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
205
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
206
        tree.merge_from_branch(tree2.branch)
207
        self.assertFileEqual('text2', 'tree/sub-tree/file')
208
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
209
    def test_merge_with_missing(self):
210
        tree_a = self.make_branch_and_tree('tree_a')
211
        self.build_tree_contents([('tree_a/file', 'content_1')])
212
        tree_a.add('file')
213
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
214
        # basis_tree() is only guaranteed to be valid as long as it is actually
215
        # the basis tree. This mutates the tree after grabbing basis, so go to
216
        # the repository.
217
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
218
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
219
        self.build_tree_contents([('tree_a/file', 'content_2')])
220
        tree_a.commit('commit other')
221
        other_tree = tree_a.basis_tree()
222
        os.unlink('tree_b/file')
223
        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
224
225
    def test_merge_kind_change(self):
226
        tree_a = self.make_branch_and_tree('tree_a')
227
        self.build_tree_contents([('tree_a/file', 'content_1')])
228
        tree_a.add('file', 'file-id')
229
        tree_a.commit('added file')
230
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
231
        os.unlink('tree_a/file')
232
        self.build_tree(['tree_a/file/'])
233
        tree_a.commit('changed file to directory')
234
        tree_b.merge_from_branch(tree_a.branch)
235
        self.assertEqual('directory', file_kind('tree_b/file'))
2748.3.2 by Aaron Bentley
Fix revert, remove-tree, and various tests to use None for 'no files specified'
236
        tree_b.revert()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
237
        self.assertEqual('file', file_kind('tree_b/file'))
238
        self.build_tree_contents([('tree_b/file', 'content_2')])
239
        tree_b.commit('content change')
240
        tree_b.merge_from_branch(tree_a.branch)
241
        self.assertEqual(tree_b.conflicts(),
242
                         [conflicts.ContentsConflict('file',
243
                          file_id='file-id')])
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
244
    
245
    def test_merge_type_registry(self):
246
        merge_type_option = option.Option.OPTIONS['merge-type']
247
        self.assertFalse('merge4' in [x[0] for x in 
248
                        merge_type_option.iter_switches()])
249
        registry = _mod_merge.get_merge_type_registry()
250
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
251
                               'time-travelling merge')
252
        self.assertTrue('merge4' in [x[0] for x in 
253
                        merge_type_option.iter_switches()])
254
        registry.remove('merge4')
255
        self.assertFalse('merge4' in [x[0] for x in 
256
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
257
1551.16.3 by Aaron Bentley
Rename test case
258
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
259
        tree_a = self.make_branch_and_tree('A')
260
        tree_a.lock_write()
261
        self.addCleanup(tree_a.unlock)
262
        self.build_tree(['A/a'])
263
        tree_a.add('a')
264
        tree_a.commit('1', rev_id='rev-1')
265
        tree_a.flush()
266
        tree_a.rename_one('a', 'b')
267
        tree_a.commit('2')
268
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
269
        tree_b = bzrdir_b.open_workingtree()
270
        tree_b.lock_write()
271
        self.addCleanup(tree_b.unlock)
272
        os.unlink('B/a')
273
        tree_b.commit('3')
274
        try:
275
            tree_b.merge_from_branch(tree_a.branch)
276
        except AttributeError:
277
            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()
278
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
    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()
280
        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.
281
        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()
282
        tree_a.add(['file_1'])
283
        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.
284
        tree_a.add(['file_2'])
285
        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()
286
        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.
287
        tree_b.rename_one('file_1', 'renamed')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
288
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
289
                                                    progress.DummyProgress())
290
        merger.merge_type = _mod_merge.Merge3Merger
291
        merger.do_merge()
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.
292
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
293
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
294
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis_weave(self):
295
        tree_a = self.make_branch_and_tree('a')
296
        self.build_tree(['a/file_1', 'a/file_2'])
297
        tree_a.add(['file_1'])
298
        tree_a.commit('commit 1')
299
        tree_a.add(['file_2'])
300
        tree_a.commit('commit 2')
301
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
302
        tree_b.rename_one('file_1', 'renamed')
303
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
304
                                                    progress.DummyProgress())
305
        merger.merge_type = _mod_merge.WeaveMerger
306
        merger.do_merge()
307
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
308
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
309
    def prepare_cherrypick(self):
3062.2.13 by Aaron Bentley
Update prepare_cherrypick docstring
310
        """Prepare a pair of trees for cherrypicking tests.
311
312
        Both trees have a file, 'file'.
313
        rev1 sets content to 'a'.
314
        rev2b adds 'b'.
315
        rev3b adds 'c'.
316
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
317
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
318
        'c', but not 'b'.
319
        """
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
320
        this_tree = self.make_branch_and_tree('this')
321
        self.build_tree_contents([('this/file', "a\n")])
322
        this_tree.add('file')
323
        this_tree.commit('rev1')
324
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
325
        self.build_tree_contents([('other/file', "a\nb\n")])
326
        other_tree.commit('rev2b', rev_id='rev2b')
327
        self.build_tree_contents([('other/file', "c\na\nb\n")])
328
        other_tree.commit('rev3b', rev_id='rev3b')
329
        this_tree.lock_write()
330
        self.addCleanup(this_tree.unlock)
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
331
        return this_tree, other_tree
332
333
    def test_weave_cherrypick(self):
334
        this_tree, other_tree = self.prepare_cherrypick()
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
335
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
336
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
337
        merger.merge_type = _mod_merge.WeaveMerger
338
        merger.do_merge()
339
        self.assertFileEqual('c\na\n', 'this/file')
340
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
341
    def test_weave_cannot_reverse_cherrypick(self):
342
        this_tree, other_tree = self.prepare_cherrypick()
343
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
344
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
345
        merger.merge_type = _mod_merge.WeaveMerger
346
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
347
348
    def test_merge3_can_reverse_cherrypick(self):
349
        this_tree, other_tree = self.prepare_cherrypick()
350
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
351
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
352
        merger.merge_type = _mod_merge.Merge3Merger
353
        merger.do_merge()
354
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
355
    def test_merge3_will_detect_cherrypick(self):
356
        this_tree = self.make_branch_and_tree('this')
357
        self.build_tree_contents([('this/file', "a\n")])
358
        this_tree.add('file')
359
        this_tree.commit('rev1')
360
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
361
        self.build_tree_contents([('other/file', "a\nb\n")])
362
        other_tree.commit('rev2b', rev_id='rev2b')
363
        self.build_tree_contents([('other/file', "a\nb\nc\n")])
364
        other_tree.commit('rev3b', rev_id='rev3b')
365
        this_tree.lock_write()
366
        self.addCleanup(this_tree.unlock)
367
368
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
369
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
370
        merger.merge_type = _mod_merge.Merge3Merger
371
        merger.do_merge()
372
        self.assertFileEqual('a\n'
373
                             '<<<<<<< TREE\n'
374
                             '=======\n'
375
                             'c\n'
376
                             '>>>>>>> MERGE-SOURCE\n',
377
                             'this/file')
378
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
379
    def test_make_merger(self):
380
        this_tree = self.make_branch_and_tree('this')
381
        this_tree.commit('rev1', rev_id='rev1')
382
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
383
        this_tree.commit('rev2', rev_id='rev2a')
384
        other_tree.commit('rev2', rev_id='rev2b')
385
        this_tree.lock_write()
386
        self.addCleanup(this_tree.unlock)
387
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress,
388
            this_tree, 'rev2b', other_branch=other_tree.branch)
389
        merger.merge_type = _mod_merge.Merge3Merger
390
        tree_merger = merger.make_merger()
391
        self.assertIs(_mod_merge.Merge3Merger, tree_merger.__class__)
392
        self.assertEqual('rev2b', tree_merger.other_tree.get_revision_id())
393
        self.assertEqual('rev1', tree_merger.base_tree.get_revision_id())
394
395
    def test_make_preview_transform(self):
396
        this_tree = self.make_branch_and_tree('this')
397
        self.build_tree_contents([('this/file', '1\n')])
398
        this_tree.add('file', 'file-id')
399
        this_tree.commit('rev1', rev_id='rev1')
400
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
401
        self.build_tree_contents([('this/file', '1\n2a\n')])
402
        this_tree.commit('rev2', rev_id='rev2a')
403
        self.build_tree_contents([('other/file', '2b\n1\n')])
404
        other_tree.commit('rev2', rev_id='rev2b')
405
        this_tree.lock_write()
406
        self.addCleanup(this_tree.unlock)
407
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
408
            this_tree, 'rev2b', other_branch=other_tree.branch)
409
        merger.merge_type = _mod_merge.Merge3Merger
410
        tree_merger = merger.make_merger()
411
        tt = tree_merger.make_preview_transform()
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
412
        self.addCleanup(tt.finalize)
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
413
        preview_tree = tt.get_preview_tree()
414
        tree_file = this_tree.get_file('file-id')
415
        try:
416
            self.assertEqual('1\n2a\n', tree_file.read())
417
        finally:
418
            tree_file.close()
419
        preview_file = preview_tree.get_file('file-id')
420
        try:
421
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
422
        finally:
423
            preview_file.close()
424
3008.1.22 by Aaron Bentley
Get do_merge under test
425
    def test_do_merge(self):
426
        this_tree = self.make_branch_and_tree('this')
427
        self.build_tree_contents([('this/file', '1\n')])
428
        this_tree.add('file', 'file-id')
429
        this_tree.commit('rev1', rev_id='rev1')
430
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
431
        self.build_tree_contents([('this/file', '1\n2a\n')])
432
        this_tree.commit('rev2', rev_id='rev2a')
433
        self.build_tree_contents([('other/file', '2b\n1\n')])
434
        other_tree.commit('rev2', rev_id='rev2b')
435
        this_tree.lock_write()
436
        self.addCleanup(this_tree.unlock)
437
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
438
            this_tree, 'rev2b', other_branch=other_tree.branch)
439
        merger.merge_type = _mod_merge.Merge3Merger
440
        tree_merger = merger.make_merger()
441
        tt = tree_merger.do_merge()
442
        tree_file = this_tree.get_file('file-id')
443
        try:
444
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
445
        finally:
446
            tree_file.close()
447
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
448
449
class TestPlanMerge(TestCaseWithMemoryTransport):
450
451
    def setUp(self):
452
        TestCaseWithMemoryTransport.setUp(self)
453
        self.vf = knit.KnitVersionedFile('root', self.get_transport(),
454
                                         create=True)
455
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
456
                                                                   [self.vf])
457
458
    def add_version(self, version_id, parents, text):
459
        self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
460
461
    def add_uncommitted_version(self, version_id, parents, text):
462
        self.plan_merge_vf.add_lines(version_id, parents,
463
                                     [c+'\n' for c in text])
464
465
    def setup_plan_merge(self):
466
        self.add_version('A', [], 'abc')
467
        self.add_version('B', ['A'], 'acehg')
468
        self.add_version('C', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
469
        return _PlanMerge('B', 'C', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
470
471
    def setup_plan_merge_uncommitted(self):
472
        self.add_version('A', [], 'abc')
473
        self.add_uncommitted_version('B:', ['A'], 'acehg')
474
        self.add_uncommitted_version('C:', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
475
        return _PlanMerge('B:', 'C:', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
476
477
    def test_unique_lines(self):
478
        plan = self.setup_plan_merge()
479
        self.assertEqual(plan._unique_lines(
480
            plan._get_matching_blocks('B', 'C')),
481
            ([1, 2, 3], [0, 2]))
482
483
    def test_find_new(self):
484
        plan = self.setup_plan_merge()
485
        self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
486
        self.assertEqual(set([0, 3]), plan._find_new('C'))
487
488
    def test_find_new2(self):
489
        self.add_version('A', [], 'abc')
490
        self.add_version('B', ['A'], 'abcde')
491
        self.add_version('C', ['A'], 'abcefg')
492
        self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
493
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
494
        self.assertEqual(set([5, 6]), my_plan._find_new('D'))
495
        self.assertEqual(set(), my_plan._find_new('A'))
496
497
    def test_find_new_no_ancestors(self):
498
        self.add_version('A', [], 'abc')
499
        self.add_version('B', [], 'xyz')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
500
        my_plan = _PlanMerge('A', 'B', self.vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
501
        self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
502
503
    def test_plan_merge(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
504
        self.setup_plan_merge()
505
        plan = self.plan_merge_vf.plan_merge('B', 'C')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
506
        self.assertEqual([
507
                          ('new-b', 'f\n'),
508
                          ('unchanged', 'a\n'),
509
                          ('killed-b', 'c\n'),
510
                          ('new-a', 'e\n'),
511
                          ('new-a', 'h\n'),
512
                          ('killed-a', 'b\n'),
513
                          ('unchanged', 'g\n')],
514
                         list(plan))
515
516
    def test_plan_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
517
        self.setup_plan_merge_uncommitted()
518
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
519
        self.assertEqual([
520
                          ('new-b', 'f\n'),
521
                          ('unchanged', 'a\n'),
522
                          ('killed-b', 'c\n'),
523
                          ('new-a', 'e\n'),
524
                          ('new-a', 'h\n'),
525
                          ('killed-a', 'b\n'),
526
                          ('unchanged', 'g\n')],
527
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
528
529
    def test_subtract_plans(self):
530
        old_plan = [
531
        ('unchanged', 'a\n'),
532
        ('new-a', 'b\n'),
533
        ('killed-a', 'c\n'),
534
        ('new-b', 'd\n'),
535
        ('new-b', 'e\n'),
536
        ('killed-b', 'f\n'),
537
        ('killed-b', 'g\n'),
538
        ]
539
        new_plan = [
540
        ('unchanged', 'a\n'),
541
        ('new-a', 'b\n'),
542
        ('killed-a', 'c\n'),
543
        ('new-b', 'd\n'),
544
        ('new-b', 'h\n'),
545
        ('killed-b', 'f\n'),
546
        ('killed-b', 'i\n'),
547
        ]
548
        subtracted_plan = [
549
        ('unchanged', 'a\n'),
550
        ('new-a', 'b\n'),
551
        ('killed-a', 'c\n'),
552
        ('new-b', 'h\n'),
553
        ('unchanged', 'f\n'),
554
        ('killed-b', 'i\n'),
555
        ]
556
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
557
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
558
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
559
    def setup_merge_with_base(self):
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
560
        self.add_version('COMMON', [], 'abc')
561
        self.add_version('THIS', ['COMMON'], 'abcd')
562
        self.add_version('BASE', ['COMMON'], 'eabc')
563
        self.add_version('OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
564
565
    def test_plan_merge_with_base(self):
566
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
567
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
568
        self.assertEqual([('unchanged', 'a\n'),
569
                          ('new-b', 'f\n'),
570
                          ('unchanged', 'b\n'),
571
                          ('killed-b', 'c\n'),
572
                          ('new-a', 'd\n')
573
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
574
575
    def test_plan_lca_merge(self):
576
        self.setup_plan_merge()
577
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
578
        self.assertEqual([
579
                          ('new-b', 'f\n'),
580
                          ('unchanged', 'a\n'),
581
                          ('killed-b', 'c\n'),
582
                          ('new-a', 'e\n'),
583
                          ('new-a', 'h\n'),
584
                          ('killed-a', 'b\n'),
585
                          ('unchanged', 'g\n')],
586
                         list(plan))
587
588
    def test_plan_lca_merge_uncommitted_files(self):
589
        self.setup_plan_merge_uncommitted()
590
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
591
        self.assertEqual([
592
                          ('new-b', 'f\n'),
593
                          ('unchanged', 'a\n'),
594
                          ('killed-b', 'c\n'),
595
                          ('new-a', 'e\n'),
596
                          ('new-a', 'h\n'),
597
                          ('killed-a', 'b\n'),
598
                          ('unchanged', 'g\n')],
599
                         list(plan))
600
601
    def test_plan_lca_merge_with_base(self):
602
        self.setup_merge_with_base()
603
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
604
        self.assertEqual([('unchanged', 'a\n'),
605
                          ('new-b', 'f\n'),
606
                          ('unchanged', 'b\n'),
607
                          ('killed-b', 'c\n'),
608
                          ('new-a', 'd\n')
609
                         ], list(plan))
610
611
    def test_plan_lca_merge_with_criss_cross(self):
612
        self.add_version('ROOT', [], 'abc')
613
        # each side makes a change
614
        self.add_version('REV1', ['ROOT'], 'abcd')
615
        self.add_version('REV2', ['ROOT'], 'abce')
616
        # both sides merge, discarding others' changes
617
        self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
618
        self.add_version('LCA2', ['REV1', 'REV2'], 'fabce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
619
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
620
        self.assertEqual([('new-b', 'f\n'),
621
                          ('unchanged', 'a\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
622
                          ('unchanged', 'b\n'),
623
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
624
                          ('conflicted-a', 'd\n'),
625
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
626
                         ], list(plan))
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
627
628
629
class TestMergeImplementation(object):
630
631
    def do_merge(self, target_tree, source_tree, **kwargs):
632
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
633
            target_tree, source_tree.last_revision(),
634
            other_branch=source_tree.branch)
635
        merger.merge_type=self.merge_type
636
        for name, value in kwargs.items():
637
            setattr(merger, name, value)
638
        merger.do_merge()
639
640
    def test_merge_specific_file(self):
641
        this_tree = self.make_branch_and_tree('this')
642
        this_tree.lock_write()
643
        self.addCleanup(this_tree.unlock)
644
        self.build_tree_contents([
645
            ('this/file1', 'a\nb\n'),
646
            ('this/file2', 'a\nb\n')
647
        ])
648
        this_tree.add(['file1', 'file2'])
649
        this_tree.commit('Added files')
650
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
651
        self.build_tree_contents([
652
            ('other/file1', 'a\nb\nc\n'),
653
            ('other/file2', 'a\nb\nc\n')
654
        ])
655
        other_tree.commit('modified both')
656
        self.build_tree_contents([
657
            ('this/file1', 'd\na\nb\n'),
658
            ('this/file2', 'd\na\nb\n')
659
        ])
660
        this_tree.commit('modified both')
661
        self.do_merge(this_tree, other_tree, interesting_files=['file1'])
662
        self.assertFileEqual('d\na\nb\nc\n', 'this/file1')
663
        self.assertFileEqual('d\na\nb\n', 'this/file2')
664
665
666
class TestMerge3Merge(TestCaseWithTransport, TestMergeImplementation):
667
668
    merge_type = _mod_merge.Merge3Merger
669
670
671
class TestWeaveMerge(TestCaseWithTransport, TestMergeImplementation):
672
673
    merge_type = _mod_merge.WeaveMerger
674
675
676
class TestLCAMerge(TestCaseWithTransport, TestMergeImplementation):
677
678
    merge_type = _mod_merge.LCAMerger