/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_merge.py

  • Committer: Martin Pool
  • Date: 2007-10-03 08:06:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2901.
  • Revision ID: mbp@sourcefrog.net-20071003080644-oivy0gkg98sex0ed
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).

Add new LockFailed, which doesn't imply that we failed to get it because of
contention.  Raise this if we fail to create the pending or lock directories
because of Transport errors.

UnlockableTransport is not an internal error.

ReadOnlyLockError has a message which didn't match its name or usage; it's now
deprecated and callers are updated to use LockFailed which is more appropriate.

Add zero_ninetytwo deprecation symbol.

Unify assertMatchesRe with TestCase.assertContainsRe.

When the constructor is deprecated, just say that the class is deprecated, not
the __init__ method - this works better with applyDeprecated in tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
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
16
16
#
17
17
# Author: Aaron Bentley <aaron.bentley@utoronto.ca>
18
18
 
21
21
 
22
22
import os
23
23
 
24
 
from bzrlib import (
25
 
    branch,
26
 
    bzrdir,
27
 
    conflicts,
28
 
    errors,
29
 
    merge_directive,
30
 
    osutils,
31
 
    tests,
32
 
    urlutils,
33
 
    workingtree,
34
 
    )
35
 
 
36
 
 
37
 
class TestMerge(tests.TestCaseWithTransport):
 
24
from bzrlib import merge_directive
 
25
from bzrlib.branch import Branch
 
26
from bzrlib.bzrdir import BzrDir
 
27
from bzrlib.conflicts import ConflictList, ContentsConflict
 
28
from bzrlib.osutils import abspath, file_kind, pathjoin
 
29
from bzrlib.tests.blackbox import ExternalBase
 
30
import bzrlib.urlutils as urlutils
 
31
from bzrlib.workingtree import WorkingTree
 
32
 
 
33
 
 
34
class TestMerge(ExternalBase):
38
35
 
39
36
    def example_branch(self, path='.'):
40
37
        tree = self.make_branch_and_tree(path)
41
38
        self.build_tree_contents([
42
 
            (osutils.pathjoin(path, 'hello'), 'foo'),
43
 
            (osutils.pathjoin(path, 'goodbye'), 'baz')])
 
39
            (pathjoin(path, 'hello'), 'foo'),
 
40
            (pathjoin(path, 'goodbye'), 'baz')])
44
41
        tree.add('hello')
45
42
        tree.commit(message='setup')
46
43
        tree.add('goodbye')
47
44
        tree.commit(message='setup')
48
45
        return tree
49
46
 
50
 
    def create_conflicting_branches(self):
51
 
        """Create two branches which have overlapping modifications.
52
 
 
53
 
        :return: (tree, other_branch) Where merging other_branch causes a file
54
 
            conflict.
55
 
        """
56
 
        builder = self.make_branch_builder('branch')
57
 
        builder.build_snapshot('rev1', None,
58
 
            [('add', ('', 'root-id', 'directory', None)),
59
 
             ('add', ('fname', 'f-id', 'file', 'a\nb\nc\n'))])
60
 
        builder.build_snapshot('rev2other', ['rev1'],
61
 
            [('modify', ('f-id', 'a\nB\nD\n'))])
62
 
        other = builder.get_branch().bzrdir.sprout('other').open_branch()
63
 
        builder.build_snapshot('rev2this', ['rev1'],
64
 
            [('modify', ('f-id', 'a\nB\nC\n'))])
65
 
        tree = builder.get_branch().create_checkout('tree', lightweight=True)
66
 
        return tree, other
67
 
 
68
47
    def test_merge_reprocess(self):
69
 
        d = bzrdir.BzrDir.create_standalone_workingtree('.')
 
48
        d = BzrDir.create_standalone_workingtree('.')
70
49
        d.commit('h')
71
50
        self.run_bzr('merge . --reprocess --merge-type weave')
72
51
 
73
52
    def test_merge(self):
 
53
        from bzrlib.branch import Branch
 
54
 
74
55
        a_tree = self.example_branch('a')
75
56
        ancestor = a_tree.branch.revno()
76
57
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
81
62
        # We can't merge when there are in-tree changes
82
63
        os.chdir('a')
83
64
        self.run_bzr('merge ../b', retcode=3)
84
 
        a = workingtree.WorkingTree.open('.')
 
