/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/test_merge.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2012 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
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
 
18
from StringIO import StringIO
18
19
 
19
 
from .. import (
 
20
from bzrlib import (
20
21
    branch as _mod_branch,
21
22
    cleanup,
22
23
    conflicts,
23
24
    errors,
 
25
    inventory,
 
26
    knit,
24
27
    memorytree,
25
28
    merge as _mod_merge,
26
29
    option,
27
30
    revision as _mod_revision,
28
31
    tests,
29
32
    transform,
30
 
    )
31
 
from ..bzr import (
32
 
    inventory,
33
 
    knit,
34
33
    versionedfile,
35
34
    )
36
 
from ..conflicts import ConflictList, TextConflict
37
 
from ..errors import UnrelatedBranches, NoCommits
38
 
from ..merge import transform_tree, merge_inner, _PlanMerge
39
 
from ..osutils import basename, pathjoin, file_kind
40
 
from . import (
 
35
from bzrlib.conflicts import ConflictList, TextConflict
 
36
from bzrlib.errors import UnrelatedBranches, NoCommits
 
37
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
 
38
from bzrlib.osutils import basename, pathjoin, file_kind
 
39
from bzrlib.tests import (
41
40
    features,
42
41
    TestCaseWithMemoryTransport,
43
42
    TestCaseWithTransport,
44
43
    test_merge_core,
45
44
    )
46
 
from ..workingtree import WorkingTree
 
45
from bzrlib.workingtree import WorkingTree
47
46
 
48
47
 
49
48
class TestMerge(TestCaseWithTransport):
178
177
        # Test that merge_inner's ignore zero parameter is effective
179
178
        tree_a =self.make_branch_and_tree('a')
180
179
        tree_a.commit(message="hello")
181
 
        dir_b = tree_a.controldir.sprout('b')
 
180
        dir_b = tree_a.bzrdir.sprout('b')
182
181
        tree_b = dir_b.open_workingtree()
183
182
        tree_b.lock_write()
184
183
        self.addCleanup(tree_b.unlock)
185
184
        tree_a.commit(message="hello again")
 
185
        log = StringIO()
186
186
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
187
187
                    this_tree=tree_b, ignore_zero=True)
188
188
        self.assertTrue('All changes applied successfully.\n' not in
201
201
    def test_rmdir_conflict(self):
202
202
        tree_a = self.make_branch_and_tree('a')
203
203
        self.build_tree(['a/b/'])
204
 
        tree_a.add('b', b'b-id')
 
204
        tree_a.add('b', 'b-id')
205
205
        tree_a.commit('added b')
206
206
        # basis_tree() is only guaranteed to be valid as long as it is actually
207
207
        # the basis tree. This mutates the tree after grabbing basis, so go to
208
208
        # the repository.
209
209
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
210
 
        tree_z = tree_a.controldir.sprout('z').open_workingtree()
 
210
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
211
211
        self.build_tree(['a/b/c'])
212
212
        tree_a.add('b/c')
213
213
        tree_a.commit('added c')
215
215
        tree_z.commit('removed b')
216
216
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
217
217
        self.assertEqual([
218
 
            conflicts.MissingParent('Created directory', 'b', b'b-id'),
219
 
            conflicts.UnversionedParent('Versioned directory', 'b', b'b-id')],
 
218
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
 
219
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
220
220
            tree_z.conflicts())
221
221
        merge_inner(tree_a.branch, tree_z.basis_tree(), base_tree,
222
222
                    this_tree=tree_a)
223
223
        self.assertEqual([
224
 
            conflicts.DeletingParent('Not deleting', 'b', b'b-id'),
225
 
            conflicts.UnversionedParent('Versioned directory', 'b', b'b-id')],
 
224
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
 
225
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
226
226
            tree_a.conflicts())
227
227
 
228
228
    def test_nested_merge(self):
229
 
        self.knownFailure(
230
 
            'iter_changes doesn\'t work with changes in nested trees')
231
229
        tree = self.make_branch_and_tree('tree',
232
230
            format='development-subtree')
233
231
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
234
232
            format='development-subtree')
235
 
        sub_tree.set_root_id(b'sub-tree-root')
236
 
        self.build_tree_contents([('tree/sub-tree/file', b'text1')])
 
233
        sub_tree.set_root_id('sub-tree-root')
 
234
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
237
235
        sub_tree.add('file')
238
236
        sub_tree.commit('foo')
239
237
        tree.add_reference(sub_tree)
240
238
        tree.commit('set text to 1')
241
 
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
 
239
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
242
240
        # modify the file in the subtree
243
 
        self.build_tree_contents([('tree2/sub-tree/file', b'text2')])
 
241
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
244
242
        # and merge the changes from the diverged subtree into the containing
245
243
        # tree
246
244
        tree2.commit('changed file text')
249
247
 
250
248
    def test_merge_with_missing(self):
251
249
        tree_a = self.make_branch_and_tree('tree_a')
252
 
        self.build_tree_contents([('tree_a/file', b'content_1')])
 
250
        self.build_tree_contents([('tree_a/file', 'content_1')])
253
251
        tree_a.add('file')
254
252
        tree_a.commit('commit base')
255
253
        # basis_tree() is only guaranteed to be valid as long as it is actually
256
254
        # the basis tree. This test commits to the tree after grabbing basis,
257
255
        # so we go to the repository.
258
256
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
259
 
        tree_b = tree_a.controldir.sprout('tree_b').open_workingtree()
260
 
        self.build_tree_contents([('tree_a/file', b'content_2')])
 
257
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
 
258
        self.build_tree_contents([('tree_a/file', 'content_2')])
261
259
        tree_a.commit('commit other')
262
260
        other_tree = tree_a.basis_tree()
263
261
        # 'file' is now missing but isn't altered in any commit in b so no
267
265
 
268
266
    def test_merge_kind_change(self):
269
267
        tree_a = self.make_branch_and_tree('tree_a')
270
 
        self.build_tree_contents([('tree_a/file', b'content_1')])
271
 
        tree_a.add('file', b'file-id')
 
268
        self.build_tree_contents([('tree_a/file', 'content_1')])
 
269
        tree_a.add('file', 'file-id')
272
270
        tree_a.commit('added file')
273
 
        tree_b = tree_a.controldir.sprout('tree_b').open_workingtree()
 
271
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
274
272
        os.unlink('tree_a/file')
275
273
        self.build_tree(['tree_a/file/'])
276
274
        tree_a.commit('changed file to directory')
278
276
        self.assertEqual('directory', file_kind('tree_b/file'))
279
277
        tree_b.revert()
280
278
        self.assertEqual('file', file_kind('tree_b/file'))
281
 
        self.build_tree_contents([('tree_b/file', b'content_2')])
 
279
        self.build_tree_contents([('tree_b/file', 'content_2')])
282
280
        tree_b.commit('content change')
283
281
        tree_b.merge_from_branch(tree_a.branch)
284
282
        self.assertEqual(tree_b.conflicts(),
285
283
                         [conflicts.ContentsConflict('file',
286
 
                          file_id=b'file-id')])
 
284
                          file_id='file-id')])
287
285
 
288
286
    def test_merge_type_registry(self):
289
287
        merge_type_option = option.Option.OPTIONS['merge-type']
290
288
        self.assertFalse('merge4' in [x[0] for x in
291
289
                        merge_type_option.iter_switches()])
292
290
        registry = _mod_merge.get_merge_type_registry()
293
 
        registry.register_lazy('merge4', 'breezy.merge', 'Merge4Merger',
 
291
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
294
292
                               'time-travelling merge')
295
293
        self.assertTrue('merge4' in [x[0] for x in
296
294
                        merge_type_option.iter_switches()])
304
302
        self.addCleanup(tree_a.unlock)
305
303
        self.build_tree(['A/a'])
306
304
        tree_a.add('a')
307
 
        tree_a.commit('1', rev_id=b'rev-1')
 
305
        tree_a.commit('1', rev_id='rev-1')
308
306
        tree_a.flush()
309
307
        tree_a.rename_one('a', 'b')
310
308
        tree_a.commit('2')
311
 
        bzrdir_b = tree_a.controldir.sprout('B', revision_id='rev-1')
 
309
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
312
310
        tree_b = bzrdir_b.open_workingtree()
313
311
        tree_b.lock_write()
314
312
        self.addCleanup(tree_b.unlock)
326
324
        tree_a.commit('commit 1')
327
325
        tree_a.add(['file_2'])
328
326
        tree_a.commit('commit 2')
329
 
        tree_b = tree_a.controldir.sprout('b').open_workingtree()
 
327
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
330
328
        tree_b.rename_one('file_1', 'renamed')
331
329
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
332
330
        merger.merge_type = _mod_merge.Merge3Merger
340
338
        tree_a.commit('commit 1')
341
339
        tree_a.add(['file_2'])
342
340
        tree_a.commit('commit 2')
343
 
        tree_b = tree_a.controldir.sprout('b').open_workingtree()
 
341
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
344
342
        tree_b.rename_one('file_1', 'renamed')
345
343
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
346
344
        merger.merge_type = _mod_merge.WeaveMerger
359
357
        'c', but not 'b'.