65
        a = WorkingTree.open('.')
85
66
        a_tip = a.commit("Like an epidemic of u's")
86
67
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type blooof',
87
68
                    retcode=3)
89
70
        a_tree.revert(backups=False)
90
71
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type weave')
91
72
        a_tree.revert(backups=False)
92
 
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type lca')
93
 
        a_tree.revert(backups=False)
94
73
        self.run_bzr_error(['Show-base is not supported for this merge type'],
95
74
                           'merge ../b -r last:1..last:1 --merge-type weave'
96
75
                           ' --show-base')
100
79
        self.run_bzr('merge ../b -r last:1')
101
80
        self.check_file_contents('goodbye', 'quux')
102
81
        # Merging a branch pulls its revision into the tree
103
 
        b = branch.Branch.open('../b')
 
82
        b = Branch.open('../b')
104
83
        b_tip = b.last_revision()
105
84
        self.failUnless(a.branch.repository.has_revision(b_tip))
106
85
        self.assertEqual([a_tip, b_tip], a.get_parent_ids())
109
88
        self.assertTrue("Not a branch" in err)
110
89
        self.run_bzr('merge -r revno:%d:./..revno:%d:../b'
111
90
                    %(ancestor,b.revno()))
112
 
        self.assertEquals(a.get_parent_ids(),
 
91
        self.assertEquals(a.get_parent_ids(), 
113
92
                          [a.branch.last_revision(), b.last_revision()])
114
93
        self.check_file_contents('goodbye', 'quux')
115
94
        a_tree.revert(backups=False)
120
99
        self.run_bzr('merge ../b -r last:1')
121
100
        self.assertEqual([a_tip], a.get_parent_ids())
122
101
 
123
 
    def test_merge_defaults_to_reprocess(self):
124
 
        tree, other = self.create_conflicting_branches()
125
 
        # The default merge algorithm should enable 'reprocess' because
126
 
        # 'show-base' is not set
127
 
        self.run_bzr('merge ../other', working_dir='tree',
128
 
                     retcode=1)
129
 
        self.assertEqualDiff('a\n'
130
 
                             'B\n'
131
 
                             '<<<<<<< TREE\n'
132
 
                             'C\n'
133
 
                             '=======\n'
134
 
                             'D\n'
135
 
                             '>>>>>>> MERGE-SOURCE\n',
136
 
                             tree.get_file_text('f-id'))
137
 
 
138
 
    def test_merge_explicit_reprocess_show_base(self):
139
 
        tree, other = self.create_conflicting_branches()
140
 
        # Explicitly setting --reprocess, and --show-base is an error
141
 
        self.run_bzr_error(['Cannot do conflict reduction and show base'],
142
 
                           'merge ../other --reprocess --show-base',
143
 
                           working_dir='tree')
144
 
 
145
 
    def test_merge_override_reprocess(self):
146
 
        tree, other = self.create_conflicting_branches()
147
 
        # Explicitly disable reprocess
148
 
        self.run_bzr('merge ../other --no-reprocess', working_dir='tree',
149
 
                     retcode=1)
150
 
        self.assertEqualDiff('a\n'
151
 
                             '<<<<<<< TREE\n'
152
 
                             'B\n'
153
 
                             'C\n'
154
 
                             '=======\n'
155
 
                             'B\n'
156
 
                             'D\n'
157
 
                             '>>>>>>> MERGE-SOURCE\n',
158
 
                             tree.get_file_text('f-id'))
159
 
 
160
 
    def test_merge_override_show_base(self):
161
 
        tree, other = self.create_conflicting_branches()
162
 
        # Setting '--show-base' will auto-disable '--reprocess'
163
 
        self.run_bzr('merge ../other --show-base', working_dir='tree',
164
 
                     retcode=1)
165
 
        self.assertEqualDiff('a\n'
166
 
                             '<<<<<<< TREE\n'
167
 
                             'B\n'
168
 
                             'C\n'
169
 
                             '||||||| BASE-REVISION\n'
170
 
                             'b\n'
171
 
                             'c\n'
172
 
                             '=======\n'
173
 
                             'B\n'
174
 
                             'D\n'
175
 
                             '>>>>>>> MERGE-SOURCE\n',
176
 
                             tree.get_file_text('f-id'))
177
 
 
178
102
    def test_merge_with_missing_file(self):
179
103
        """Merge handles missing file conflicts"""
180
104
        self.build_tree_contents([
211
135
        self.failUnlessExists('sub/a.txt.OTHER')
212
136
        self.failUnlessExists('sub/a.txt.BASE')
213
137
 
214
 
    def test_conflict_leaves_base_this_other_files(self):
215
 
        tree, other = self.create_conflicting_branches()
216
 
        self.run_bzr('merge ../other', working_dir='tree',
217
 
                     retcode=1)
218
 
        self.assertFileEqual('a\nb\nc\n', 'tree/fname.BASE')
219
 
        self.assertFileEqual('a\nB\nD\n', 'tree/fname.OTHER')
220
 
        self.assertFileEqual('a\nB\nC\n', 'tree/fname.THIS')
221
 
 
222
 
    def test_weave_conflict_leaves_base_this_other_files(self):
223
 
        tree, other = self.create_conflicting_branches()
224
 
        self.run_bzr('merge ../other --weave', working_dir='tree',
225
 
                     retcode=1)
226
 
        self.assertFileEqual('a\nb\nc\n', 'tree/fname.BASE')
227
 
        self.assertFileEqual('a\nB\nD\n', 'tree/fname.OTHER')
228
 
        self.assertFileEqual('a\nB\nC\n', 'tree/fname.THIS')
229
 
 
230
138
    def test_merge_remember(self):
231
 
        """Merge changes from one branch to another, test submit location."""
 
139
        """Merge changes from one branch to another and test parent location."""
232
140
        tree_a = self.make_branch_and_tree('branch_a')
233
141
        branch_a = tree_a.branch
234
142
        self.build_tree(['branch_a/a'])
253
161
        out = self.run_bzr('merge', retcode=3)
254
162
        self.assertEquals(out,
255
163
                ('','bzr: ERROR: No location specified or remembered\n'))
256
 
 
257
 
        # test uncommitted changes
 
164
        # test implicit --remember when no parent set, this merge conflicts
258
165
        self.build_tree(['d'])
259
166
        tree_b.add('d')
260
167
        self.run_bzr_error(['Working tree ".*" has uncommitted changes'],
261
 
                           'merge')
262
 
 
263
 
        # merge should now pass and implicitly remember merge location
 
168
                           'merge ../branch_a')
 
169
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
 
170
        # test implicit --remember after resolving conflict
264
171
        tree_b.commit('commit d')
265
 
        out, err = self.run_bzr('merge ../branch_a')
266
 
 
 
172
        out, err = self.run_bzr('merge')
 
173
        
267
174
        base = urlutils.local_path_from_url(branch_a.base)
268
 
        self.assertEndsWith(err, '+N  b\nAll changes applied successfully.\n')
269
 
        self.assertEquals(osutils.abspath(branch_b.get_submit_branch()),
270
 
                          osutils.abspath(parent))
271
 
        # test implicit --remember when committing new file
272
 
        self.build_tree(['e'])
273
 
        tree_b.add('e')
274
 
        tree_b.commit('commit e')
275
 
        out, err = self.run_bzr('merge')
276
 
        self.assertStartsWith(err,
277
 
                          'Merging from remembered submit location %s\n' % (base,))
 
175
        self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
 
176
        self.assertEquals(err, '+N  b\nAll changes applied successfully.\n')
 
177
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
278
178
        # re-open tree as external run_bzr modified it
279
179
        tree_b = branch_b.bzrdir.open_workingtree()
280
180
        tree_b.commit('merge branch_a')
282
182
        out, err = self.run_bzr('merge ../branch_c --remember')
283
183
        self.assertEquals(out, '')
284
184
        self.assertEquals(err, '+N  c\nAll changes applied successfully.\n')
285
 
        self.assertEquals(osutils.abspath(branch_b.get_submit_branch()),
286
 
                          osutils.abspath(branch_c.bzrdir.root_transport.base))
 
185
        self.assertEquals(abspath(branch_b.get_parent()),
 
186
                          abspath(branch_c.bzrdir.root_transport.base))
287
187
        # re-open tree as external run_bzr modified it
288
188
        tree_b = branch_b.bzrdir.open_workingtree()
289
189
        tree_b.commit('merge branch_c')
311
211
                                              tree_b.get_parent_ids()[0])
312
212
        self.assertEqualDiff(testament_a.as_text(),
313
213
                         testament_b.as_text())
314
 
        tree_a.set_conflicts(conflicts.ConflictList())
 
214
        tree_a.set_conflicts(ConflictList())
315
215
        tree_a.commit('message')
316
216
        # it is legal to attempt to merge an already-merged bundle
317
217
        output = self.run_bzr('merge ../bundle')[1]
338
238
        self.run_bzr_error(('Cannot use --uncommitted and --revision',),
339
239
                           'merge /a --uncommitted -r1 -d b')
340
240
 
341
 
    def test_merge_uncommitted_file(self):
342
 
        """It should be possible to merge changes from a single file."""
343
 
        tree_a = self.make_branch_and_tree('tree_a')
344
 
        tree_a.commit('initial commit')
345
 
        tree_a.bzrdir.sprout('tree_b')
346
 
        self.build_tree(['tree_a/file1', 'tree_a/file2'])
347
 
        tree_a.add(['file1', 'file2'])
348
 
        os.chdir('tree_b')
349
 
        self.run_bzr(['merge', '--uncommitted', '../tree_a/file1'])
350
 
        self.failUnlessExists('file1')
351
 
        self.failIfExists('file2')
352
 
 
353
241
    def pullable_branch(self):
354
242
        tree_a = self.make_branch_and_tree('a')
355
243
        self.build_tree(['a/file'])
366
254
        os.chdir('a')
367
255
        (out, err) = self.run_bzr('merge --pull ../b')
368
256
        self.assertContainsRe(out, 'Now on revision 2\\.')
369
 
        tree_a = workingtree.WorkingTree.open('.')
 
257
        tree_a = WorkingTree.open('.')
370
258
        self.assertEqual([self.id2], tree_a.get_parent_ids())
371
259
 
372
260
    def test_merge_kind_change(self):
380
268
        tree_a.commit('changed file to directory')
381
269
        os.chdir('tree_b')
382
270
        self.run_bzr('merge ../tree_a')
383
 
        self.assertEqual('directory', osutils.file_kind('file'))
 
271
        self.assertEqual('directory', file_kind('file'))
384
272
        tree_b.revert()
385
 
        self.assertEqual('file', osutils.file_kind('file'))
 
273
        self.assertEqual('file', file_kind('file'))
386
274
        self.build_tree_contents([('file', 'content_2')])
387
275
        tree_b.commit('content change')
388
276
        self.run_bzr('merge ../tree_a', retcode=1)
389
277
        self.assertEqual(tree_b.conflicts(),
390
 
                         [conflicts.ContentsConflict('file',
391
 
                                                     file_id='file-id')])
 
278
                         [ContentsConflict('file', file_id='file-id')])
392
279
 
393
280
    def test_directive_cherrypick(self):
394
281
        source = self.make_branch_and_tree('source')
395
 
        source.commit("nothing")
396
 
        # see https://bugs.edge.launchpad.net/bzr/+bug/409688 - trying to
397
 
        # cherrypick from one branch into another unrelated branch with a
398
 
        # different root id will give shape conflicts.  as a workaround we
399
 
        # make sure they share the same root id.
400
 
        target = source.bzrdir.sprout('target').open_workingtree()
401
282
        self.build_tree(['source/a'])
402
283
        source.add('a')
403
284
        source.commit('Added a', rev_id='rev1')
404
285
        self.build_tree(['source/b'])
405
286
        source.add('b')
406
287
        source.commit('Added b', rev_id='rev2')
 
288
        target = self.make_branch_and_tree('target')
407
289
        target.commit('empty commit')
408
290
        self.write_directive('directive', source.branch, 'target', 'rev2',
409
291
                             'rev1')
410
 
        out, err = self.run_bzr('merge -d target directive')
 
292
        self.run_bzr('merge -d target directive')
411
293
        self.failIfExists('target/a')
412
294
        self.failUnlessExists('target/b')
413
 
        self.assertContainsRe(err, 'Performing cherrypick')
414
295
 