360
358
        """
361
359
        this_tree = self.make_branch_and_tree('this')
362
 
        self.build_tree_contents([('this/file', b"a\n")])
 
360
        self.build_tree_contents([('this/file', "a\n")])
363
361
        this_tree.add('file')
364
362
        this_tree.commit('rev1')
365
 
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
366
 
        self.build_tree_contents([('other/file', b"a\nb\n")])
367
 
        other_tree.commit('rev2b', rev_id=b'rev2b')
368
 
        self.build_tree_contents([('other/file', b"c\na\nb\n")])
369
 
        other_tree.commit('rev3b', rev_id=b'rev3b')
 
363
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
364
        self.build_tree_contents([('other/file', "a\nb\n")])
 
365
        other_tree.commit('rev2b', rev_id='rev2b')
 
366
        self.build_tree_contents([('other/file', "c\na\nb\n")])
 
367
        other_tree.commit('rev3b', rev_id='rev3b')
370
368
        this_tree.lock_write()
371
369
        self.addCleanup(this_tree.unlock)
372
370
        return this_tree, other_tree
373
371
 
374
372
    def test_weave_cherrypick(self):
375
373
        this_tree, other_tree = self.prepare_cherrypick()
376
 
        merger = _mod_merge.Merger.from_revision_ids(
 
374
        merger = _mod_merge.Merger.from_revision_ids(None,
377
375
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
378
376
        merger.merge_type = _mod_merge.WeaveMerger
379
377
        merger.do_merge()
381
379
 
382
380
    def test_weave_cannot_reverse_cherrypick(self):
383
381
        this_tree, other_tree = self.prepare_cherrypick()
384
 
        merger = _mod_merge.Merger.from_revision_ids(
 
382
        merger = _mod_merge.Merger.from_revision_ids(None,
385
383
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
386
384
        merger.merge_type = _mod_merge.WeaveMerger
387
385
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
388
386
 
389
387
    def test_merge3_can_reverse_cherrypick(self):
390
388
        this_tree, other_tree = self.prepare_cherrypick()
391
 
        merger = _mod_merge.Merger.from_revision_ids(
 
389
        merger = _mod_merge.Merger.from_revision_ids(None,
392
390
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
393
391
        merger.merge_type = _mod_merge.Merge3Merger
394
392
        merger.do_merge()
395
393
 
396
394
    def test_merge3_will_detect_cherrypick(self):
397
395
        this_tree = self.make_branch_and_tree('this')
398
 
        self.build_tree_contents([('this/file', b"a\n")])
 
396
        self.build_tree_contents([('this/file', "a\n")])
399
397
        this_tree.add('file')
400
398
        this_tree.commit('rev1')
401
 
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
402
 
        self.build_tree_contents([('other/file', b"a\nb\n")])
403
 
        other_tree.commit('rev2b', rev_id=b'rev2b')
404
 
        self.build_tree_contents([('other/file', b"a\nb\nc\n")])
405
 
        other_tree.commit('rev3b', rev_id=b'rev3b')
 
399
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
400
        self.build_tree_contents([('other/file', "a\nb\n")])
 
401
        other_tree.commit('rev2b', rev_id='rev2b')
 
402
        self.build_tree_contents([('other/file', "a\nb\nc\n")])
 
403
        other_tree.commit('rev3b', rev_id='rev3b')
406
404
        this_tree.lock_write()
407
405
        self.addCleanup(this_tree.unlock)
408
406
 
409
 
        merger = _mod_merge.Merger.from_revision_ids(
 
407
        merger = _mod_merge.Merger.from_revision_ids(None,
410
408
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
411
409
        merger.merge_type = _mod_merge.Merge3Merger
412
410
        merger.do_merge()
424
422
        self.build_tree(['a'])
425
423
        tree.add('a')
426
424
        first_rev = tree.commit("added a")
427
 
        merger = _mod_merge.Merger.from_revision_ids(tree,
 
425
        merger = _mod_merge.Merger.from_revision_ids(None, tree,
428
426
                                          _mod_revision.NULL_REVISION,
429
427
                                          first_rev)
430
428
        merger.merge_type = _mod_merge.Merge3Merger
438
436
 
439
437
    def test_make_merger(self):
440
438
        this_tree = self.make_branch_and_tree('this')
441
 
        this_tree.commit('rev1', rev_id=b'rev1')
442
 
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
443
 
        this_tree.commit('rev2', rev_id=b'rev2a')
444
 
        other_tree.commit('rev2', rev_id=b'rev2b')
 
439
        this_tree.commit('rev1', rev_id='rev1')
 
440
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
441
        this_tree.commit('rev2', rev_id='rev2a')
 
442
        other_tree.commit('rev2', rev_id='rev2b')
445
443
        this_tree.lock_write()
446
444
        self.addCleanup(this_tree.unlock)
447
 
        merger = _mod_merge.Merger.from_revision_ids(
 
445
        merger = _mod_merge.Merger.from_revision_ids(None,
448
446
            this_tree, 'rev2b', other_branch=other_tree.branch)
449
447
        merger.merge_type = _mod_merge.Merge3Merger
450
448
        tree_merger = merger.make_merger()
457
455
 
458
456
    def test_make_preview_transform(self):
459
457
        this_tree = self.make_branch_and_tree('this')
460
 
        self.build_tree_contents([('this/file', b'1\n')])
461
 
        this_tree.add('file', b'file-id')
462
 
        this_tree.commit('rev1', rev_id=b'rev1')
463
 
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
464
 
        self.build_tree_contents([('this/file', b'1\n2a\n')])
465
 
        this_tree.commit('rev2', rev_id=b'rev2a')
466
 
        self.build_tree_contents([('other/file', b'2b\n1\n')])
467
 
        other_tree.commit('rev2', rev_id=b'rev2b')
 
458
        self.build_tree_contents([('this/file', '1\n')])
 
459
        this_tree.add('file', 'file-id')
 
460
        this_tree.commit('rev1', rev_id='rev1')
 
461
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
462
        self.build_tree_contents([('this/file', '1\n2a\n')])
 
463
        this_tree.commit('rev2', rev_id='rev2a')
 
464
        self.build_tree_contents([('other/file', '2b\n1\n')])
 
465
        other_tree.commit('rev2', rev_id='rev2b')
468
466
        this_tree.lock_write()
469
467
        self.addCleanup(this_tree.unlock)
470
 
        merger = _mod_merge.Merger.from_revision_ids(
471
 
            this_tree, b'rev2b', other_branch=other_tree.branch)
 
468
        merger = _mod_merge.Merger.from_revision_ids(None,
 
469
            this_tree, 'rev2b', other_branch=other_tree.branch)
472
470
        merger.merge_type = _mod_merge.Merge3Merger
473
471
        tree_merger = merger.make_merger()
474
472
        tt = tree_merger.make_preview_transform()
475
473
        self.addCleanup(tt.finalize)
476
474
        preview_tree = tt.get_preview_tree()
477
 
        tree_file = this_tree.get_file('file')
 
475
        tree_file = this_tree.get_file('file-id')
478
476
        try:
479
477
            self.assertEqual('1\n2a\n', tree_file.read())
480
478
        finally:
481
479
            tree_file.close()
482
 
        preview_file = preview_tree.get_file('file')
 
480
        preview_file = preview_tree.get_file('file-id')
483
481
        try:
484
482
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
485
483
        finally:
487
485
 
488
486
    def test_do_merge(self):
489
487
        this_tree = self.make_branch_and_tree('this')
490
 
        self.build_tree_contents([('this/file', b'1\n')])
491
 
        this_tree.add('file', b'file-id')
492
 
        this_tree.commit('rev1', rev_id=b'rev1')
493
 
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
494
 
        self.build_tree_contents([('this/file', b'1\n2a\n')])
495
 
        this_tree.commit('rev2', rev_id=b'rev2a')
496
 
        self.build_tree_contents([('other/file', b'2b\n1\n')])
497
 
        other_tree.commit('rev2', rev_id=b'rev2b')
 
488
        self.build_tree_contents([('this/file', '1\n')])
 
489
        this_tree.add('file', 'file-id')
 
490
        this_tree.commit('rev1', rev_id='rev1')
 
491
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
492
        self.build_tree_contents([('this/file', '1\n2a\n')])
 
493
        this_tree.commit('rev2', rev_id='rev2a')
 
494
        self.build_tree_contents([('other/file', '2b\n1\n')])
 
495
        other_tree.commit('rev2', rev_id='rev2b')
498
496
        this_tree.lock_write()
499
497
        self.addCleanup(this_tree.unlock)
500
 
        merger = _mod_merge.Merger.from_revision_ids(
501
 
            this_tree, b'rev2b', other_branch=other_tree.branch)
 
498
        merger = _mod_merge.Merger.from_revision_ids(None,
 
499
            this_tree, 'rev2b', other_branch=other_tree.branch)
502
500
        merger.merge_type = _mod_merge.Merge3Merger
503
501
        tree_merger = merger.make_merger()
504
502
        tt = tree_merger.do_merge()
505
 
        tree_file = this_tree.get_file('file')
 
503
        tree_file = this_tree.get_file('file-id')
506
504
        try:
507
505
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
508
506
        finally:
516
514
        tree.add('a')
517
515
        first_rev = tree.commit("added a")
518
516
        old_root_id = tree.get_root_id()
519
 
        merger = _mod_merge.Merger.from_revision_ids(tree,
 
517
        merger = _mod_merge.Merger.from_revision_ids(None, tree,
520
518
                                          _mod_revision.NULL_REVISION,
521
519
                                          first_rev)
522
520
        merger.merge_type = _mod_merge.Merge3Merger
523
521
        conflict_count = merger.do_merge()
524
522
        self.assertEqual(0, conflict_count)
525
 
        self.assertEqual({''}, set(tree.all_versioned_paths()))
 
523
        self.assertEquals(set([old_root_id]), tree.all_file_ids())
526
524
        tree.set_parent_ids([])
527
525
 
528
526
    def test_merge_add_into_deleted_root(self):
529
527
        # Yes, people actually do this.  And report bugs if it breaks.
530
528
        source = self.make_branch_and_tree('source', format='rich-root-pack')
531
529
        self.build_tree(['source/foo/'])
532
 
        source.add('foo', b'foo-id')
 
530
        source.add('foo', 'foo-id')
533
531
        source.commit('Add foo')
534
 
        target = source.controldir.sprout('target').open_workingtree()
535
 
        subtree = target.extract('foo', b'foo-id')
 
532
        target = source.bzrdir.sprout('target').open_workingtree()
 
533
        subtree = target.extract('foo-id')
536
534
        subtree.commit('Delete root')
537
535
        self.build_tree(['source/bar'])
538
 
        source.add('bar', b'bar-id')
 
536
        source.add('bar', 'bar-id')
539
537
        source.commit('Add bar')
540
538
        subtree.merge_from_branch(source.branch)
541
539
 
548
546
        self.build_tree(['target/bla'])
549
547
        target.add('bla')
550
548
        target.commit('Add bla')
551
 
        nested = source.controldir.sprout('target/subtree').open_workingtree()
 
549
        nested = source.bzrdir.sprout('target/subtree').open_workingtree()
552
550
        target.subsume(nested)
553
551
        target.commit('Join nested')
554
552
        self.build_tree(['source/bar'])
1047
1045
 
1048
1046
    def assertPruneTails(self, pruned_map, tails, parent_map):
1049
1047
        child_map = {}
1050
 
        for key, parent_keys in parent_map.items():
 
1048
        for key, parent_keys in parent_map.iteritems():
1051
1049
            child_map.setdefault(key, [])
1052
1050
            for pkey in parent_keys:
1053
1051
                child_map.setdefault(pkey, []).append(key)
1243
1241
        #  B C
1244
1242
        #
1245
1243
        builder = self.get_builder()
1246
 
        builder.build_snapshot(None,
1247
 
            [('add', ('', None, 'directory', None))],
1248
 
            revision_id='A-id' )
1249
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1250
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
 
1244
        builder.build_snapshot('A-id', None,
 
1245
            [('add', ('', None, 'directory', None))])
 
1246
        builder.build_snapshot('C-id', ['A-id'], [])
 
1247
        builder.build_snapshot('B-id', ['A-id'], [])
1251
1248
        return builder
1252
1249
 
1253
1250
    def setup_criss_cross_graph(self):
1261
1258
        # |X|
1262
1259
        # D E
1263
1260
        builder = self.setup_simple_graph()
1264
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1265
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1261
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1262
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1266
1263
        return builder
1267
1264
 
1268
 
    def make_Merger(self, builder, other_revision_id, interesting_files=None):
 
1265
    def make_Merger(self, builder, other_revision_id,
 
1266
                    interesting_files=None, interesting_ids=None):
1269
1267
        """Make a Merger object from a branch builder"""
1270
1268
        mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1271
1269
        mem_tree.lock_write()
1272
1270
        self.addCleanup(mem_tree.unlock)
1273
 
        merger = _mod_merge.Merger.from_revision_ids(
 
1271
        merger = _mod_merge.Merger.from_revision_ids(None,
1274
1272
            mem_tree, other_revision_id)
1275
1273
        merger.set_interesting_files(interesting_files)
 
1274
        # It seems there is no matching function for set_interesting_ids
 
1275
        merger.interesting_ids = interesting_ids
1276
1276
        merger.merge_type = _mod_merge.Merge3Merger
1277
1277
        return merger
1278
1278
 
1314
1314
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1315
1315
                                            for t in merger._lca_trees])
1316
1316
        # If we swap the order, we should get a different lca order
1317
 
        builder.build_snapshot(['E-id'], [], revision_id='F-id')
 
1317
        builder.build_snapshot('F-id', ['E-id'], [])
1318
1318
        merger = self.make_Merger(builder, 'D-id')
1319
1319
        self.assertEqual(['C-id', 'B-id'], [t.get_revision_id()
1320
1320
                                            for t in merger._lca_trees])
1330
1330
        #    \|   |/
1331
1331
        #     G   H
1332
1332
        builder = self.setup_criss_cross_graph()
1333
 
        builder.build_snapshot(['A-id'], [], revision_id='F-id')
1334
 
        builder.build_snapshot(['E-id', 'F-id'], [], revision_id='H-id')
1335
 
        builder.build_snapshot(['D-id', 'F-id'], [], revision_id='G-id')
 
1333
        builder.build_snapshot('F-id', ['A-id'], [])
 
1334
        builder.build_snapshot('H-id', ['E-id', 'F-id'], [])
 
1335
        builder.build_snapshot('G-id', ['D-id', 'F-id'], [])
1336
1336
        merger = self.make_Merger(builder, 'H-id')
1337
1337
        self.assertEqual(['B-id', 'C-id', 'F-id'],
1338
1338
                         [t.get_revision_id() for t in merger._lca_trees])
1343
1343
        # | X |
1344
1344
        # |/ \|
1345
1345
        # C   D
 
1346
        
1346
1347
        builder = self.get_builder()
1347
 
        builder.build_snapshot(None,
1348
 
            [('add', ('', None, 'directory', None))],
1349
 
            revision_id='A-id')
1350
 
        builder.build_snapshot([],
1351
 
            [('add', ('', None, 'directory', None))],
1352
 
            revision_id='B-id')
1353
 
        builder.build_snapshot(['A-id', 'B-id'], [], revision_id='D-id')
1354
 
        builder.build_snapshot(['A-id', 'B-id'], [], revision_id='C-id')
 
1348
        builder.build_snapshot('A-id', None,
 
1349
            [('add', ('', None, 'directory', None))])
 
1350
        builder.build_snapshot('B-id', [],
 
1351
            [('add', ('', None, 'directory', None))])
 
1352
        builder.build_snapshot('D-id', ['A-id', 'B-id'], [])
 
1353
        builder.build_snapshot('C-id', ['A-id', 'B-id'], [])
1355
1354
        merger = self.make_Merger(builder, 'D-id')
1356
1355
        self.assertEqual('A-id', merger.base_rev_id)
1357
1356
        self.assertTrue(merger._is_criss_cross)
1397
1396
class TestMergerEntriesLCA(TestMergerBase):
1398
1397
 
1399
1398
    def make_merge_obj(self, builder, other_revision_id,
1400
 
                       interesting_files=None):
 
1399
                       interesting_files=None, interesting_ids=None):
1401
1400
        merger = self.make_Merger(builder, other_revision_id,
1402
 
            interesting_files=interesting_files)
 
1401
            interesting_files=interesting_files,
 
1402
            interesting_ids=interesting_ids)
1403
1403
        return merger.make_merger()
1404
1404
 
1405
1405
    def test_simple(self):
1406
1406
        builder = self.get_builder()
1407
 
        builder.build_snapshot(None,
 
1407
        builder.build_snapshot('A-id', None,
1408
1408
            [('add', (u'', 'a-root-id', 'directory', None)),
1409
 
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1410
 
            revision_id='A-id')
1411
 
        builder.build_snapshot(['A-id'],
1412
 
            [('modify', ('a', 'a\nb\nC\nc\n'))],
1413
 
            revision_id='C-id')
1414
 
        builder.build_snapshot(['A-id'],
1415
 
            [('modify', ('a', 'a\nB\nb\nc\n'))],
1416
 
            revision_id='B-id')
1417
 
        builder.build_snapshot(['C-id', 'B-id'],
1418
 
            [('modify', ('a', 'a\nB\nb\nC\nc\nE\n'))],
1419
 
            revision_id='E-id')
1420
 
        builder.build_snapshot(['B-id', 'C-id'],
1421
 
            [('modify', ('a', 'a\nB\nb\nC\nc\n'))],
1422
 
            revision_id='D-id', )
 
1409
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1410
        builder.build_snapshot('C-id', ['A-id'],
 
1411
            [('modify', ('a-id', 'a\nb\nC\nc\n'))])
 
1412
        builder.build_snapshot('B-id', ['A-id'],
 
1413
            [('modify', ('a-id', 'a\nB\nb\nc\n'))])
 
1414
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1415
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))])
 
1416
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1417
            [('modify', ('a-id', 'a\nB\nb\nC\nc\n'))])
1423
1418
        merge_obj = self.make_merge_obj(builder, 'E-id')
1424
1419
 
1425
1420
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1431
1426
        # BASE, lca1, lca2, OTHER, THIS
1432
1427
        root_id = 'a-root-id'
1433
1428
        self.assertEqual([('a-id', True,
1434
 
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1435
1429
                           ((root_id, [root_id, root_id]), root_id, root_id),
1436
1430
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1437
1431
                           ((False, [False, False]), False, False)),
1450
1444
        #            G modifies 'bar'
1451
1445
 
1452
1446
        builder = self.get_builder()
1453
 
        builder.build_snapshot(None,
1454
 
            [('add', (u'', 'a-root-id', 'directory', None))],
1455
 
            revision_id='A-id')
1456
 
        builder.build_snapshot(['A-id'],
1457
 
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
1458
 
            revision_id='B-id')
1459
 
        builder.build_snapshot(['A-id'],
1460
 
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))],
1461
 
            revision_id='C-id')
1462
 
        builder.build_snapshot(['B-id', 'C-id'],
1463
 
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))],
1464
 
            revision_id='D-id')
1465
 
        builder.build_snapshot(['C-id', 'B-id'],
1466
 
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
1467
 
            revision_id='E-id')
1468
 
        builder.build_snapshot(['E-id', 'D-id'],
1469
 
            [('modify', (u'bar', 'd\ne\nf\nG\n'))],
1470
 
            revision_id='G-id')
1471
 
        builder.build_snapshot(['D-id', 'E-id'], [], revision_id='F-id')
 
1447
        builder.build_snapshot('A-id', None,
 
1448
            [('add', (u'', 'a-root-id', 'directory', None))])
 
1449
        builder.build_snapshot('B-id', ['A-id'],
 
1450
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
1451
        builder.build_snapshot('C-id', ['A-id'],
 
1452
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))])
 
1453
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1454
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))])
 
1455
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1456
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
1457
        builder.build_snapshot('G-id', ['E-id', 'D-id'],
 
1458
            [('modify', (u'bar-id', 'd\ne\nf\nG\n'))])
 
1459
        builder.build_snapshot('F-id', ['D-id', 'E-id'], [])
1472
1460
        merge_obj = self.make_merge_obj(builder, 'G-id')
1473
1461
 
1474
1462
        self.assertEqual(['D-id', 'E-id'], [t.get_revision_id()
1477
1465
        entries = list(merge_obj._entries_lca())
1478
1466
        root_id = 'a-root-id'
1479
1467
        self.assertEqual([('bar-id', True,
1480
 
                           ((None, [u'bar', u'bar']), u'bar', u'bar'),
1481
1468
                           ((None, [root_id, root_id]), root_id, root_id),
1482
1469
                           ((None, [u'bar', u'bar']), u'bar', u'bar'),
1483
1470
                           ((None, [False, False]), False, False)),
1485
1472
 
1486
1473
    def test_not_in_this(self):
1487
1474
        builder = self.get_builder()
1488
 
        builder.build_snapshot(None,
 
1475
        builder.build_snapshot('A-id', None,
1489
1476
            [('add', (u'', 'a-root-id', 'directory', None)),
1490
 
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1491
 
            revision_id='A-id')
1492
 
        builder.build_snapshot(['A-id'],
1493
 
            [('modify', ('a', 'a\nB\nb\nc\n'))],
1494
 
            revision_id='B-id')
1495
 
        builder.build_snapshot(['A-id'],
1496
 
            [('modify', ('a', 'a\nb\nC\nc\n'))],
1497
 
            revision_id='C-id')
1498
 
        builder.build_snapshot(['C-id', 'B-id'],
1499
 
            [('modify', ('a', 'a\nB\nb\nC\nc\nE\n'))],
1500
 
            revision_id='E-id')
1501
 
        builder.build_snapshot(['B-id', 'C-id'],
1502
 
            [('unversion', 'a')],
1503
 
            revision_id='D-id')
 
1477
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1478
        builder.build_snapshot('B-id', ['A-id'],
 
1479
            [('modify', ('a-id', 'a\nB\nb\nc\n'))])
 
1480
        builder.build_snapshot('C-id', ['A-id'],
 
1481
            [('modify', ('a-id', 'a\nb\nC\nc\n'))])
 
1482
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1483
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))])
 
1484
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1485
            [('unversion', 'a-id')])
1504
1486
        merge_obj = self.make_merge_obj(builder, 'E-id')
1505
1487
 
1506
1488
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1510
1492
        entries = list(merge_obj._entries_lca())
1511
1493
        root_id = 'a-root-id'
1512
1494
        self.assertEqual([('a-id', True,
1513
 
                           ((u'a', [u'a', u'a']), u'a', None),
1514
1495
                           ((root_id, [root_id, root_id]), root_id, None),
1515
1496
                           ((u'a', [u'a', u'a']), u'a', None),
1516
1497
                           ((False, [False, False]), False, None)),
1523
1504
        #   |X|
1524
1505
        #   D E # D and E both have the file, unchanged from C
1525
1506
        builder = self.get_builder()
1526
 
        builder.build_snapshot(None,
1527
 
            [('add', (u'', 'a-root-id', 'directory', None))],
1528
 
            revision_id='A-id')
1529
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1530
 
        builder.build_snapshot(['A-id'],
1531
 
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1532
 
            revision_id='C-id')
1533
 
        builder.build_snapshot(['C-id', 'B-id'],
1534
 
                               [], revision_id='E-id') # Inherited from C
1535
 
        builder.build_snapshot(['B-id', 'C-id'], # Merged from C
1536
 
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1537
 
            revision_id='D-id')
 
1507
        builder.build_snapshot('A-id', None,
 
1508
            [('add', (u'', 'a-root-id', 'directory', None))])
 
1509
        builder.build_snapshot('B-id', ['A-id'], [])
 
1510
        builder.build_snapshot('C-id', ['A-id'],
 
1511
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1512
        builder.build_snapshot('E-id', ['C-id', 'B-id'], []) # Inherited from C
 
1513
        builder.build_snapshot('D-id', ['B-id', 'C-id'], # Merged from C
 
1514
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1538
1515
        merge_obj = self.make_merge_obj(builder, 'E-id')
1539
1516
 
1540
1517
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1546
1523
 
1547
1524
    def test_not_in_other(self):
1548
1525
        builder = self.get_builder()
1549
 
        builder.build_snapshot(None,
 
1526
        builder.build_snapshot('A-id', None,
1550
1527
            [('add', (u'', 'a-root-id', 'directory', None)),
1551
 
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1552
 
            revision_id='A-id')
1553
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1554
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1555
 
        builder.build_snapshot(
1556
 
                ['C-id', 'B-id'],
1557
 
                [('unversion', 'a')], revision_id='E-id')
1558
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1528
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1529
        builder.build_snapshot('B-id', ['A-id'], [])
 
1530
        builder.build_snapshot('C-id', ['A-id'], [])
 
1531
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1532
            [('unversion', 'a-id')])
 
1533
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1559
1534
        merge_obj = self.make_merge_obj(builder, 'E-id')
1560
1535
 
1561
1536
        entries = list(merge_obj._entries_lca())
1562
1537
        root_id = 'a-root-id'
1563
1538
        self.assertEqual([('a-id', True,
1564
 
                           ((u'a', [u'a', u'a']), None, u'a'),
1565
1539
                           ((root_id, [root_id, root_id]), None, root_id),
1566
1540
                           ((u'a', [u'a', u'a']), None, u'a'),
1567
1541
                           ((False, [False, False]), None, False)),
1580
1554
        #   C => E, no changes
1581
1555
        # D would then win 'cleanly' and no record would be given
1582
1556
        builder = self.get_builder()
1583
 
        builder.build_snapshot(None,
 
1557
        builder.build_snapshot('A-id', None,
1584
1558
            [('add', (u'', 'a-root-id', 'directory', None)),
1585
 
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))],
1586
 
            revision_id='A-id')
1587
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1588
 
        builder.build_snapshot(['A-id'],
1589
 
            [('unversion', 'foo')], revision_id='C-id')
1590
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1591
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1559
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))])
 
1560
        builder.build_snapshot('B-id', ['A-id'], [])
 
1561
        builder.build_snapshot('C-id', ['A-id'],
 
1562
            [('unversion', 'foo-id')])
 
1563
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1564
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1592
1565
        merge_obj = self.make_merge_obj(builder, 'E-id')
1593
1566
 
1594
1567
        entries = list(merge_obj._entries_lca())
1610
1583
        # In this case, we have a conflict of how the changes were resolved. E
1611
1584
        # picked C and D picked B, so we should issue a conflict
1612
1585
        builder = self.get_builder()
1613
 
        builder.build_snapshot(None,
 
1586
        builder.build_snapshot('A-id', None,
1614
1587
            [('add', (u'', 'a-root-id', 'directory', None)),
1615
 
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))],
1616
 
            revision_id='A-id')
1617
 
        builder.build_snapshot(['A-id'], [
1618
 
            ('modify', ('foo', 'new-content\n'))],
1619
 
            revision_id='B-id')
1620
 
        builder.build_snapshot(['A-id'],
1621
 
            [('unversion', 'foo')],
1622
 
            revision_id='C-id')
1623
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1624
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1588
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))])
 
1589
        builder.build_snapshot('B-id', ['A-id'], [
 
1590
            ('modify', ('foo-id', 'new-content\n'))])
 
1591
        builder.build_snapshot('C-id', ['A-id'],
 
1592
            [('unversion', 'foo-id')])
 
1593
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1594
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1625
1595
        merge_obj = self.make_merge_obj(builder, 'E-id')
1626
1596
 
1627
1597
        entries = list(merge_obj._entries_lca())
1628
1598
        root_id = 'a-root-id'
1629
1599
        self.assertEqual([('foo-id', True,
1630
 
                           ((u'foo', [u'foo', None]), None, u'foo'),
1631
1600
                           ((root_id, [root_id, None]), None, root_id),
1632
1601
                           ((u'foo', [u'foo', None]), None, 'foo'),
1633
1602
                           ((False, [False, None]), None, False)),
1650
1619
        #   A => C, add file, thus C supersedes B
1651
1620
        #   w/ C=BASE, D=THIS, E=OTHER we have 'happy convergence'
1652
1621
        builder = self.get_builder()
1653
 
        builder.build_snapshot(None,
1654
 
            [('add', (u'', 'a-root-id', 'directory', None))],
1655
 
            revision_id='A-id')
1656
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1657
 
        builder.build_snapshot(['A-id'],
1658
 
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1659
 
            revision_id='C-id')
1660
 
        builder.build_snapshot(['C-id', 'B-id'],
1661
 
            [('unversion', 'a')],
1662
 
            revision_id='E-id')
1663
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1622
        builder.build_snapshot('A-id', None,
 
1623
            [('add', (u'', 'a-root-id', 'directory', None))])
 
1624
        builder.build_snapshot('B-id', ['A-id'], [])
 
1625
        builder.build_snapshot('C-id', ['A-id'],
 
1626
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1627
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1628
            [('unversion', 'a-id')])
 
1629
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1664
1630
        merge_obj = self.make_merge_obj(builder, 'E-id')
1665
1631
 
1666
1632
        entries = list(merge_obj._entries_lca())
1668
1634
 
1669
1635
    def test_only_in_other(self):
1670
1636
        builder = self.get_builder()
1671
 
        builder.build_snapshot(None,
1672
 
            [('add', (u'', 'a-root-id', 'directory', None))],
1673
 
            revision_id='A-id')
1674
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1675
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1676
 
        builder.build_snapshot(['C-id', 'B-id'],
1677
 
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1678
 
            revision_id='E-id')
1679
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1637
        builder.build_snapshot('A-id', None,
 
1638
            [('add', (u'', 'a-root-id', 'directory', None))])
 
1639
        builder.build_snapshot('B-id', ['A-id'], [])
 
1640
        builder.build_snapshot('C-id', ['A-id'], [])
 
1641
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1642
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
1643
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1680
1644
        merge_obj = self.make_merge_obj(builder, 'E-id')
1681
1645
 
1682
1646
        entries = list(merge_obj._entries_lca())
1683
1647
        root_id = 'a-root-id'
1684
1648
        self.assertEqual([('a-id', True,
1685
 
                           ((None, [None, None]), u'a', None),
1686
1649
                           ((None, [None, None]), root_id, None),
1687
1650
                           ((None, [None, None]), u'a', None),
1688
1651
                           ((None, [None, None]), False, None)),
1703
1666
        #   though its LCAs disagree. This is because the modification in E
1704
1667
        #   completely supersedes the value in D.
1705
1668
        builder = self.get_builder()
1706
 
        builder.build_snapshot(None,
 
1669
        builder.build_snapshot('A-id', None,
1707
1670
            [('add', (u'', 'a-root-id', 'directory', None)),
1708
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1709
 
            revision_id='A-id')
1710
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1711
 
        builder.build_snapshot(['A-id'],
1712
 
            [('modify', ('foo', 'B content\n'))],
1713
 
            revision_id='B-id')
1714
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1715
 
        builder.build_snapshot(['C-id', 'B-id'],
1716
 
            [('modify', ('foo', 'E content\n'))],
1717
 
            revision_id='E-id')
1718
 
        builder.build_snapshot(['E-id', 'D-id'], [], revision_id='G-id')
1719
 
        builder.build_snapshot(['D-id', 'E-id'],
1720
 
            [('modify', ('foo', 'F content\n'))],
1721
 
            revision_id='F-id')
 
1671
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1672
        builder.build_snapshot('C-id', ['A-id'], [])
 
1673
        builder.build_snapshot('B-id', ['A-id'],
 
1674
            [('modify', ('foo-id', 'B content\n'))])
 
1675
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
1676
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1677
            [('modify', ('foo-id', 'E content\n'))])
 
1678
        builder.build_snapshot('G-id', ['E-id', 'D-id'], [])
 
1679
        builder.build_snapshot('F-id', ['D-id', 'E-id'],
 
1680
            [('modify', ('foo-id', 'F content\n'))])
1722
1681
        merge_obj = self.make_merge_obj(builder, 'G-id')
1723
1682
 
1724
1683
        self.assertEqual([], list(merge_obj._entries_lca()))
1753
1712
        # aren't supporting it yet.
1754
1713
        #
1755
1714
        builder = self.get_builder()
1756
 
        builder.build_snapshot(None,
 
1715
        builder.build_snapshot('A-id', None,
1757
1716
            [('add', (u'', 'a-root-id', 'directory', None)),
1758
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1759
 
            revision_id='A-id')
1760
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1761
 
        builder.build_snapshot(['A-id'],
1762
 
            [('rename', ('foo', 'bar'))],
1763
 
            revision_id='B-id')
1764
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1765
 
        builder.build_snapshot(['C-id', 'B-id'],
1766
 
            [('rename', ('foo', 'bing'))],
1767
 
            revision_id='E-id') # override to bing
1768
 
        builder.build_snapshot(['E-id', 'D-id'],
1769
 
            [('rename', ('bing', 'barry'))],
1770
 
            revision_id='G-id') # override to barry
1771
 
        builder.build_snapshot(['D-id', 'E-id'],
1772
 
            [('rename', ('bar', 'bing'))],
1773
 
            revision_id='F-id') # Merge in E's change
 
1717
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1718
        builder.build_snapshot('C-id', ['A-id'], [])
 
1719
        builder.build_snapshot('B-id', ['A-id'],
 
1720
            [('rename', ('foo', 'bar'))])
 
1721
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
1722
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1723
            [('rename', ('foo', 'bing'))]) # override to bing
 
1724
        builder.build_snapshot('G-id', ['E-id', 'D-id'],
 
1725
            [('rename', ('bing', 'barry'))]) # override to barry
 
1726
        builder.build_snapshot('F-id', ['D-id', 'E-id'],
 
1727
            [('rename', ('bar', 'bing'))]) # Merge in E's change
1774
1728
        merge_obj = self.make_merge_obj(builder, 'G-id')
1775
1729
 
1776
1730
        self.expectFailure("We don't do an actual heads() check on lca values,"
1791
1745
        # be pruned from the LCAs, even though it was newly introduced by E
1792
1746
        # (superseding B).
1793
1747
        builder = self.get_builder()
1794
 
        builder.build_snapshot(None,
 
1748
        builder.build_snapshot('A-id', None,
1795
1749
            [('add', (u'', 'a-root-id', 'directory', None)),
1796
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1797
 
            revision_id='A-id')
1798
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1799
 
        builder.build_snapshot(['A-id'],
1800
 
            [('rename', ('foo', 'bar'))],
1801
 
            revision_id='B-id')
1802
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1803
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1804
 
        builder.build_snapshot(['E-id', 'D-id'],
1805
 
            [('rename', ('foo', 'bar'))],
1806
 
            revision_id='G-id')
1807
 
        builder.build_snapshot(['D-id', 'E-id'],
1808
 
            [('rename', ('bar', 'bing'))],
1809
 
            revision_id='F-id') # should end up conflicting
 
1750
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1751
        builder.build_snapshot('C-id', ['A-id'], [])
 
1752
        builder.build_snapshot('B-id', ['A-id'],
 
1753
            [('rename', ('foo', 'bar'))])
 
1754
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
1755
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1756
        builder.build_snapshot('G-id', ['E-id', 'D-id'],
 
1757
            [('rename', ('foo', 'bar'))])
 
1758
        builder.build_snapshot('F-id', ['D-id', 'E-id'],
 
1759
            [('rename', ('bar', 'bing'))]) # should end up conflicting
1810
1760
        merge_obj = self.make_merge_obj(builder, 'G-id')
1811
1761
 
1812
1762
        entries = list(merge_obj._entries_lca())
1828
1778
        #       D E  D reverts to B, E reverts to C
1829
1779
        # This should conflict
1830
1780
        builder = self.get_builder()
1831
 
        builder.build_snapshot(None,
 
1781
        builder.build_snapshot('A-id', None,
1832
1782
            [('add', (u'', 'a-root-id', 'directory', None)),
1833
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1834
 
            revision_id='A-id')
1835
 
        builder.build_snapshot(['A-id'],
1836
 
            [('modify', ('foo', 'B content\n'))],
1837
 
            revision_id='B-id')
1838
 
        builder.build_snapshot(['A-id'],
1839
 
            [('modify', ('foo', 'C content\n'))],
1840
 
            revision_id='C-id')
1841
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1842
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1783
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1784
        builder.build_snapshot('B-id', ['A-id'],
 
1785
            [('modify', ('foo-id', 'B content\n'))])
 
1786
        builder.build_snapshot('C-id', ['A-id'],
 
1787
            [('modify', ('foo-id', 'C content\n'))])
 
1788
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1789
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1843
1790
        merge_obj = self.make_merge_obj(builder, 'E-id')
1844
1791
 
1845
1792
        entries = list(merge_obj._entries_lca())
1846
1793
        root_id = 'a-root-id'
1847
1794
        self.assertEqual([('foo-id', True,
1848
 
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1849
1795
                           ((root_id, [root_id, root_id]), root_id, root_id),
1850
1796
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1851
1797
                           ((False, [False, False]), False, False)),
1863
1809
        # We need to emit an entry for 'foo', because D & E differed on the
1864
1810
        # merge resolution
1865
1811
        builder = self.get_builder()
1866
 
        builder.build_snapshot(None,
 
1812
        builder.build_snapshot('A-id', None,
1867
1813
            [('add', (u'', 'a-root-id', 'directory', None)),
1868
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1869
 
            revision_id='A-id')
1870
 
        builder.build_snapshot(['A-id'],
1871
 
            [('modify', ('foo', 'B content\n'))],
1872
 
            revision_id='B-id')
1873
 
        builder.build_snapshot(['A-id'],
1874
 
            [('modify', ('foo', 'C content\n'))],
1875
 
            revision_id='C-id', )
1876
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1877
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1878
 
        builder.build_snapshot(['D-id'],
1879
 
            [('modify', ('foo', 'F content\n'))],
1880
 
            revision_id='F-id')
 
1814
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1815
        builder.build_snapshot('B-id', ['A-id'],
 
1816
            [('modify', ('foo-id', 'B content\n'))])
 
1817
        builder.build_snapshot('C-id', ['A-id'],
 
1818
            [('modify', ('foo-id', 'C content\n'))])
 
1819
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1820
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
1821
        builder.build_snapshot('F-id', ['D-id'],
 
1822
            [('modify', ('foo-id', 'F content\n'))])
1881
1823
        merge_obj = self.make_merge_obj(builder, 'E-id')
1882
1824
 
1883
1825
        entries = list(merge_obj._entries_lca())
1884
1826
        root_id = 'a-root-id'
1885
1827
        self.assertEqual([('foo-id', True,
1886
 
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1887
1828
                           ((root_id, [root_id, root_id]), root_id, root_id),
1888
1829
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1889
1830
                           ((False, [False, False]), False, False)),
1904
1845
        # We need to conflict.
1905
1846
 
1906
1847
        builder = self.get_builder()
1907
 
        builder.build_snapshot(None,
 
1848
        builder.build_snapshot('A-id', None,
1908
1849
            [('add', (u'', 'a-root-id', 'directory', None)),
1909
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1910
 
            revision_id='A-id')
1911
 
        builder.build_snapshot(['A-id'],
1912
 
            [('modify', ('foo', 'B content\n'))],
1913
 
            revision_id='B-id')
1914
 
        builder.build_snapshot(['A-id'],
1915
 
            [('modify', ('foo', 'C content\n'))],
1916
 
            revision_id='C-id')
1917
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1918
 
        builder.build_snapshot(['B-id', 'C-id'],
1919
 
            [('modify', ('foo', 'C content\n'))],
1920
 
            revision_id='D-id') # Same as E
1921
 
        builder.build_snapshot(['D-id'],
1922
 
            [('modify', ('foo', 'F content\n'))],
1923
 
            revision_id='F-id')
 
1850
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
1851
        builder.build_snapshot('B-id', ['A-id'],
 
1852
            [('modify', ('foo-id', 'B content\n'))])
 
1853
        builder.build_snapshot('C-id', ['A-id'],
 
1854
            [('modify', ('foo-id', 'C content\n'))])
 
1855
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1856
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1857
            [('modify', ('foo-id', 'C content\n'))]) # Same as E
 
1858
        builder.build_snapshot('F-id', ['D-id'],
 
1859
            [('modify', ('foo-id', 'F content\n'))])
1924
1860
        merge_obj = self.make_merge_obj(builder, 'E-id')
1925
1861
 
1926
1862
        entries = list(merge_obj._entries_lca())
1930
1866
 
1931
1867
    def test_only_path_changed(self):
1932
1868
        builder = self.get_builder()
1933
 
        builder.build_snapshot(None,
 
1869
        builder.build_snapshot('A-id', None,
1934
1870
            [('add', (u'', 'a-root-id', 'directory', None)),
1935
 
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1936
 
            revision_id='A-id')
1937
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1938
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1939
 
        builder.build_snapshot(['C-id', 'B-id'],
1940
 
            [('rename', (u'a', u'b'))],
1941
 
            revision_id='E-id')
1942
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1871
             ('add', (u'a', 'a-id', 'file', 'content\n'))])
 
1872
        builder.build_snapshot('B-id', ['A-id'], [])
 
1873
        builder.build_snapshot('C-id', ['A-id'], [])
 
1874
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1875
            [('rename', (u'a', u'b'))])
 
1876
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1943
1877
        merge_obj = self.make_merge_obj(builder, 'E-id')
1944
1878
        entries = list(merge_obj._entries_lca())
1945
1879
        root_id = 'a-root-id'
1946
1880
        # The content was not changed, only the path
1947
1881
        self.assertEqual([('a-id', False,
1948
 
                           ((u'a', [u'a', u'a']), u'b', u'a'),
1949
1882
                           ((root_id, [root_id, root_id]), root_id, root_id),
1950
1883
                           ((u'a', [u'a', u'a']), u'b', u'a'),
1951
1884
                           ((False, [False, False]), False, False)),
1954
1887
    def test_kind_changed(self):
1955
1888
        # Identical content, except 'D' changes a-id into a directory
1956
1889
        builder = self.get_builder()
1957
 
        builder.build_snapshot(None,
 
1890
        builder.build_snapshot('A-id', None,
1958
1891
            [('add', (u'', 'a-root-id', 'directory', None)),
1959
 
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1960
 
            revision_id='A-id')
1961
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1962
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1963
 
        builder.build_snapshot(['C-id', 'B-id'],
1964
 
            [('unversion', 'a'),
 
1892
             ('add', (u'a', 'a-id', 'file', 'content\n'))])
 
1893
        builder.build_snapshot('B-id', ['A-id'], [])
 
1894
        builder.build_snapshot('C-id', ['A-id'], [])
 
1895
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1896
            [('unversion', 'a-id'),
1965
1897
             ('flush', None),
1966
 
             ('add', (u'a', 'a-id', 'directory', None))],
1967
 
            revision_id='E-id')
1968
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1898
             ('add', (u'a', 'a-id', 'directory', None))])
 
1899
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1969
1900
        merge_obj = self.make_merge_obj(builder, 'E-id')
1970
1901
        entries = list(merge_obj._entries_lca())
1971
1902
        root_id = 'a-root-id'
1972
1903
        # Only the kind was changed (content)
1973
1904
        self.assertEqual([('a-id', True,
1974
 
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1975
1905
                           ((root_id, [root_id, root_id]), root_id, root_id),
1976
1906
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1977
1907
                           ((False, [False, False]), False, False)),
1980
1910
    def test_this_changed_kind(self):
1981
1911
        # Identical content, but THIS changes a file to a directory
1982
1912
        builder = self.get_builder()
1983
 
        builder.build_snapshot(None,
 
1913
        builder.build_snapshot('A-id', None,
1984
1914
            [('add', (u'', 'a-root-id', 'directory', None)),
1985
 
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1986
 
            revision_id='A-id')
1987
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1988
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1989
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1990
 
        builder.build_snapshot(['B-id', 'C-id'],
1991
 
            [('unversion', 'a'),
 
1915
             ('add', (u'a', 'a-id', 'file', 'content\n'))])
 
1916
        builder.build_snapshot('B-id', ['A-id'], [])
 
1917
        builder.build_snapshot('C-id', ['A-id'], [])
 
1918
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
1919
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1920
            [('unversion', 'a-id'),
1992
1921
             ('flush', None),
1993
 
             ('add', (u'a', 'a-id', 'directory', None))],
1994
 
            revision_id='D-id')
 
1922
             ('add', (u'a', 'a-id', 'directory', None))])
1995
1923
        merge_obj = self.make_merge_obj(builder, 'E-id')
1996
1924
        entries = list(merge_obj._entries_lca())
1997
1925
        # Only the kind was changed (content)
2000
1928
    def test_interesting_files(self):
2001
1929
        # Two files modified, but we should filter one of them
2002
1930
        builder = self.get_builder()
2003
 
        builder.build_snapshot(None,
 
1931
        builder.build_snapshot('A-id', None,
2004
1932
            [('add', (u'', 'a-root-id', 'directory', None)),
2005
1933
             ('add', (u'a', 'a-id', 'file', 'content\n')),
2006
 
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2007
 
            revision_id='A-id')
2008
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2009
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2010
 
        builder.build_snapshot(['C-id', 'B-id'],
2011
 
            [('modify', ('a', 'new-content\n')),
2012
 
             ('modify', ('b', 'new-content\n'))],
2013
 
            revision_id='E-id')
2014
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1934
             ('add', (u'b', 'b-id', 'file', 'content\n'))])
 
1935
        builder.build_snapshot('B-id', ['A-id'], [])
 
1936
        builder.build_snapshot('C-id', ['A-id'], [])
 
1937
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1938
            [('modify', ('a-id', 'new-content\n')),
 
1939
             ('modify', ('b-id', 'new-content\n'))])
 
1940
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2015
1941
        merge_obj = self.make_merge_obj(builder, 'E-id',
2016
1942
                                        interesting_files=['b'])
2017
1943
        entries = list(merge_obj._entries_lca())
2018
1944
        root_id = 'a-root-id'
2019
1945
        self.assertEqual([('b-id', True,
2020
 
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2021
1946
                           ((root_id, [root_id, root_id]), root_id, root_id),
2022
1947
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2023
1948
                           ((False, [False, False]), False, False)),
2026
1951
    def test_interesting_file_in_this(self):
2027
1952
        # This renamed the file, but it should still match the entry in other
2028
1953
        builder = self.get_builder()
2029
 
        builder.build_snapshot(None,
 
1954
        builder.build_snapshot('A-id', None,
2030
1955
            [('add', (u'', 'a-root-id', 'directory', None)),
2031
1956
             ('add', (u'a', 'a-id', 'file', 'content\n')),
2032
 
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2033
 
            revision_id='A-id')
2034
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2035
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2036
 
        builder.build_snapshot(['C-id', 'B-id'],
2037
 
            [('modify', ('a', 'new-content\n')),
2038
 
             ('modify', ('b', 'new-content\n'))],
2039
 
            revision_id='E-id')
2040
 
        builder.build_snapshot(['B-id', 'C-id'],
2041
 
            [('rename', ('b', 'c'))],
2042
 
            revision_id='D-id')
 
1957
             ('add', (u'b', 'b-id', 'file', 'content\n'))])
 
1958
        builder.build_snapshot('B-id', ['A-id'], [])
 
1959
        builder.build_snapshot('C-id', ['A-id'], [])
 
1960
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1961
            [('modify', ('a-id', 'new-content\n')),
 
1962
             ('modify', ('b-id', 'new-content\n'))])
 
1963
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
1964
            [('rename', ('b', 'c'))])
2043
1965
        merge_obj = self.make_merge_obj(builder, 'E-id',
2044
1966
                                        interesting_files=['c'])
2045
1967
        entries = list(merge_obj._entries_lca())
2046
1968
        root_id = 'a-root-id'
2047
1969
        self.assertEqual([('b-id', True,
2048
 
                           ((u'b', [u'b', u'b']), u'b', u'c'),
2049
1970
                           ((root_id, [root_id, root_id]), root_id, root_id),
2050
1971
                           ((u'b', [u'b', u'b']), u'b', u'c'),
2051
1972
                           ((False, [False, False]), False, False)),
2054
1975
    def test_interesting_file_in_base(self):
2055
1976
        # This renamed the file, but it should still match the entry in BASE
2056
1977
        builder = self.get_builder()
2057
 
        builder.build_snapshot(None,
 
1978
        builder.build_snapshot('A-id', None,
2058
1979
            [('add', (u'', 'a-root-id', 'directory', None)),
2059
1980
             ('add', (u'a', 'a-id', 'file', 'content\n')),
2060
 
             ('add', (u'c', 'c-id', 'file', 'content\n'))],
2061
 
            revision_id='A-id')
2062
 
        builder.build_snapshot(['A-id'],
2063
 
            [('rename', ('c', 'b'))],
2064
 
            revision_id='B-id')
2065
 
        builder.build_snapshot(['A-id'],
2066
 
            [('rename', ('c', 'b'))],
2067
 
            revision_id='C-id')
2068
 
        builder.build_snapshot(['C-id', 'B-id'],
2069
 
            [('modify', ('a', 'new-content\n')),
2070
 
             ('modify', ('b', 'new-content\n'))],
2071
 
            revision_id='E-id')
2072
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
1981
             ('add', (u'c', 'c-id', 'file', 'content\n'))])
 
1982
        builder.build_snapshot('B-id', ['A-id'],
 
1983
            [('rename', ('c', 'b'))])
 
1984
        builder.build_snapshot('C-id', ['A-id'],
 
1985
            [('rename', ('c', 'b'))])
 
1986
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
1987
            [('modify', ('a-id', 'new-content\n')),
 
1988
             ('modify', ('c-id', 'new-content\n'))])
 
1989
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2073
1990
        merge_obj = self.make_merge_obj(builder, 'E-id',
2074
1991
                                        interesting_files=['c'])
2075
1992
        entries = list(merge_obj._entries_lca())
2076
1993
        root_id = 'a-root-id'
2077
1994
        self.assertEqual([('c-id', True,
2078
 
                           ((u'c', [u'b', u'b']), u'b', u'b'),
2079
1995
                           ((root_id, [root_id, root_id]), root_id, root_id),
2080
1996
                           ((u'c', [u'b', u'b']), u'b', u'b'),
2081
1997
                           ((False, [False, False]), False, False)),
2084
2000
    def test_interesting_file_in_lca(self):
2085
2001
        # This renamed the file, but it should still match the entry in LCA
2086
2002
        builder = self.get_builder()
2087
 
        builder.build_snapshot(None,
 
2003
        builder.build_snapshot('A-id', None,
2088
2004
            [('add', (u'', 'a-root-id', 'directory', None)),
2089
2005
             ('add', (u'a', 'a-id', 'file', 'content\n')),
2090
 
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2091
 
            revision_id='A-id')
2092
 
        builder.build_snapshot(['A-id'],
2093
 
            [('rename', ('b', 'c'))], revision_id='B-id')
2094
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2095
 
        builder.build_snapshot(['C-id', 'B-id'],
2096
 
            [('modify', ('a', 'new-content\n')),
2097
 
             ('modify', ('b', 'new-content\n'))],
2098
 
            revision_id='E-id')
2099
 
        builder.build_snapshot(['B-id', 'C-id'],
2100
 
            [('rename', ('c', 'b'))], revision_id='D-id')
 
2006
             ('add', (u'b', 'b-id', 'file', 'content\n'))])
 
2007
        builder.build_snapshot('B-id', ['A-id'],
 
2008
            [('rename', ('b', 'c'))])
 
2009
        builder.build_snapshot('C-id', ['A-id'], [])
 
2010
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
2011
            [('modify', ('a-id', 'new-content\n')),
 
2012
             ('modify', ('b-id', 'new-content\n'))])
 
2013
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
2014
            [('rename', ('c', 'b'))])
2101
2015
        merge_obj = self.make_merge_obj(builder, 'E-id',
2102
2016
                                        interesting_files=['c'])
2103
2017
        entries = list(merge_obj._entries_lca())
2104
2018
        root_id = 'a-root-id'
2105
2019
        self.assertEqual([('b-id', True,
2106
 
                           ((u'b', [u'c', u'b']), u'b', u'b'),
2107
2020
                           ((root_id, [root_id, root_id]), root_id, root_id),
2108
2021
                           ((u'b', [u'c', u'b']), u'b', u'b'),
2109
2022
                           ((False, [False, False]), False, False)),
2110
2023
                         ], entries)
2111
2024
 
2112
 
    def test_interesting_files(self):
 
2025
    def test_interesting_ids(self):
2113
2026
        # Two files modified, but we should filter one of them
2114
2027
        builder = self.get_builder()
2115
 
        builder.build_snapshot(None,
 
2028
        builder.build_snapshot('A-id', None,
2116
2029
            [('add', (u'', 'a-root-id', 'directory', None)),
2117
2030
             ('add', (u'a', 'a-id', 'file', 'content\n')),
2118
 
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2119
 
            revision_id='A-id')
2120
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2121
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2122
 
        builder.build_snapshot(['C-id', 'B-id'],
2123
 
            [('modify', ('a', 'new-content\n')),
2124
 
             ('modify', ('b', 'new-content\n'))], revision_id='E-id')
2125
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
2031
             ('add', (u'b', 'b-id', 'file', 'content\n'))])
 
2032
        builder.build_snapshot('B-id', ['A-id'], [])
 
2033
        builder.build_snapshot('C-id', ['A-id'], [])
 
2034
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
2035
            [('modify', ('a-id', 'new-content\n')),
 
2036
             ('modify', ('b-id', 'new-content\n'))])
 
2037
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2126
2038
        merge_obj = self.make_merge_obj(builder, 'E-id',
2127
 
                                        interesting_files=['b'])
 
2039
                                        interesting_ids=['b-id'])
2128
2040
        entries = list(merge_obj._entries_lca())
2129
2041
        root_id = 'a-root-id'
2130
2042
        self.assertEqual([('b-id', True,
2131
 
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2132
2043
                           ((root_id, [root_id, root_id]), root_id, root_id),
2133
2044
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2134
2045
                           ((False, [False, False]), False, False)),
2147
2058
    def get_wt_from_builder(self, builder):
2148
2059
        """Get a real WorkingTree from the builder."""
2149
2060
        the_branch = builder.get_branch()
2150
 
        wt = the_branch.controldir.create_workingtree()
 
2061
        wt = the_branch.bzrdir.create_workingtree()
2151
2062
        # Note: This is a little bit ugly, but we are holding the branch
2152
2063
        #       write-locked as part of the build process, and we would like to
2153
2064
        #       maintain that. So we just force the WT to re-use the same
2159
2070
 
2160
2071
    def do_merge(self, builder, other_revision_id):
2161
2072
        wt = self.get_wt_from_builder(builder)
2162
 
        merger = _mod_merge.Merger.from_revision_ids(
 
2073
        merger = _mod_merge.Merger.from_revision_ids(None,
2163
2074
            wt, other_revision_id)
2164
2075
        merger.merge_type = _mod_merge.Merge3Merger
2165
2076
        return wt, merger.do_merge()
2166
2077
 
2167
2078
    def test_simple_lca(self):
2168
2079
        builder = self.get_builder()
2169
 
        builder.build_snapshot(None,
 
2080
        builder.build_snapshot('A-id', None,
2170
2081
            [('add', (u'', 'a-root-id', 'directory', None)),
2171
 
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
2172
 
            revision_id='A-id')
2173
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2174
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2175
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
2176
 
        builder.build_snapshot(['B-id', 'C-id'],
2177
 
            [('modify', ('a', 'a\nb\nc\nd\ne\nf\n'))],
2178
 
            revision_id='D-id')
 
2082
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
 
2083
        builder.build_snapshot('C-id', ['A-id'], [])
 
2084
        builder.build_snapshot('B-id', ['A-id'], [])
 
2085
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
2086
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
2087
            [('modify', ('a-id', 'a\nb\nc\nd\ne\nf\n'))])
2179
2088
        wt, conflicts = self.do_merge(builder, 'E-id')
2180
2089
        self.assertEqual(0, conflicts)
2181
2090
        # The merge should have simply update the contents of 'a'
2182
 
        self.assertEqual('a\nb\nc\nd\ne\nf\n', wt.get_file_text('a'))
 
2091
        self.assertEqual('a\nb\nc\nd\ne\nf\n', wt.get_file_text('a-id'))
2183
2092
 
2184
2093
    def test_conflict_without_lca(self):
2185
2094
        # This test would cause a merge conflict, unless we use the lca trees
2194
2103
        #     |
2195
2104
        #     F     Path at 'baz' in F, which supersedes 'bar' and 'foo'
2196
2105
        builder = self.get_builder()
2197
 
        builder.build_snapshot(None,
 
2106
        builder.build_snapshot('A-id', None,
2198
2107
            [('add', (u'', 'a-root-id', 'directory', None)),
2199
 
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2200
 
            revision_id='A-id')
2201
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2202
 
        builder.build_snapshot(['A-id'],
2203
 
            [('rename', ('foo', 'bar'))], revision_id='B-id', )
2204
 
        builder.build_snapshot(['C-id', 'B-id'], # merge the rename
2205
 
            [('rename', ('foo', 'bar'))], revision_id='E-id')
2206
 
        builder.build_snapshot(['E-id'],
2207
 
            [('rename', ('bar', 'baz'))], revision_id='F-id')
2208
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
2108
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
2109
        builder.build_snapshot('C-id', ['A-id'], [])
 
2110
        builder.build_snapshot('B-id', ['A-id'],
 
2111
            [('rename', ('foo', 'bar'))])
 
2112
        builder.build_snapshot('E-id', ['C-id', 'B-id'], # merge the rename
 
2113
            [('rename', ('foo', 'bar'))])
 
2114
        builder.build_snapshot('F-id', ['E-id'],
 
2115
            [('rename', ('bar', 'baz'))])
 
2116
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2209
2117
        wt, conflicts = self.do_merge(builder, 'F-id')
2210
2118
        self.assertEqual(0, conflicts)
2211
2119
        # The merge should simply recognize that the final rename takes
2212
2120
        # precedence
2213
 
        self.assertEqual('baz', wt.id2path(b'foo-id'))
 
2121
        self.assertEqual('baz', wt.id2path('foo-id'))
2214
2122
 
2215
2123
    def test_other_deletes_lca_renames(self):
2216
2124
        # This test would cause a merge conflict, unless we use the lca trees
2225
2133
        #     |
2226
2134
        #     F     F deletes 'bar'
2227
2135
        builder = self.get_builder()
2228
 
        builder.build_snapshot(None,
 
2136
        builder.build_snapshot('A-id', None,
2229
2137
            [('add', (u'', 'a-root-id', 'directory', None)),
2230
 
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2231
 
            revision_id='A-id')
2232
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2233
 
        builder.build_snapshot(['A-id'],
2234
 
            [('rename', ('foo', 'bar'))], revision_id='B-id')
2235
 
        builder.build_snapshot(['C-id', 'B-id'], # merge the rename
2236
 
            [('rename', ('foo', 'bar'))], revision_id='E-id')
2237
 
        builder.build_snapshot(['E-id'],
2238
 
            [('unversion', 'bar')], revision_id='F-id')
2239
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
 
2138
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
2139
        builder.build_snapshot('C-id', ['A-id'], [])
 
2140
        builder.build_snapshot('B-id', ['A-id'],
 
2141
            [('rename', ('foo', 'bar'))])
 
2142
        builder.build_snapshot('E-id', ['C-id', 'B-id'], # merge the rename
 
2143
            [('rename', ('foo', 'bar'))])
 
2144
        builder.build_snapshot('F-id', ['E-id'],
 
2145
            [('unversion', 'foo-id')])
 
2146
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2240
2147
        wt, conflicts = self.do_merge(builder, 'F-id')
2241
2148
        self.assertEqual(0, conflicts)
2242
2149
        self.assertRaises(errors.NoSuchId, wt.id2path, 'foo-id')
2252
2159
        #     |
2253
2160
        #     F     Executable bit changed
2254
2161
        builder = self.get_builder()
2255
 
        builder.build_snapshot(None,
 
2162
        builder.build_snapshot('A-id', None,
2256
2163
            [('add', (u'', 'a-root-id', 'directory', None)),
2257
 
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2258
 
            revision_id='A-id')
2259
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2260
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2261
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
2262
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
 
2164
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
2165
        builder.build_snapshot('C-id', ['A-id'], [])
 
2166
        builder.build_snapshot('B-id', ['A-id'], [])
 
2167
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
2168
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
2263
2169
        # Have to use a real WT, because BranchBuilder doesn't support exec bit
2264
2170
        wt = self.get_wt_from_builder(builder)
2265
2171
        tt = transform.TreeTransform(wt)
2266
2172
        try:
2267
 
            tt.set_executability(True, tt.trans_id_tree_path('foo'))
 
2173
            tt.set_executability(True, tt.trans_id_tree_file_id('foo-id'))
2268
2174
            tt.apply()
2269
2175
        except:
2270
2176
            tt.finalize()
2271
2177
            raise
2272
 
        self.assertTrue(wt.is_executable('foo'))
2273
 
        wt.commit('F-id', rev_id=b'F-id')
 
2178
        self.assertTrue(wt.is_executable('foo-id'))
 
2179
        wt.commit('F-id', rev_id='F-id')
2274
2180
        # Reset to D, so that we can merge F
2275
2181
        wt.set_parent_ids(['D-id'])
2276
2182
        wt.branch.set_last_revision_info(3, 'D-id')
2277
2183
        wt.revert()
2278
 
        self.assertFalse(wt.is_executable('foo'))
 
2184
        self.assertFalse(wt.is_executable('foo-id'))
2279
2185
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2280
2186
        self.assertEqual(0, conflicts)
2281
 
        self.assertTrue(wt.is_executable('foo'))
 
2187
        self.assertTrue(wt.is_executable('foo-id'))
2282
2188
 
2283
2189
    def test_create_symlink(self):
2284
2190
        self.requireFeature(features.SymlinkFeature)
2294
2200
        # Have to use a real WT, because BranchBuilder and MemoryTree don't
2295
2201
        # have symlink support
2296
2202
        builder = self.get_builder()
2297
 
        builder.build_snapshot(None,
2298
 
            [('add', (u'', 'a-root-id', 'directory', None))],
2299
 
            revision_id='A-id')
2300
 
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2301
 
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2302
 
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
2303
 
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
 
2203
        builder.build_snapshot('A-id', None,
 
2204
            [('add', (u'', 'a-root-id', 'directory', None))])
 
2205
        builder.build_snapshot('C-id', ['A-id'], [])
 
2206
        builder.build_snapshot('B-id', ['A-id'], [])
 
2207
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
2208
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
2304
2209
        # Have to use a real WT, because BranchBuilder doesn't support exec bit
2305
2210
        wt = self.get_wt_from_builder(builder)
2306
2211
        os.symlink('bar', 'path/foo')
2307
 
        wt.add(['foo'], [b'foo-id'])
2308
 
        self.assertEqual('bar', wt.get_symlink_target('foo'))
2309
 
        wt.commit('add symlink', rev_id=b'F-id')
 
2212
        wt.add(['foo'], ['foo-id'])
 
2213
        self.assertEqual('bar', wt.get_symlink_target('foo-id'))
 
2214
        wt.commit('add symlink', rev_id='F-id')
2310
2215
        # Reset to D, so that we can merge F
2311
 
        wt.set_parent_ids([b'D-id'])
2312
 
        wt.branch.set_last_revision_info(3, b'D-id')
 
2216
        wt.set_parent_ids(['D-id'])
 
2217
        wt.branch.set_last_revision_info(3, 'D-id')
2313
2218
        wt.revert()
2314
 
        self.assertFalse(wt.is_versioned('foo'))
2315
 
        conflicts = wt.merge_from_branch(wt.branch, to_revision=b'F-id')
 
2219
        self.assertIs(None, wt.path2id('foo'))
 
2220
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2316
2221
        self.assertEqual(0, conflicts)
2317
 
        self.assertEqual(b'foo-id', wt.path2id('foo'))
2318
 
        self.assertEqual('bar', wt.get_symlink_target('foo'))
 
2222
        self.assertEqual('foo-id', wt.path2id('foo'))
 
2223
        self.assertEqual('bar', wt.get_symlink_target('foo-id'))
2319
2224
 
2320
2225
    def test_both_sides_revert(self):
2321
2226
        # Both sides of a criss-cross revert the text to the lca
2328
2233
        # This must be done with a real WorkingTree, because normally their
2329
2234
        # inventory contains "None" rather than a real sha1
2330
2235
        builder = self.get_builder()
2331
 
        builder.build_snapshot(None,
 
2236
        builder.build_snapshot('A-id', None,
2332
2237
            [('add', (u'', 'a-root-id', 'directory', None)),
2333
 
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
2334
 
            revision_id='A-id')
2335
 
        builder.build_snapshot(['A-id'],
2336
 
            [('modify', ('foo', 'B content\n'))],
2337
 
            revision_id='B-id')
2338
 
        builder.build_snapshot(['A-id'],
2339
 
            [('modify', ('foo', 'C content\n'))],
2340
 
            revision_id='C-id')
2341
 
        builder.build_snapshot(['C-id', 'B-id'], [],
2342
 
                revision_id='E-id')
2343
 
        builder.build_snapshot(['B-id', 'C-id'], [],
2344
 
                revision_id='D-id')
 
2238
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
 
2239
        builder.build_snapshot('B-id', ['A-id'],
 
2240
            [('modify', ('foo-id', 'B content\n'))])
 
2241
        builder.build_snapshot('C-id', ['A-id'],
 
2242
            [('modify', ('foo-id', 'C content\n'))])
 
2243
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
 
2244
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
2345
2245
        wt, conflicts = self.do_merge(builder, 'E-id')
2346
2246
        self.assertEqual(1, conflicts)
2347
2247
        self.assertEqualDiff('<<<<<<< TREE\n'
2349
2249
                             '=======\n'
2350
2250
                             'C content\n'
2351
2251
                             '>>>>>>> MERGE-SOURCE\n',
2352
 
                             wt.get_file_text('foo'))
 
2252
                             wt.get_file_text('foo-id'))
2353
2253
 
2354
2254
    def test_modified_symlink(self):
2355
2255
        self.requireFeature(features.SymlinkFeature)
2372
2272
        wt.lock_write()
2373
2273
        self.addCleanup(wt.unlock)
2374
2274
        os.symlink('bar', 'path/foo')
2375
 
        wt.add(['foo'], [b'foo-id'])
2376
 
        wt.commit('add symlink', rev_id=b'A-id')
 
2275
        wt.add(['foo'], ['foo-id'])
 
2276
        wt.commit('add symlink', rev_id='A-id')
2377
2277
        os.remove('path/foo')
2378
2278
        os.symlink('baz', 'path/foo')
2379
 
        wt.commit('foo => baz', rev_id=b'B-id')
2380
 
        wt.set_last_revision(b'A-id')
 
2279
        wt.commit('foo => baz', rev_id='B-id')
 
2280
        wt.set_last_revision('A-id')
2381
2281
        wt.branch.set_last_revision_info(1, 'A-id')
2382
2282
        wt.revert()
2383
 
        wt.commit('C', rev_id=b'C-id')
2384
 
        wt.merge_from_branch(wt.branch, b'B-id')
2385
 
        self.assertEqual('baz', wt.get_symlink_target('foo'))
2386
 
        wt.commit('E merges C & B', rev_id=b'E-id')
 
2283
        wt.commit('C', rev_id='C-id')
 
2284
        wt.merge_from_branch(wt.branch, 'B-id')
 
2285
        self.assertEqual('baz', wt.get_symlink_target('foo-id'))
 
2286
        wt.commit('E merges C & B', rev_id='E-id')
2387
2287
        os.remove('path/foo')
2388
2288
        os.symlink('bing', 'path/foo')
2389
 
        wt.commit('F foo => bing', rev_id=b'F-id')
 
2289
        wt.commit('F foo => bing', rev_id='F-id')
2390
2290
        wt.set_last_revision('B-id')
2391
 
        wt.branch.set_last_revision_info(2, b'B-id')
 
2291
        wt.branch.set_last_revision_info(2, 'B-id')
2392
2292
        wt.revert()
2393
 
        wt.merge_from_branch(wt.branch, b'C-id')
2394
 
        wt.commit('D merges B & C', rev_id=b'D-id')
2395
 
        conflicts = wt.merge_from_branch(wt.branch, to_revision=b'F-id')
 
2293
        wt.merge_from_branch(wt.branch, 'C-id')
 
2294
        wt.commit('D merges B & C', rev_id='D-id')
 
2295
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2396
2296
        self.assertEqual(0, conflicts)
2397
 
        self.assertEqual('bing', wt.get_symlink_target('foo'))
 
2297
        self.assertEqual('bing', wt.get_symlink_target('foo-id'))
2398
2298
 
2399
2299
    def test_renamed_symlink(self):
2400
2300
        self.requireFeature(features.SymlinkFeature)
2415
2315
        wt.lock_write()
2416
2316
        self.addCleanup(wt.unlock)
2417
2317
        os.symlink('bar', 'path/foo')
2418
 
        wt.add(['foo'], [b'foo-id'])
2419
 
        wt.commit('A add symlink', rev_id=b'A-id')
 
2318
        wt.add(['foo'], ['foo-id'])
 
2319
        wt.commit('A add symlink', rev_id='A-id')
2420
2320
        wt.rename_one('foo', 'barry')
2421
 
        wt.commit('B foo => barry', rev_id=b'B-id')
 
2321
        wt.commit('B foo => barry', rev_id='B-id')
2422
2322
        wt.set_last_revision('A-id')
2423
 
        wt.branch.set_last_revision_info(1, b'A-id')
 
2323
        wt.branch.set_last_revision_info(1, 'A-id')
2424
2324
        wt.revert()
2425
 
        wt.commit('C', rev_id=b'C-id')
2426
 
        wt.merge_from_branch(wt.branch, b'B-id')
2427
 
        self.assertEqual('barry', wt.id2path(b'foo-id'))
2428
 
        self.assertEqual('bar', wt.get_symlink_target('barry'))
2429
 
        wt.commit('E merges C & B', rev_id=b'E-id')
 
2325
        wt.commit('C', rev_id='C-id')
 
2326
        wt.merge_from_branch(wt.branch, 'B-id')
 
2327
        self.assertEqual('barry', wt.id2path('foo-id'))
 
2328
        self.assertEqual('bar', wt.get_symlink_target('foo-id'))
 
2329
        wt.commit('E merges C & B', rev_id='E-id')
2430
2330
        wt.rename_one('barry', 'blah')
2431
 
        wt.commit('F barry => blah', rev_id=b'F-id')
2432
 
        wt.set_last_revision(b'B-id')
2433
 
        wt.branch.set_last_revision_info(2, b'B-id')
 
2331
        wt.commit('F barry => blah', rev_id='F-id')
 
2332
        wt.set_last_revision('B-id')
 
2333
        wt.branch.set_last_revision_info(2, 'B-id')
2434
2334
        wt.revert()
2435
 
        wt.merge_from_branch(wt.branch, b'C-id')
2436
 
        wt.commit('D merges B & C', rev_id=b'D-id')
2437
 
        self.assertEqual('barry', wt.id2path(b'foo-id'))
 
2335
        wt.merge_from_branch(wt.branch, 'C-id')
 
2336
        wt.commit('D merges B & C', rev_id='D-id')
 
2337
        self.assertEqual('barry', wt.id2path('foo-id'))
2438
2338
        # Check the output of the Merger object directly
2439
 
        merger = _mod_merge.Merger.from_revision_ids(wt, b'F-id')
 
2339
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2340
            wt, 'F-id')
2440
2341
        merger.merge_type = _mod_merge.Merge3Merger
2441
2342
        merge_obj = merger.make_merger()
2442
2343
        root_id = wt.path2id('')
2443
2344
        entries = list(merge_obj._entries_lca())
2444
2345
        # No content change, just a path change
2445
 
        self.assertEqual([(b'foo-id', False,
2446
 
                           ((u'foo', [u'barry', u'foo']), u'blah', u'barry'),
 
2346
        self.assertEqual([('foo-id', False,
2447
2347
                           ((root_id, [root_id, root_id]), root_id, root_id),
2448
2348
                           ((u'foo', [u'barry', u'foo']), u'blah', u'barry'),
2449
2349
                           ((False, [False, False]), False, False)),
2450
2350
                         ], entries)
2451
 
        conflicts = wt.merge_from_branch(wt.branch, to_revision=b'F-id')
 
2351
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2452
2352
        self.assertEqual(0, conflicts)
2453
 
        self.assertEqual('blah', wt.id2path(b'foo-id'))
 
2353
        self.assertEqual('blah', wt.id2path('foo-id'))
2454
2354
 
2455
2355
    def test_symlink_no_content_change(self):
2456
2356
        self.requireFeature(features.SymlinkFeature)
2470
2370
        wt.lock_write()
2471
2371
        self.addCleanup(wt.unlock)
2472
2372
        os.symlink('bar', 'path/foo')
2473
 
        wt.add(['foo'], [b'foo-id'])
2474
 
        wt.commit('add symlink', rev_id=b'A-id')
 
2373
        wt.add(['foo'], ['foo-id'])
 
2374
        wt.commit('add symlink', rev_id='A-id')
2475
2375
        os.remove('path/foo')
2476
2376
        os.symlink('baz', 'path/foo')
2477
 
        wt.commit('foo => baz', rev_id=b'B-id')
2478
 
        wt.set_last_revision(b'A-id')
2479
 
        wt.branch.set_last_revision_info(1, b'A-id')
2480
 
        wt.revert()
2481
 
        wt.commit('C', rev_id=b'C-id')
2482
 
        wt.merge_from_branch(wt.branch, b'B-id')
2483
 
        self.assertEqual('baz', wt.get_symlink_target('foo'))
2484
 
        wt.commit('E merges C & B', rev_id=b'E-id')
2485
 
        wt.set_last_revision(b'B-id')
2486
 
        wt.branch.set_last_revision_info(2, b'B-id')
2487
 
        wt.revert()
2488
 
        wt.merge_from_branch(wt.branch, b'C-id')
2489
 
        wt.commit('D merges B & C', rev_id=b'D-id')
 
2377
        wt.commit('foo => baz', rev_id='B-id')
 
2378
        wt.set_last_revision('A-id')
 
2379
        wt.branch.set_last_revision_info(1, 'A-id')
 
2380
        wt.revert()
 
2381
        wt.commit('C', rev_id='C-id')
 
2382
        wt.merge_from_branch(wt.branch, 'B-id')
 
2383
        self.assertEqual('baz', wt.get_symlink_target('foo-id'))
 
2384
        wt.commit('E merges C & B', rev_id='E-id')
 
2385
        wt.set_last_revision('B-id')
 
2386
        wt.branch.set_last_revision_info(2, 'B-id')
 
2387
        wt.revert()
 
2388
        wt.merge_from_branch(wt.branch, 'C-id')
 
2389
        wt.commit('D merges B & C', rev_id='D-id')
2490
2390
        os.remove('path/foo')
2491
2391
        os.symlink('bing', 'path/foo')
2492
 
        wt.commit('F foo => bing', rev_id=b'F-id')
 
2392
        wt.commit('F foo => bing', rev_id='F-id')
2493
2393
 
2494
2394
        # Check the output of the Merger object directly
2495
 
        merger = _mod_merge.Merger.from_revision_ids(wt, b'E-id')
 
2395
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2396
            wt, 'E-id')
2496
2397
        merger.merge_type = _mod_merge.Merge3Merger
2497
2398
        merge_obj = merger.make_merger()
2498
2399
        # Nothing interesting happened in OTHER relative to BASE
2499
2400
        self.assertEqual([], list(merge_obj._entries_lca()))
2500
2401
        # Now do a real merge, just to test the rest of the stack
2501
 
        conflicts = wt.merge_from_branch(wt.branch, to_revision=b'E-id')
 
2402
        conflicts = wt.merge_from_branch(wt.branch, to_revision='E-id')
2502
2403
        self.assertEqual(0, conflicts)
2503
 
        self.assertEqual('bing', wt.get_symlink_target('foo'))
 
2404
        self.assertEqual('bing', wt.get_symlink_target('foo-id'))
2504
2405
 
2505
2406
    def test_symlink_this_changed_kind(self):
2506
2407
        self.requireFeature(features.SymlinkFeature)
2517
2418
        wt = self.make_branch_and_tree('path')
2518
2419
        wt.lock_write()
2519
2420
        self.addCleanup(wt.unlock)
2520
 
        wt.commit('base', rev_id=b'A-id')
 
2421
        wt.commit('base', rev_id='A-id')
2521
2422
        os.symlink('bar', 'path/foo')
2522
 
        wt.add(['foo'], [b'foo-id'])
2523
 
        wt.commit('add symlink foo => bar', rev_id=b'B-id')
2524
 
        wt.set_last_revision(b'A-id')
2525
 
        wt.branch.set_last_revision_info(1, b'A-id')
 
2423
        wt.add(['foo'], ['foo-id'])
 
2424
        wt.commit('add symlink foo => bar', rev_id='B-id')
 
2425
        wt.set_last_revision('A-id')
 
2426
        wt.branch.set_last_revision_info(1, 'A-id')
2526
2427
        wt.revert()
2527
 
        wt.commit('C', rev_id=b'C-id')
2528
 
        wt.merge_from_branch(wt.branch, b'B-id')
2529
 
        self.assertEqual('bar', wt.get_symlink_target('foo'))
 
2428
        wt.commit('C', rev_id='C-id')
 
2429
        wt.merge_from_branch(wt.branch, 'B-id')
 
2430
        self.assertEqual('bar', wt.get_symlink_target('foo-id'))
2530
2431
        os.remove('path/foo')
2531
2432
        # We have to change the link in E, or it won't try to do a comparison
2532
2433
        os.symlink('bing', 'path/foo')
2533
 
        wt.commit('E merges C & B, overrides to bing', rev_id=b'E-id')
 
2434
        wt.commit('E merges C & B, overrides to bing', rev_id='E-id')
2534
2435
        wt.set_last_revision('B-id')
2535
 
        wt.branch.set_last_revision_info(2, b'B-id')
 
2436
        wt.branch.set_last_revision_info(2, 'B-id')
2536
2437
        wt.revert()
2537
 
        wt.merge_from_branch(wt.branch, b'C-id')
 
2438
        wt.merge_from_branch(wt.branch, 'C-id')
2538
2439
        os.remove('path/foo')
2539
 
        self.build_tree_contents([('path/foo', b'file content\n')])
 
2440
        self.build_tree_contents([('path/foo', 'file content\n')])
2540
2441
        # XXX: workaround, WT doesn't detect kind changes unless you do
2541
2442
        # iter_changes()
2542
2443
        list(wt.iter_changes(wt.basis_tree()))
2543
 
        wt.commit('D merges B & C, makes it a file', rev_id=b'D-id')
 
2444
        wt.commit('D merges B & C, makes it a file', rev_id='D-id')
2544
2445
 
2545
 
        merger = _mod_merge.Merger.from_revision_ids(wt, b'E-id')
 
2446
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2447
            wt, 'E-id')
2546
2448
        merger.merge_type = _mod_merge.Merge3Merger
2547
2449
        merge_obj = merger.make_merger()
2548
2450
        entries = list(merge_obj._entries_lca())
2549
2451
        root_id = wt.path2id('')
2550
 
        self.assertEqual([(b'foo-id', True,
2551
 
                           ((None, [u'foo', None]), u'foo', u'foo'),
 
2452
        self.assertEqual([('foo-id', True,
2552
2453
                           ((None, [root_id, None]), root_id, root_id),
2553
2454
                           ((None, [u'foo', None]), u'foo', u'foo'),
2554
2455
                           ((None, [False, None]), False, False)),
2573
2474
        wt.lock_write()
2574
2475
        self.addCleanup(wt.unlock)
2575
2476
        os.symlink('bar', 'path/foo')
2576
 
        wt.add(['foo'], [b'foo-id'])
2577
 
        wt.commit('add symlink', rev_id=b'A-id')
 
2477
        wt.add(['foo'], ['foo-id'])
 
2478
        wt.commit('add symlink', rev_id='A-id')
2578
2479
        os.remove('path/foo')
2579
2480
        os.symlink('baz', 'path/foo')
2580
 
        wt.commit('foo => baz', rev_id=b'B-id')
2581
 
        wt.set_last_revision(b'A-id')
2582
 
        wt.branch.set_last_revision_info(1, b'A-id')
 
2481
        wt.commit('foo => baz', rev_id='B-id')
 
2482
        wt.set_last_revision('A-id')
 
2483
        wt.branch.set_last_revision_info(1, 'A-id')
2583
2484
        wt.revert()
2584
 
        wt.commit('C', rev_id=b'C-id')
2585
 
        wt.merge_from_branch(wt.branch, b'B-id')
2586
 
        self.assertEqual('baz', wt.get_symlink_target('foo'))
2587
 
        wt.commit('E merges C & B', rev_id=b'E-id')
 
2485
        wt.commit('C', rev_id='C-id')
 
2486
        wt.merge_from_branch(wt.branch, 'B-id')
 
2487
        self.assertEqual('baz', wt.get_symlink_target('foo-id'))
 
2488
        wt.commit('E merges C & B', rev_id='E-id')
2588
2489
        os.remove('path/foo')
2589
2490
        os.symlink('bing', 'path/foo')
2590
 
        wt.commit('F foo => bing', rev_id=b'F-id')
 
2491
        wt.commit('F foo => bing', rev_id='F-id')
2591
2492
        wt.set_last_revision('B-id')
2592
 
        wt.branch.set_last_revision_info(2, b'B-id')
 
2493
        wt.branch.set_last_revision_info(2, 'B-id')
2593
2494
        wt.revert()
2594
 
        wt.merge_from_branch(wt.branch, b'C-id')
2595
 
        wt.commit('D merges B & C', rev_id=b'D-id')
2596
 
        wt_base = wt.controldir.sprout('base', b'A-id').open_workingtree()
 
2495
        wt.merge_from_branch(wt.branch, 'C-id')
 
2496
        wt.commit('D merges B & C', rev_id='D-id')
 
2497
        wt_base = wt.bzrdir.sprout('base', 'A-id').open_workingtree()
2597
2498
        wt_base.lock_read()
2598
2499
        self.addCleanup(wt_base.unlock)
2599
 
        wt_lca1 = wt.controldir.sprout('b-tree', b'B-id').open_workingtree()
 
2500
        wt_lca1 = wt.bzrdir.sprout('b-tree', 'B-id').open_workingtree()
2600
2501
        wt_lca1.lock_read()
2601
2502
        self.addCleanup(wt_lca1.unlock)
2602
 
        wt_lca2 = wt.controldir.sprout('c-tree', b'C-id').open_workingtree()
 
2503
        wt_lca2 = wt.bzrdir.sprout('c-tree', 'C-id').open_workingtree()
2603
2504
        wt_lca2.lock_read()
2604
2505
        self.addCleanup(wt_lca2.unlock)
2605
 
        wt_other = wt.controldir.sprout('other', b'F-id').open_workingtree()
 
2506
        wt_other = wt.bzrdir.sprout('other', 'F-id').open_workingtree()
2606
2507
        wt_other.lock_read()
2607
2508
        self.addCleanup(wt_other.unlock)
2608
2509
        merge_obj = _mod_merge.Merge3Merger(wt, wt, wt_base,
2609
2510
            wt_other, lca_trees=[wt_lca1, wt_lca2], do_merge=False)
2610
2511
        entries = list(merge_obj._entries_lca())
2611
2512
        root_id = wt.path2id('')
2612
 
        self.assertEqual([(b'foo-id', True,
2613
 
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
 
2513
        self.assertEqual([('foo-id', True,
2614
2514
                           ((root_id, [root_id, root_id]), root_id, root_id),
2615
2515
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2616
2516
                           ((False, [False, False]), False, False)),
2627
2527
        #     |
2628
2528
        #     F     Path at 'foo'
2629
2529
        builder = self.get_builder()
2630
 
        builder.build_snapshot(None,
2631
 
            [('add', (u'', b'a-root-id', 'directory', None)),
2632
 
             ('add', (u'foo', b'foo-id', 'file', 'a\nb\nc\n'))],
2633
 
            revision_id=b'A-id')
2634
 
        builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
2635
 
        builder.build_snapshot([b'A-id'],
2636
 
            [('rename', ('foo', 'bar'))], revision_id=b'B-id')
2637
 
        builder.build_snapshot([b'C-id', b'B-id'],
2638
 
            [('rename', ('foo', 'bar'))], revision_id=b'E-id') # merge the rename
2639
 
        builder.build_snapshot([b'E-id'],
2640
 
            [('rename', ('bar', 'foo'))], revision_id=b'F-id') # Rename back to BASE
2641
 
        builder.build_snapshot([b'B-id', b'C-id'], [], revision_id=b'D-id')
2642
 
        wt, conflicts = self.do_merge(builder, b'F-id')
 
2530
        builder.build_snapshot('A-id', None,
 
2531
            [('add', (u'', 'a-root-id', 'directory', None)),
 
2532
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
 
2533
        builder.build_snapshot('C-id', ['A-id'], [])
 
2534
        builder.build_snapshot('B-id', ['A-id'],
 
2535
            [('rename', ('foo', 'bar'))])
 
2536
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
2537
            [('rename', ('foo', 'bar'))]) # merge the rename
 
2538
        builder.build_snapshot('F-id', ['E-id'],
 
2539
            [('rename', ('bar', 'foo'))]) # Rename back to BASE
 
2540
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
2541
        wt, conflicts = self.do_merge(builder, 'F-id')
2643
2542
        self.assertEqual(0, conflicts)
2644
 
        self.assertEqual('foo', wt.id2path(b'foo-id'))
 
2543
        self.assertEqual('foo', wt.id2path('foo-id'))
2645
2544
 
2646
2545
    def test_other_reverted_content_to_base(self):
2647
2546
        builder = self.get_builder()
2648
 
        builder.build_snapshot(None,
2649
 
            [('add', (u'', b'a-root-id', 'directory', None)),
2650
 
             ('add', (u'foo', b'foo-id', 'file', b'base content\n'))],
2651
 
            revision_id=b'A-id')
2652
 
        builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
2653
 
        builder.build_snapshot([b'A-id'],
2654
 
            [('modify', ('foo', b'B content\n'))],
2655
 
            revision_id=b'B-id')
2656
 
        builder.build_snapshot([b'C-id', b'B-id'],
2657
 
            [('modify', ('foo', b'B content\n'))],
2658
 
            revision_id=b'E-id') # merge the content
2659
 
        builder.build_snapshot([b'E-id'],
2660
 
            [('modify', ('foo', b'base content\n'))],
2661
 
            revision_id=b'F-id') # Revert back to BASE
2662
 
        builder.build_snapshot([b'B-id', b'C-id'], [], revision_id=b'D-id')
2663
 
        wt, conflicts = self.do_merge(builder, b'F-id')
 
2547
        builder.build_snapshot('A-id', None,
 
2548
            [('add', (u'', 'a-root-id', 'directory', None)),
 
2549
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))])
 
2550
        builder.build_snapshot('C-id', ['A-id'], [])
 
2551
        builder.build_snapshot('B-id', ['A-id'],
 
2552
            [('modify', ('foo-id', 'B content\n'))])
 
2553
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
2554
            [('modify', ('foo-id', 'B content\n'))]) # merge the content
 
2555
        builder.build_snapshot('F-id', ['E-id'],
 
2556
            [('modify', ('foo-id', 'base content\n'))]) # Revert back to BASE
 
2557
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
2558
        wt, conflicts = self.do_merge(builder, 'F-id')
2664
2559
        self.assertEqual(0, conflicts)
2665
2560
        # TODO: We need to use the per-file graph to properly select a BASE
2666
2561
        #       before this will work. Or at least use the LCA trees to find
2667
2562
        #       the appropriate content base. (which is B, not A).
2668
 
        self.assertEqual('base content\n', wt.get_file_text('foo'))
 
2563
        self.assertEqual('base content\n', wt.get_file_text('foo-id'))
2669
2564
 
2670
2565
    def test_other_modified_content(self):
2671
2566
        builder = self.get_builder()
2672
 
        builder.build_snapshot(None,
2673
 
            [('add', (u'', b'a-root-id', 'directory', None)),
2674
 
             ('add', (u'foo', b'foo-id', 'file', b'base content\n'))],
2675
 
            revision_id=b'A-id')
2676
 
        builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
2677
 
        builder.build_snapshot([b'A-id'],
2678
 
            [('modify', ('foo', b'B content\n'))],
2679
 
            revision_id=b'B-id')
2680
 
        builder.build_snapshot([b'C-id', b'B-id'],
2681
 
            [('modify', ('foo', b'B content\n'))],
2682
 
            revision_id=b'E-id') # merge the content
2683
 
        builder.build_snapshot([b'E-id'],
2684
 
            [('modify', ('foo', b'F content\n'))],
2685
 
            revision_id=b'F-id') # Override B content
2686
 
        builder.build_snapshot([b'B-id', b'C-id'], [], revision_id=b'D-id')
2687
 
        wt, conflicts = self.do_merge(builder, b'F-id')
 
2567
        builder.build_snapshot('A-id', None,
 
2568
            [('add', (u'', 'a-root-id', 'directory', None)),
 
2569
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))])
 
2570
        builder.build_snapshot('C-id', ['A-id'], [])
 
2571
        builder.build_snapshot('B-id', ['A-id'],
 
2572
            [('modify', ('foo-id', 'B content\n'))])
 
2573
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
 
2574
            [('modify', ('foo-id', 'B content\n'))]) # merge the content
 
2575
        builder.build_snapshot('F-id', ['E-id'],
 
2576
            [('modify', ('foo-id', 'F content\n'))]) # Override B content
 
2577
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
2578
        wt, conflicts = self.do_merge(builder, 'F-id')
2688
2579
        self.assertEqual(0, conflicts)
2689
 
        self.assertEqual(b'F content\n', wt.get_file_text('foo'))
 
2580
        self.assertEqual('F content\n', wt.get_file_text('foo-id'))
2690
2581
 
2691
2582
    def test_all_wt(self):
2692
2583
        """Check behavior if all trees are Working Trees."""
2699
2590
        #   |X|
2700
2591
        #   D E E updates content, renames 'b' => 'c'
2701
2592
        builder = self.get_builder()
2702
 
        builder.build_snapshot(None,
 
2593
        builder.build_snapshot('A-id', None,
2703
2594
            [('add', (u'', 'a-root-id', 'directory', None)),
2704
2595
             ('add', (u'a', 'a-id', 'file', 'base content\n')),
2705
 
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))],
2706
 
            revision_id='A-id')
2707
 
        builder.build_snapshot(['A-id'],
2708
 
            [('modify', ('foo', 'B content\n'))],
2709
 
            revision_id='B-id')
2710
 
        builder.build_snapshot(['A-id'],
2711
 
            [('rename', ('a', 'b'))],
2712
 
            revision_id='C-id')
2713
 
        builder.build_snapshot(['C-id', 'B-id'],
 
2596
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))])
 
2597
        builder.build_snapshot('B-id', ['A-id'],
 
2598
            [('modify', ('foo-id', 'B content\n'))])
 
2599
        builder.build_snapshot('C-id', ['A-id'],
 
2600
            [('rename', ('a', 'b'))])
 
2601
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
2714
2602
            [('rename', ('b', 'c')),
2715
 
             ('modify', ('foo', 'E content\n'))],
2716
 
            revision_id='E-id')
2717
 
        builder.build_snapshot(['B-id', 'C-id'],
2718
 
            [('rename', ('a', 'b'))], revision_id='D-id') # merged change
 
2603
             ('modify', ('foo-id', 'E content\n'))])
 
2604
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
2605
            [('rename', ('a', 'b'))]) # merged change
2719
2606
        wt_this = self.get_wt_from_builder(builder)
2720
 
        wt_base = wt_this.controldir.sprout('base', 'A-id').open_workingtree()
 
2607
        wt_base = wt_this.bzrdir.sprout('base', 'A-id').open_workingtree()
2721
2608
        wt_base.lock_read()
2722
2609
        self.addCleanup(wt_base.unlock)
2723
 
        wt_lca1 = wt_this.controldir.sprout('b-tree', 'B-id').open_workingtree()
 
2610
        wt_lca1 = wt_this.bzrdir.sprout('b-tree', 'B-id').open_workingtree()
2724
2611
        wt_lca1.lock_read()
2725
2612
        self.addCleanup(wt_lca1.unlock)
2726
 
        wt_lca2 = wt_this.controldir.sprout('c-tree', 'C-id').open_workingtree()
 
2613
        wt_lca2 = wt_this.bzrdir.sprout('c-tree', 'C-id').open_workingtree()
2727
2614
        wt_lca2.lock_read()
2728
2615
        self.addCleanup(wt_lca2.unlock)
2729
 
        wt_other = wt_this.controldir.sprout('other', 'E-id').open_workingtree()
 
2616
        wt_other = wt_this.bzrdir.sprout('other', 'E-id').open_workingtree()
2730
2617
        wt_other.lock_read()
2731
2618
        self.addCleanup(wt_other.unlock)
2732
2619
        merge_obj = _mod_merge.Merge3Merger(wt_this, wt_this, wt_base,
2734
2621
        entries = list(merge_obj._entries_lca())
2735
2622
        root_id = 'a-root-id'
2736
2623
        self.assertEqual([('a-id', False,
2737
 
                           ((u'a', [u'a', u'b']), u'c', u'b'),
2738
2624
                           ((root_id, [root_id, root_id]), root_id, root_id),
2739
2625
                           ((u'a', [u'a', u'b']), u'c', u'b'),
2740
2626
                           ((False, [False, False]), False, False)),
2741
2627
                          ('foo-id', True,
2742
 
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2743
2628
                           ((root_id, [root_id, root_id]), root_id, root_id),
2744
2629
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2745
2630
                           ((False, [False, False]), False, False)),
2754
2639
        self.addCleanup(wt.unlock)
2755
2640
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
2756
2641
            format='development-subtree')
2757
 
        wt.set_root_id(b'a-root-id')
2758
 
        sub_tree.set_root_id(b'sub-tree-root')
2759
 
        self.build_tree_contents([('tree/sub-tree/file', b'text1')])
 
2642
        wt.set_root_id('a-root-id')
 
2643
        sub_tree.set_root_id('sub-tree-root')
 
2644
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
2760
2645
        sub_tree.add('file')
2761
 
        sub_tree.commit('foo', rev_id=b'sub-A-id')
 
2646
        sub_tree.commit('foo', rev_id='sub-A-id')
2762
2647
        wt.add_reference(sub_tree)
2763
 
        wt.commit('set text to 1', rev_id=b'A-id', recursive=None)
 
2648
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2764
2649
        # Now create a criss-cross merge in the parent, without modifying the
2765
2650
        # subtree
2766
 
        wt.commit('B', rev_id=b'B-id', recursive=None)
 
2651
        wt.commit('B', rev_id='B-id', recursive=None)
2767
2652
        wt.set_last_revision('A-id')
2768
2653
        wt.branch.set_last_revision_info(1, 'A-id')
2769
 
        wt.commit('C', rev_id=b'C-id', recursive=None)
 
2654
        wt.commit('C', rev_id='C-id', recursive=None)
2770
2655
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2771
 
        wt.commit('E', rev_id=b'E-id', recursive=None)
 
2656
        wt.commit('E', rev_id='E-id', recursive=None)
2772
2657
        wt.set_parent_ids(['B-id', 'C-id'])
2773
2658
        wt.branch.set_last_revision_info(2, 'B-id')
2774
 
        wt.commit('D', rev_id=b'D-id', recursive=None)
 
2659
        wt.commit('D', rev_id='D-id', recursive=None)
2775
2660
 
2776
 
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
 
2661
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2662
            wt, 'E-id')
2777
2663
        merger.merge_type = _mod_merge.Merge3Merger
2778
2664
        merge_obj = merger.make_merger()
2779
2665
        entries = list(merge_obj._entries_lca())
2788
2674
        self.addCleanup(wt.unlock)
2789
2675
        sub_tree = self.make_branch_and_tree('tree/sub',
2790
2676
            format='development-subtree')
2791
 
        wt.set_root_id(b'a-root-id')
2792
 
        sub_tree.set_root_id(b'sub-tree-root')
2793
 
        self.build_tree_contents([('tree/sub/file', b'text1')])
 
2677
        wt.set_root_id('a-root-id')
 
2678
        sub_tree.set_root_id('sub-tree-root')
 
2679
        self.build_tree_contents([('tree/sub/file', 'text1')])
2794
2680
        sub_tree.add('file')
2795
 
        sub_tree.commit('foo', rev_id=b'sub-A-id')
 
2681
        sub_tree.commit('foo', rev_id='sub-A-id')
2796
2682
        wt.add_reference(sub_tree)
2797
 
        wt.commit('set text to 1', rev_id=b'A-id', recursive=None)
 
2683
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2798
2684
        # Now create a criss-cross merge in the parent, without modifying the
2799
2685
        # subtree
2800
 
        wt.commit('B', rev_id=b'B-id', recursive=None)
 
2686
        wt.commit('B', rev_id='B-id', recursive=None)
2801
2687
        wt.set_last_revision('A-id')
2802
2688
        wt.branch.set_last_revision_info(1, 'A-id')
2803
 
        wt.commit('C', rev_id=b'C-id', recursive=None)
 
2689
        wt.commit('C', rev_id='C-id', recursive=None)
2804
2690
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2805
 
        self.build_tree_contents([('tree/sub/file', b'text2')])
2806
 
        sub_tree.commit('modify contents', rev_id=b'sub-B-id')
2807
 
        wt.commit('E', rev_id=b'E-id', recursive=None)
 
2691
        self.build_tree_contents([('tree/sub/file', 'text2')])
 
2692
        sub_tree.commit('modify contents', rev_id='sub-B-id')
 
2693
        wt.commit('E', rev_id='E-id', recursive=None)
2808
2694
        wt.set_parent_ids(['B-id', 'C-id'])
2809
2695
        wt.branch.set_last_revision_info(2, 'B-id')
2810
 
        wt.commit('D', rev_id=b'D-id', recursive=None)
 
2696
        wt.commit('D', rev_id='D-id', recursive=None)
2811
2697
 
2812
 
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
 
2698
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2699
            wt, 'E-id')
2813
2700
        merger.merge_type = _mod_merge.Merge3Merger
2814
2701
        merge_obj = merger.make_merger()
2815
2702
        entries = list(merge_obj._entries_lca())
2826
2713
        self.addCleanup(wt.unlock)
2827
2714
        sub_tree = self.make_branch_and_tree('tree/sub',
2828
2715
            format='development-subtree')
2829
 
        wt.set_root_id(b'a-root-id')
2830
 
        sub_tree.set_root_id(b'sub-tree-root')
2831
 
        self.build_tree_contents([('tree/sub/file', b'text1')])
 
2716
        wt.set_root_id('a-root-id')
 
2717
        sub_tree.set_root_id('sub-tree-root')
 
2718
        self.build_tree_contents([('tree/sub/file', 'text1')])
2832
2719
        sub_tree.add('file')
2833
 
        sub_tree.commit('foo', rev_id=b'sub-A-id')
 
2720
        sub_tree.commit('foo', rev_id='sub-A-id')
2834
2721
        wt.add_reference(sub_tree)
2835
 
        wt.commit('set text to 1', rev_id=b'A-id', recursive=None)
 
2722
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2836
2723
        # Now create a criss-cross merge in the parent, without modifying the
2837
2724
        # subtree
2838
 
        wt.commit('B', rev_id=b'B-id', recursive=None)
 
2725
        wt.commit('B', rev_id='B-id', recursive=None)
2839
2726
        wt.set_last_revision('A-id')
2840
2727
        wt.branch.set_last_revision_info(1, 'A-id')
2841
 
        wt.commit('C', rev_id=b'C-id', recursive=None)
 
2728
        wt.commit('C', rev_id='C-id', recursive=None)
2842
2729
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2843
2730
        wt.rename_one('sub', 'alt_sub')
2844
 
        wt.commit('E', rev_id=b'E-id', recursive=None)
 
2731
        wt.commit('E', rev_id='E-id', recursive=None)
2845
2732
        wt.set_last_revision('B-id')
2846
2733
        wt.revert()
2847
2734
        wt.set_parent_ids(['B-id', 'C-id'])
2848
2735
        wt.branch.set_last_revision_info(2, 'B-id')
2849
 
        wt.commit('D', rev_id=b'D-id', recursive=None)
 
2736
        wt.commit('D', rev_id='D-id', recursive=None)
2850
2737
 
2851
 
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
 
2738
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2739
            wt, 'E-id')
2852
2740
        merger.merge_type = _mod_merge.Merge3Merger
2853
2741
        merge_obj = merger.make_merger()
2854
2742
        entries = list(merge_obj._entries_lca())
2855
2743
        root_id = 'a-root-id'
2856
2744
        self.assertEqual([('sub-tree-root', False,
2857
 
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2858
2745
                           ((root_id, [root_id, root_id]), root_id, root_id),
2859
2746
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2860
2747
                           ((False, [False, False]), False, False)),
2869
2756
        self.addCleanup(wt.unlock)
2870
2757
        sub_tree = self.make_branch_and_tree('tree/sub',
2871
2758
            format='development-subtree')
2872
 
        wt.set_root_id(b'a-root-id')
2873
 
        sub_tree.set_root_id(b'sub-tree-root')
2874
 
        self.build_tree_contents([('tree/sub/file', b'text1')])
 
2759
        wt.set_root_id('a-root-id')
 
2760
        sub_tree.set_root_id('sub-tree-root')
 
2761
        self.build_tree_contents([('tree/sub/file', 'text1')])
2875
2762
        sub_tree.add('file')
2876
 
        sub_tree.commit('foo', rev_id=b'sub-A-id')
 
2763
        sub_tree.commit('foo', rev_id='sub-A-id')
2877
2764
        wt.add_reference(sub_tree)
2878
 
        wt.commit('set text to 1', rev_id=b'A-id', recursive=None)
 
2765
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2879
2766
        # Now create a criss-cross merge in the parent, without modifying the
2880
2767
        # subtree
2881
 
        wt.commit('B', rev_id=b'B-id', recursive=None)
 
2768
        wt.commit('B', rev_id='B-id', recursive=None)
2882
2769
        wt.set_last_revision('A-id')
2883
2770
        wt.branch.set_last_revision_info(1, 'A-id')
2884
 
        wt.commit('C', rev_id=b'C-id', recursive=None)
 
2771
        wt.commit('C', rev_id='C-id', recursive=None)
2885
2772
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2886
 
        self.build_tree_contents([('tree/sub/file', b'text2')])
2887
 
        sub_tree.commit('modify contents', rev_id=b'sub-B-id')
 
2773
        self.build_tree_contents([('tree/sub/file', 'text2')])
 
2774
        sub_tree.commit('modify contents', rev_id='sub-B-id')
2888
2775
        wt.rename_one('sub', 'alt_sub')
2889
 
        wt.commit('E', rev_id=b'E-id', recursive=None)
 
2776
        wt.commit('E', rev_id='E-id', recursive=None)
2890
2777
        wt.set_last_revision('B-id')
2891
2778
        wt.revert()
2892
2779
        wt.set_parent_ids(['B-id', 'C-id'])
2893
2780
        wt.branch.set_last_revision_info(2, 'B-id')
2894
 
        wt.commit('D', rev_id=b'D-id', recursive=None)
 
2781
        wt.commit('D', rev_id='D-id', recursive=None)
2895
2782
 
2896
 
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
 
2783
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2784
            wt, 'E-id')
2897
2785
        merger.merge_type = _mod_merge.Merge3Merger
2898
2786
        merge_obj = merger.make_merger()
2899
2787
        entries = list(merge_obj._entries_lca())
2900
2788
        root_id = 'a-root-id'
2901
2789
        self.assertEqual([('sub-tree-root', False,
2902
 
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2903
2790
                           ((root_id, [root_id, root_id]), root_id, root_id),
2904
2791
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2905
2792
                           ((False, [False, False]), False, False)),
3291
3178
        # dest.
3292
3179
        src_wt = self.make_branch_and_tree('src')
3293
3180
        self.build_tree(['src/README'])
3294
 
        src_wt.add(['README'], ids=[b'dest-file.txt-id'])
3295
 
        src_wt.commit("Rev 1 of src.", rev_id=b'r1-src')
 
3181
        src_wt.add(['README'], ids=['dest-file.txt-id'])
 
3182
        src_wt.commit("Rev 1 of src.", rev_id='r1-src')
3296
3183
        conflicts = self.do_merge_into('src', 'dest/dir')
3297
3184
        # This is an edge case that shouldn't happen to users very often.  So
3298
3185
        # we don't care really about the exact presentation of the conflict,
3366
3253
    def setUp(self):
3367
3254
        super(TestMergeHooks, self).setUp()
3368
3255
        self.tree_a = self.make_branch_and_tree('tree_a')
3369
 
        self.build_tree_contents([('tree_a/file', b'content_1')])
3370
 
        self.tree_a.add('file', b'file-id')
 
3256
        self.build_tree_contents([('tree_a/file', 'content_1')])
 
3257
        self.tree_a.add('file', 'file-id')
3371
3258
        self.tree_a.commit('added file')
3372
3259
 
3373
 
        self.tree_b = self.tree_a.controldir.sprout('tree_b').open_workingtree()
3374
 
        self.build_tree_contents([('tree_b/file', b'content_2')])
 
3260
        self.tree_b = self.tree_a.bzrdir.sprout('tree_b').open_workingtree()
 
3261
        self.build_tree_contents([('tree_b/file', 'content_2')])
3375
3262
        self.tree_b.commit('modify file')
3376
3263
 
3377
3264
    def test_pre_merge_hook_inject_different_tree(self):
3378
 
        tree_c = self.tree_b.controldir.sprout('tree_c').open_workingtree()
3379
 
        self.build_tree_contents([('tree_c/file', b'content_3')])
 
3265
        tree_c = self.tree_b.bzrdir.sprout('tree_c').open_workingtree()
 
3266
        self.build_tree_contents([('tree_c/file', 'content_3')])
3380
3267
        tree_c.commit("more content")
3381
3268
        calls = []
3382
3269
        def factory(merger):