415
296
    def write_directive(self, filename, source, target, revision_id,
416
297
                        base_revision_id=None, mangle_patch=False):
466
347
 
467
348
    def assertDirectoryContent(self, directory, entries, message=''):
468
349
        """Assert whether entries (file or directories) exist in a directory.
469
 
 
 
350
        
470
351
        It also checks that there are no extra entries.
471
352
        """
472
353
        ondisk = os.listdir(directory)
499
380
        # pick 1 revision with option --changes
500
381
        self.run_bzr('merge -d target -c revid:rev_d source')
501
382
        self.assertDirectoryContent('target', ['.bzr', 'a', 'd'])
502
 
 
503
 
    def test_merge_criss_cross(self):
504
 
        tree_a = self.make_branch_and_tree('a')
505
 
        tree_a.commit('', rev_id='rev1')
506
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
507
 
        tree_a.commit('', rev_id='rev2a')
508
 
        tree_b.commit('', rev_id='rev2b')
509
 
        tree_a.merge_from_branch(tree_b.branch)
510
 
        tree_b.merge_from_branch(tree_a.branch)
511
 
        tree_a.commit('', rev_id='rev3a')
512
 
        tree_b.commit('', rev_id='rev3b')
513
 
        graph = tree_a.branch.repository.get_graph(tree_b.branch.repository)
514
 
        out, err = self.run_bzr(['merge', '-d', 'a', 'b'])
515
 
        self.assertContainsRe(err, 'Warning: criss-cross merge encountered.')
516
 
 
517
 
    def test_merge_from_submit(self):
518
 
        tree_a = self.make_branch_and_tree('a')
519
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
520
 
        tree_c = tree_a.bzrdir.sprout('c').open_workingtree()
521
 
        out, err = self.run_bzr(['merge', '-d', 'c'])
522
 
        self.assertContainsRe(err, 'Merging from remembered parent location .*a\/')
523
 
        tree_c.branch.set_submit_branch(tree_b.bzrdir.root_transport.base)
524
 
        out, err = self.run_bzr(['merge', '-d', 'c'])
525
 
        self.assertContainsRe(err, 'Merging from remembered submit location .*b\/')
526
 
 
527
 
    def test_remember_sets_submit(self):
528
 
        tree_a = self.make_branch_and_tree('a')
529
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
530
 
        self.assertIs(tree_b.branch.get_submit_branch(), None)
531
 
 
532
 
        # Remember should not happen if using default from parent
533
 
        out, err = self.run_bzr(['merge', '-d', 'b'])
534
 
        self.assertIs(tree_b.branch.get_submit_branch(), None)
535
 
 
536
 
        # Remember should happen if user supplies location
537
 
        out, err = self.run_bzr(['merge', '-d', 'b', 'a'])
538
 
        self.assertEqual(tree_b.branch.get_submit_branch(),
539
 
                         tree_a.bzrdir.root_transport.base)
540
 
 
541
 
    def test_weave_cherrypick(self):
542
 
        this_tree = self.make_branch_and_tree('this')
543
 
        self.build_tree_contents([('this/file', "a\n")])
544
 
        this_tree.add('file')
545
 
        this_tree.commit('rev1')
546
 
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
547
 
        self.build_tree_contents([('other/file', "a\nb\n")])
548
 
        other_tree.commit('rev2b')
549
 
        self.build_tree_contents([('other/file', "c\na\nb\n")])
550
 
        other_tree.commit('rev3b')
551
 
        self.run_bzr('merge --weave -d this other -r -2..-1')
552
 
        self.assertFileEqual('c\na\n', 'this/file')
553
 
 
554
 
    def test_lca_merge_criss_cross(self):
555
 
        tree_a = self.make_branch_and_tree('a')
556
 
        self.build_tree_contents([('a/file', 'base-contents\n')])
557
 
        tree_a.add('file')
558
 
        tree_a.commit('', rev_id='rev1')
559
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
560
 
        self.build_tree_contents([('a/file',
561
 
                                   'base-contents\nthis-contents\n')])
562
 
        tree_a.commit('', rev_id='rev2a')
563
 
        self.build_tree_contents([('b/file',
564
 
                                   'base-contents\nother-contents\n')])
565
 
        tree_b.commit('', rev_id='rev2b')
566
 
        tree_a.merge_from_branch(tree_b.branch)
567
 
        self.build_tree_contents([('a/file',
568
 
                                   'base-contents\nthis-contents\n')])
569
 
        tree_a.set_conflicts(conflicts.ConflictList())
570
 
        tree_b.merge_from_branch(tree_a.branch)
571
 
        self.build_tree_contents([('b/file',
572
 
                                   'base-contents\nother-contents\n')])
573
 
        tree_b.set_conflicts(conflicts.ConflictList())
574
 
        tree_a.commit('', rev_id='rev3a')
575
 
        tree_b.commit('', rev_id='rev3b')
576
 
        out, err = self.run_bzr(['merge', '-d', 'a', 'b', '--lca'], retcode=1)
577
 
        self.assertFileEqual('base-contents\n<<<<<<< TREE\nthis-contents\n'
578
 
                             '=======\nother-contents\n>>>>>>> MERGE-SOURCE\n',
579
 
                             'a/file')
580
 
 
581
 
    def test_merge_preview(self):
582
 
        this_tree = self.make_branch_and_tree('this')
583
 
        this_tree.commit('rev1')
584
 
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
585
 
        self.build_tree_contents([('other/file', 'new line')])
586
 
        other_tree.add('file')
587
 
        other_tree.commit('rev2a')
588
 
        this_tree.commit('rev2b')
589
 
        out, err = self.run_bzr(['merge', '-d', 'this', 'other', '--preview'])
590
 
        self.assertContainsRe(out, '\+new line')
591
 
        self.assertNotContainsRe(err, '\+N  file\n')
592
 
        this_tree.lock_read()
593
 
        self.addCleanup(this_tree.unlock)
594
 
        self.assertEqual([],
595
 
                         list(this_tree.iter_changes(this_tree.basis_tree())))
596
 
 
597
 
    def test_merge_missing_second_revision_spec(self):
598
 
        """Merge uses branch basis when the second revision is unspecified."""
599
 
        this = self.make_branch_and_tree('this')
600
 
        this.commit('rev1')
601
 
        other = self.make_branch_and_tree('other')
602
 
        self.build_tree(['other/other_file'])
603
 
        other.add('other_file')
604
 
        other.commit('rev1b')
605
 
        self.run_bzr('merge -d this other -r0..')
606
 
        self.failUnlessExists('this/other_file')
607
 
 
608
 
    def test_merge_interactive_unlocks_branch(self):
609
 
        this = self.make_branch_and_tree('this')
610
 
        other = self.make_branch_and_tree('other')
611
 
        other.commit('empty commit')
612
 
        self.run_bzr('merge -i -d this other')
613
 
        this.lock_write()
614
 
        this.unlock()
615
 
 
616
 
    def test_merge_reversed_revision_range(self):
617
 
        tree = self.make_branch_and_tree(".")
618
 
        for f in ("a", "b"):
619
 
            self.build_tree([f])
620
 
            tree.add(f)
621
 
            tree.commit("added "+f)
622
 
        for context in (".", "", "a"):
623
 
            self.run_bzr("merge -r 1..0 " + context)
624
 
            self.failIfExists("a")
625
 
            tree.revert()
626
 
            self.failUnlessExists("a")
627
 
 
628
 
 
629
 
class TestMergeForce(tests.TestCaseWithTransport):
630
 
 
631
 
    def setUp(self):
632
 
        super(TestMergeForce, self).setUp()
633
 
        self.tree_a = self.make_branch_and_tree('a')
634
 
        self.build_tree(['a/foo'])
635
 
        self.tree_a.add(['foo'])
636
 
        self.tree_a.commit('add file')
637
 
        self.tree_b = self.tree_a.bzrdir.sprout('b').open_workingtree()
638
 
        self.build_tree_contents([('a/foo', 'change 1')])
639
 
        self.tree_a.commit('change file')
640
 
        self.tree_b.merge_from_branch(self.tree_a.branch)
641
 
 
642
 
    def test_merge_force(self):
643
 
        self.tree_a.commit('empty change to allow merge to run')
644
 
        # Second merge on top of the uncommitted one
645
 
        self.run_bzr(['merge', '../a', '--force'], working_dir='b')
646
 
 
647
 
 
648
 
    def test_merge_with_uncommitted_changes(self):
649
 
        self.run_bzr_error(['Working tree .* has uncommitted changes'],
650
 
                           ['merge', '../a'], working_dir='b')
651
 
 
652
 
    def test_merge_with_pending_merges(self):
653
 
        # Revert the changes keeping the pending merge
654
 
        self.run_bzr(['revert', 'b'])
655
 
        self.run_bzr_error(['Working tree .* has uncommitted changes'],
656
 
                           ['merge', '../a'], working_dir='b')