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

  • Committer: John Arbash Meinel
  • Date: 2009-12-10 17:16:19 UTC
  • mfrom: (4884 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4889.
  • Revision ID: john@arbash-meinel.com-20091210171619-ehdcxjbl8afhq9g1
Bring in bzr.dev 4884

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
 
import errno
19
 
from itertools import chain
20
 
import os
21
 
import warnings
22
 
 
23
18
from bzrlib import (
 
19
    branch as _mod_branch,
 
20
    conflicts as _mod_conflicts,
24
21
    debug,
25
22
    errors,
26
23
    graph as _mod_graph,
 
24
    merge3,
27
25
    osutils,
28
26
    patiencediff,
 
27
    progress,
29
28
    registry,
30
29
    revision as _mod_revision,
 
30
    textfile,
 
31
    trace,
 
32
    transform,
31
33
    tree as _mod_tree,
32
34
    tsort,
33
 
    )
34
 
from bzrlib.branch import Branch
35
 
from bzrlib.conflicts import ConflictList, Conflict
36
 
from bzrlib.errors import (BzrCommandError,
37
 
                           BzrError,
38
 
                           NoCommonAncestor,
39
 
                           NoCommits,
40
 
                           NoSuchRevision,
41
 
                           NoSuchFile,
42
 
                           NotBranchError,
43
 
                           NotVersionedError,
44
 
                           UnrelatedBranches,
45
 
                           UnsupportedOperation,
46
 
                           WorkingTreeNotRevision,
47
 
                           BinaryFile,
48
 
                           )
49
 
from bzrlib.graph import Graph
50
 
from bzrlib.merge3 import Merge3
51
 
from bzrlib.osutils import rename, pathjoin
52
 
from progress import DummyProgress, ProgressPhase
53
 
from bzrlib.revision import (NULL_REVISION, ensure_null)
54
 
from bzrlib.textfile import check_text_lines
55
 
from bzrlib.trace import mutter, warning, note, is_quiet
56
 
from bzrlib.transform import (TransformPreview, TreeTransform,
57
 
                              resolve_conflicts, cook_conflicts,
58
 
                              conflict_pass, FinalPaths, create_from_tree,
59
 
                              unique_add, ROOT_PARENT)
60
 
from bzrlib.versionedfile import PlanWeaveMerge
61
 
from bzrlib import ui
62
 
 
 
35
    ui,
 
36
    versionedfile
 
37
    )
 
38
from bzrlib.symbol_versioning import (
 
39
    deprecated_in,
 
40
    deprecated_method,
 
41
    )
63
42
# TODO: Report back as changes are merged in
64
43
 
65
44
 
94
73
        self.show_base = False
95
74
        self.reprocess = False
96
75
        if pb is None:
97
 
            pb = DummyProgress()
 
76
            pb = progress.DummyProgress()
98
77
        self._pb = pb
99
78
        self.pp = None
100
79
        self.recurse = recurse
184
163
                base_revision_id, tree.branch.last_revision())):
185
164
                base_revision_id = None
186
165
            else:
187
 
                warning('Performing cherrypick')
 
166
                trace.warning('Performing cherrypick')
188
167
        merger = klass.from_revision_ids(pb, tree, other_revision_id,
189
168
                                         base_revision_id, revision_graph=
190
169
                                         revision_graph)
242
221
        if revno is None:
243
222
            tree = workingtree.WorkingTree.open_containing(location)[0]
244
223
            return tree.branch, tree
245
 
        branch = Branch.open_containing(location, possible_transports)[0]
 
224
        branch = _mod_branch.Branch.open_containing(
 
225
            location, possible_transports)[0]
246
226
        if revno == -1:
247
227
            revision_id = branch.last_revision()
248
228
        else:
249
229
            revision_id = branch.get_rev_id(revno)
250
 
        revision_id = ensure_null(revision_id)
 
230
        revision_id = _mod_revision.ensure_null(revision_id)
251
231
        return branch, self.revision_tree(revision_id, branch)
252
232
 
 
233
    @deprecated_method(deprecated_in((2, 1, 0)))
253
234
    def ensure_revision_trees(self):
254
235
        if self.this_revision_tree is None:
255
236
            self.this_basis_tree = self.revision_tree(self.this_basis)
263
244
            other_rev_id = self.other_basis
264
245
            self.other_tree = other_basis_tree
265
246
 
 
247
    @deprecated_method(deprecated_in((2, 1, 0)))
266
248
    def file_revisions(self, file_id):
267
249
        self.ensure_revision_trees()
268
250
        def get_id(tree, file_id):
271
253
        if self.this_rev_id is None:
272
254
            if self.this_basis_tree.get_file_sha1(file_id) != \
273
255
                self.this_tree.get_file_sha1(file_id):
274
 
                raise WorkingTreeNotRevision(self.this_tree)
 
256
                raise errors.WorkingTreeNotRevision(self.this_tree)
275
257
 
276
258
        trees = (self.this_basis_tree, self.other_tree)
277
259
        return [get_id(tree, file_id) for tree in trees]
278
260
 
 
261
    @deprecated_method(deprecated_in((2, 1, 0)))
279
262
    def check_basis(self, check_clean, require_commits=True):
280
263
        if self.this_basis is None and require_commits is True:
281
 
            raise BzrCommandError("This branch has no commits."
282
 
                                  " (perhaps you would prefer 'bzr pull')")
 
264
            raise errors.BzrCommandError(
 
265
                "This branch has no commits."
 
266
                " (perhaps you would prefer 'bzr pull')")
283
267
        if check_clean:
284
268
            self.compare_basis()
285
269
            if self.this_basis != self.this_rev_id:
286
270
                raise errors.UncommittedChanges(self.this_tree)
287
271
 
 
272
    @deprecated_method(deprecated_in((2, 1, 0)))
288
273
    def compare_basis(self):
289
274
        try:
290
275
            basis_tree = self.revision_tree(self.this_tree.last_revision())
297
282
        self.interesting_files = file_list
298
283
 
299
284
    def set_pending(self):
300
 
        if not self.base_is_ancestor or not self.base_is_other_ancestor or self.other_rev_id is None:
 
285
        if (not self.base_is_ancestor or not self.base_is_other_ancestor
 
286
            or self.other_rev_id is None):
301
287
            return
302
288
        self._add_parent()
303
289
 
333
319
            self.other_rev_id = _mod_revision.ensure_null(
334
320
                self.other_branch.last_revision())
335
321
            if _mod_revision.is_null(self.other_rev_id):
336
 
                raise NoCommits(self.other_branch)
 
322
                raise errors.NoCommits(self.other_branch)
337
323
            self.other_basis = self.other_rev_id
338
324
        elif other_revision[1] is not None:
339
325
            self.other_rev_id = self.other_branch.get_rev_id(other_revision[1])
342
328
            self.other_rev_id = None
343
329
            self.other_basis = self.other_branch.last_revision()
344
330
            if self.other_basis is None:
345
 
                raise NoCommits(self.other_branch)
 
331
                raise errors.NoCommits(self.other_branch)
346
332
        if self.other_rev_id is not None:
347
333
            self._cached_trees[self.other_rev_id] = self.other_tree
348
334
        self._maybe_fetch(self.other_branch,self.this_branch, self.other_basis)
375
361
            target.fetch(source, revision_id)
376
362
 
377
363
    def find_base(self):
378
 
        revisions = [ensure_null(self.this_basis),
379
 
                     ensure_null(self.other_basis)]
380
 
        if NULL_REVISION in revisions:
381
 
            self.base_rev_id = NULL_REVISION
 
364
        revisions = [_mod_revision.ensure_null(self.this_basis),
 
365
                     _mod_revision.ensure_null(self.other_basis)]
 
366
        if _mod_revision.NULL_REVISION in revisions:
 
367
            self.base_rev_id = _mod_revision.NULL_REVISION
382
368
            self.base_tree = self.revision_tree(self.base_rev_id)
383
369
            self._is_criss_cross = False
384
370
        else:
385
371
            lcas = self.revision_graph.find_lca(revisions[0], revisions[1])
386
372
            self._is_criss_cross = False
387
373
            if len(lcas) == 0:
388
 
                self.base_rev_id = NULL_REVISION
 
374
                self.base_rev_id = _mod_revision.NULL_REVISION
389
375
            elif len(lcas) == 1:
390
376
                self.base_rev_id = list(lcas)[0]
391
377
            else: # len(lcas) > 1
400
386
                    self.base_rev_id = self.revision_graph.find_unique_lca(
401
387
                                            *lcas)
402
388
                self._is_criss_cross = True
403
 
            if self.base_rev_id == NULL_REVISION:
404
 
                raise UnrelatedBranches()
 
389
            if self.base_rev_id == _mod_revision.NULL_REVISION:
 
390
                raise errors.UnrelatedBranches()
405
391
            if self._is_criss_cross:
406
 
                warning('Warning: criss-cross merge encountered.  See bzr'
407
 
                        ' help criss-cross.')
408
 
                mutter('Criss-cross lcas: %r' % lcas)
 
392
                trace.warning('Warning: criss-cross merge encountered.  See bzr'
 
393
                              ' help criss-cross.')
 
394
                trace.mutter('Criss-cross lcas: %r' % lcas)
409
395
                interesting_revision_ids = [self.base_rev_id]
410
396
                interesting_revision_ids.extend(lcas)
411
397
                interesting_trees = dict((t.get_revision_id(), t)
421
407
                self.base_tree = self.revision_tree(self.base_rev_id)
422
408
        self.base_is_ancestor = True
423
409
        self.base_is_other_ancestor = True
424
 
        mutter('Base revid: %r' % self.base_rev_id)
 
410
        trace.mutter('Base revid: %r' % self.base_rev_id)
425
411
 
426
412
    def set_base(self, base_revision):
427
413
        """Set the base revision to use for the merge.
428
414
 
429
415
        :param base_revision: A 2-list containing a path and revision number.
430
416
        """
431
 
        mutter("doing merge() with no base_revision specified")
 
417
        trace.mutter("doing merge() with no base_revision specified")
432
418
        if base_revision == [None, None]:
433
419
            self.find_base()
434
420
        else:
454
440
        if self.merge_type.supports_reprocess:
455
441
            kwargs['reprocess'] = self.reprocess
456
442
        elif self.reprocess:
457
 
            raise BzrError("Conflict reduction is not supported for merge"
458
 
                                  " type %s." % self.merge_type)
 
443
            raise errors.BzrError(
 
444
                "Conflict reduction is not supported for merge"
 
445
                " type %s." % self.merge_type)
459
446
        if self.merge_type.supports_show_base:
460
447
            kwargs['show_base'] = self.show_base
461
448
        elif self.show_base:
462
 
            raise BzrError("Showing base is not supported for this"
463
 
                           " merge type. %s" % self.merge_type)
 
449
            raise errors.BzrError("Showing base is not supported for this"
 
450
                                  " merge type. %s" % self.merge_type)
464
451
        if (not getattr(self.merge_type, 'supports_reverse_cherrypick', True)
465
452
            and not self.base_is_other_ancestor):
466
453
            raise errors.CannotReverseCherrypick()
515
502
        finally:
516
503
            self.this_tree.unlock()
517
504
        if len(merge.cooked_conflicts) == 0:
518
 
            if not self.ignore_zero and not is_quiet():
519
 
                note("All changes applied successfully.")
 
505
            if not self.ignore_zero and not trace.is_quiet():
 
506
                trace.note("All changes applied successfully.")
520
507
        else:
521
 
            note("%d conflicts encountered." % len(merge.cooked_conflicts))
 
508
            trace.note("%d conflicts encountered."
 
509
                       % len(merge.cooked_conflicts))
522
510
 
523
511
        return len(merge.cooked_conflicts)
524
512
 
553
541
 
554
542
    def __init__(self, working_tree, this_tree, base_tree, other_tree,
555
543
                 interesting_ids=None, reprocess=False, show_base=False,
556
 
                 pb=DummyProgress(), pp=None, change_reporter=None,
 
544
                 pb=progress.DummyProgress(), pp=None, change_reporter=None,
557
545
                 interesting_files=None, do_merge=True,
558
546
                 cherrypick=False, lca_trees=None):
559
547
        """Initialize the merger object and perform the merge.
605
593
        self.change_reporter = change_reporter
606
594
        self.cherrypick = cherrypick
607
595
        if self.pp is None:
608
 
            self.pp = ProgressPhase("Merge phase", 3, self.pb)
 
596
            self.pp = progress.ProgressPhase("Merge phase", 3, self.pb)
609
597
        if do_merge:
610
598
            self.do_merge()
611
599
 
614
602
        self.base_tree.lock_read()
615
603
        self.other_tree.lock_read()
616
604
        try:
617
 
            self.tt = TreeTransform(self.this_tree, self.pb)
 
605
            self.tt = transform.TreeTransform(self.this_tree, self.pb)
618
606
            try:
619
607
                self.pp.next_phase()
620
608
                self._compute_transform()
623
611
                self.write_modified(results)
624
612
                try:
625
613
                    self.this_tree.add_conflicts(self.cooked_conflicts)
626
 
                except UnsupportedOperation:
 
614
                except errors.UnsupportedOperation:
627
615
                    pass
628
616
            finally:
629
617
                self.tt.finalize()
636
624
    def make_preview_transform(self):
637
625
        self.base_tree.lock_read()
638
626
        self.other_tree.lock_read()
639
 
        self.tt = TransformPreview(self.this_tree)
 
627
        self.tt = transform.TransformPreview(self.this_tree)
640
628
        try:
641
629
            self.pp.next_phase()
642
630
            self._compute_transform()
672
660
        self.pp.next_phase()
673
661
        child_pb = ui.ui_factory.nested_progress_bar()
674
662
        try:
675
 
            fs_conflicts = resolve_conflicts(self.tt, child_pb,
676
 
                lambda t, c: conflict_pass(t, c, self.other_tree))
 
663
            fs_conflicts = transform.resolve_conflicts(self.tt, child_pb,
 
664
                lambda t, c: transform.conflict_pass(t, c, self.other_tree))
677
665
        finally:
678
666
            child_pb.finished()
679
667
        if self.change_reporter is not None:
682
670
                self.tt.iter_changes(), self.change_reporter)
683
671
        self.cook_conflicts(fs_conflicts)
684
672
        for conflict in self.cooked_conflicts:
685
 
            warning(conflict)
 
673
            trace.warning(conflict)
686
674
 
687
675
    def _entries3(self):
688
676
        """Gather data about files modified between three trees.
890
878
    def fix_root(self):
891
879
        try:
892
880
            self.tt.final_kind(self.tt.root)
893
 
        except NoSuchFile:
 
881
        except errors.NoSuchFile:
894
882
            self.tt.cancel_deletion(self.tt.root)
895
883
        if self.tt.final_file_id(self.tt.root) is None:
896
884
            self.tt.version_file(self.tt.tree_file_id(self.tt.root),
903
891
            return
904
892
        try:
905
893
            self.tt.final_kind(other_root)
906
 
        except NoSuchFile:
 
894
        except errors.NoSuchFile:
907
895
            return
908
896
        if self.other_tree.inventory.root.file_id in self.this_tree.inventory:
909
897
            # the other tree's root is a non-root in the current tree
1175
1163
                else:
1176
1164
                    # Skip the id2path lookup for older formats
1177
1165
                    filter_tree_path = None
1178
 
                create_from_tree(self.tt, trans_id,
 
1166
                transform.create_from_tree(self.tt, trans_id,
1179
1167
                                 self.other_tree, file_id,
1180
1168
                                 filter_tree_path=filter_tree_path)
1181
1169
                if not file_in_this:
1194
1182
                # have agreement that output should be a file.
1195
1183
                try:
1196
1184
                    self.text_merge(file_id, trans_id)
1197
 
                except BinaryFile:
 
1185
                except errors.BinaryFile:
1198
1186
                    return contents_conflict()
1199
1187
                if file_id not in self.this_tree:
1200
1188
                    self.tt.version_file(file_id, trans_id)
1201
1189
                try:
1202
1190
                    self.tt.tree_kind(trans_id)
1203
1191
                    self.tt.delete_contents(trans_id)
1204
 
                except NoSuchFile:
 
1192
                except errors.NoSuchFile:
1205
1193
                    pass
1206
1194
                return "modified"
1207
1195
            else:
1225
1213
            base_lines = []
1226
1214
        other_lines = self.get_lines(self.other_tree, file_id)
1227
1215
        this_lines = self.get_lines(self.this_tree, file_id)
1228
 
        m3 = Merge3(base_lines, this_lines, other_lines,
1229
 
                    is_cherrypick=self.cherrypick)
 
1216
        m3 = merge3.Merge3(base_lines, this_lines, other_lines,
 
1217
                           is_cherrypick=self.cherrypick)
1230
1218
        start_marker = "!START OF MERGE CONFLICT!" + "I HOPE THIS IS UNIQUE"
1231
1219
        if self.show_base is True:
1232
1220
            base_marker = '|' * 7
1301
1289
        """Emit a single conflict file."""
1302
1290
        name = name + '.' + suffix
1303
1291
        trans_id = self.tt.create_path(name, parent_id)
1304
 
        create_from_tree(self.tt, trans_id, tree, file_id, lines,
 
1292
        transform.create_from_tree(self.tt, trans_id, tree, file_id, lines,
1305
1293
            filter_tree_path)
1306
1294
        return trans_id
1307
1295
 
1332
1320
        try:
1333
1321
            if self.tt.final_kind(trans_id) != "file":
1334
1322
                return
1335
 
        except NoSuchFile:
 
1323
        except errors.NoSuchFile:
1336
1324
            return
1337
1325
        if winner == "this":
1338
1326
            executability = this_executable
1349
1337
 
1350
1338
    def cook_conflicts(self, fs_conflicts):
1351
1339
        """Convert all conflicts into a form that doesn't depend on trans_id"""
1352
 
        from conflicts import Conflict
1353
1340
        name_conflicts = {}
1354
 
        self.cooked_conflicts.extend(cook_conflicts(fs_conflicts, self.tt))
1355
 
        fp = FinalPaths(self.tt)
 
1341
        self.cooked_conflicts.extend(transform.cook_conflicts(
 
1342
                fs_conflicts, self.tt))
 
1343
        fp = transform.FinalPaths(self.tt)
1356
1344
        for conflict in self._raw_conflicts:
1357
1345
            conflict_type = conflict[0]
1358
1346
            if conflict_type in ('name conflict', 'parent conflict'):
1360
1348
                conflict_args = conflict[2:]
1361
1349
                if trans_id not in name_conflicts:
1362
1350
                    name_conflicts[trans_id] = {}
1363
 
                unique_add(name_conflicts[trans_id], conflict_type,
1364
 
                           conflict_args)
 
1351
                transform.unique_add(name_conflicts[trans_id], conflict_type,
 
1352
                                     conflict_args)
1365
1353
            if conflict_type == 'contents conflict':
1366
1354
                for trans_id in conflict[1]:
1367
1355
                    file_id = self.tt.final_file_id(trans_id)
1372
1360
                    if path.endswith(suffix):
1373
1361
                        path = path[:-len(suffix)]
1374
1362
                        break
1375
 
                c = Conflict.factory(conflict_type, path=path, file_id=file_id)
 
1363
                c = _mod_conflicts.Conflict.factory(conflict_type,
 
1364
                                                    path=path, file_id=file_id)
1376
1365
                self.cooked_conflicts.append(c)
1377
1366
            if conflict_type == 'text conflict':
1378
1367
                trans_id = conflict[1]
1379
1368
                path = fp.get_path(trans_id)
1380
1369
                file_id = self.tt.final_file_id(trans_id)
1381
 
                c = Conflict.factory(conflict_type, path=path, file_id=file_id)
 
1370
                c = _mod_conflicts.Conflict.factory(conflict_type,
 
1371
                                                    path=path, file_id=file_id)
1382
1372
                self.cooked_conflicts.append(c)
1383
1373
 
1384
1374
        for trans_id, conflicts in name_conflicts.iteritems():
1399
1389
            if this_parent is not None and this_name is not None:
1400
1390
                this_parent_path = \
1401
1391
                    fp.get_path(self.tt.trans_id_file_id(this_parent))
1402
 
                this_path = pathjoin(this_parent_path, this_name)
 
1392
                this_path = osutils.pathjoin(this_parent_path, this_name)
1403
1393
            else:
1404
1394
                this_path = "<deleted>"
1405
1395
            file_id = self.tt.final_file_id(trans_id)
1406
 
            c = Conflict.factory('path conflict', path=this_path,
1407
 
                                 conflict_path=other_path, file_id=file_id)
 
1396
            c = _mod_conflicts.Conflict.factory('path conflict', path=this_path,
 
1397
                                                conflict_path=other_path,
 
1398
                                                file_id=file_id)
1408
1399
            self.cooked_conflicts.append(c)
1409
 
        self.cooked_conflicts.sort(key=Conflict.sort_key)
 
1400
        self.cooked_conflicts.sort(key=_mod_conflicts.Conflict.sort_key)
1410
1401
 
1411
1402
 
1412
1403
class WeaveMerger(Merge3Merger):
1436
1427
            name = self.tt.final_name(trans_id) + '.plan'
1437
1428
            contents = ('%11s|%s' % l for l in plan)
1438
1429
            self.tt.new_file(name, self.tt.final_parent(trans_id), contents)
1439
 
        textmerge = PlanWeaveMerge(plan, '<<<<<<< TREE\n',
1440
 
            '>>>>>>> MERGE-SOURCE\n')
 
1430
        textmerge = versionedfile.PlanWeaveMerge(plan, '<<<<<<< TREE\n',
 
1431
                                                 '>>>>>>> MERGE-SOURCE\n')
1441
1432
        lines, conflicts = textmerge.merge_lines(self.reprocess)
1442
1433
        if conflicts:
1443
1434
            base_lines = textmerge.base_from_plan()
1454
1445
        lines = list(lines)
1455
1446
        # Note we're checking whether the OUTPUT is binary in this case,
1456
1447
        # because we don't want to get into weave merge guts.
1457
 
        check_text_lines(lines)
 
1448
        textfile.check_text_lines(lines)
1458
1449
        self.tt.create_file(lines, trans_id)
1459
1450
        if base_lines is not None:
1460
1451
            # Conflict
1472
1463
    def _generate_merge_plan(self, file_id, base):
1473
1464
        return self.this_tree.plan_file_lca_merge(file_id, self.other_tree,
1474
1465
                                                  base=base)
1475
 
        
1476
1466
 
1477
1467
class Diff3Merger(Merge3Merger):
1478
1468
    """Three-way merger using external diff3 for text merging"""
1479
1469
 
1480
1470
    def dump_file(self, temp_dir, name, tree, file_id):
1481
 
        out_path = pathjoin(temp_dir, name)
 
1471
        out_path = osutils.pathjoin(temp_dir, name)
1482
1472
        out_file = open(out_path, "wb")
1483
1473
        try:
1484
1474
            in_file = tree.get_file(file_id)
1496
1486
        import bzrlib.patch
1497
1487
        temp_dir = osutils.mkdtemp(prefix="bzr-")
1498
1488
        try:
1499
 
            new_file = pathjoin(temp_dir, "new")
 
1489
            new_file = osutils.pathjoin(temp_dir, "new")
1500
1490
            this = self.dump_file(temp_dir, "this", self.this_tree, file_id)
1501
1491
            base = self.dump_file(temp_dir, "base", self.base_tree, file_id)
1502
1492
            other = self.dump_file(temp_dir, "other", self.other_tree, file_id)
1503
1493
            status = bzrlib.patch.diff3(new_file, this, base, other)
1504
1494
            if status not in (0, 1):
1505
 
                raise BzrError("Unhandled diff3 exit code")
 
1495
                raise errors.BzrError("Unhandled diff3 exit code")
1506
1496
            f = open(new_file, 'rb')
1507
1497
            try:
1508
1498
                self.tt.create_file(f, trans_id)
1526
1516
                other_rev_id=None,
1527
1517
                interesting_files=None,
1528
1518
                this_tree=None,
1529
 
                pb=DummyProgress(),
 
1519
                pb=progress.DummyProgress(),
1530
1520
                change_reporter=None):
1531
1521
    """Primary interface for merging.
1532
1522
 
1535
1525
                     branch.get_revision_tree(base_revision))'
1536
1526
        """
1537
1527
    if this_tree is None:
1538
 
        raise BzrError("bzrlib.merge.merge_inner requires a this_tree "
1539
 
            "parameter as of bzrlib version 0.8.")
 
1528
        raise errors.BzrError("bzrlib.merge.merge_inner requires a this_tree "
 
1529
                              "parameter as of bzrlib version 0.8.")
1540
1530
    merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
1541
1531
                    pb=pb, change_reporter=change_reporter)
1542
1532
    merger.backup_files = backup_files
1760
1750
        super(_PlanMerge, self).__init__(a_rev, b_rev, vf, key_prefix)
1761
1751
        self.a_key = self._key_prefix + (self.a_rev,)
1762
1752
        self.b_key = self._key_prefix + (self.b_rev,)
1763
 
        self.graph = Graph(self.vf)
 
1753
        self.graph = _mod_graph.Graph(self.vf)
1764
1754
        heads = self.graph.heads((self.a_key, self.b_key))
1765
1755
        if len(heads) == 1:
1766
1756
            # one side dominates, so we can just return its values, yay for
1771
1761
                other = b_rev
1772
1762
            else:
1773
1763
                other = a_rev
1774
 
            mutter('found dominating revision for %s\n%s > %s', self.vf,
1775
 
                   self._head_key[-1], other)
 
1764
            trace.mutter('found dominating revision for %s\n%s > %s', self.vf,
 
1765
                         self._head_key[-1], other)
1776
1766
            self._weave = None
1777
1767
        else:
1778
1768
            self._head_key = None
1792
1782
        while True:
1793
1783
            next_lcas = self.graph.find_lca(*cur_ancestors)
1794
1784
            # Map a plain NULL_REVISION to a simple no-ancestors
1795
 
            if next_lcas == set([NULL_REVISION]):
 
1785
            if next_lcas == set([_mod_revision.NULL_REVISION]):
1796
1786
                next_lcas = ()
1797
1787
            # Order the lca's based on when they were merged into the tip
1798
1788
            # While the actual merge portion of weave merge uses a set() of
1810
1800
            elif len(next_lcas) > 2:
1811
1801
                # More than 2 lca's, fall back to grabbing all nodes between
1812
1802
                # this and the unique lca.
1813
 
                mutter('More than 2 LCAs, falling back to all nodes for:'
1814
 
                       ' %s, %s\n=> %s', self.a_key, self.b_key, cur_ancestors)
 
1803
                trace.mutter('More than 2 LCAs, falling back to all nodes for:'
 
1804
                             ' %s, %s\n=> %s',
 
1805
                             self.a_key, self.b_key, cur_ancestors)
1815
1806
                cur_lcas = next_lcas
1816
1807
                while len(cur_lcas) > 1:
1817
1808
                    cur_lcas = self.graph.find_lca(*cur_lcas)
1820
1811
                    unique_lca = None
1821
1812
                else:
1822
1813
                    unique_lca = list(cur_lcas)[0]
1823
 
                    if unique_lca == NULL_REVISION:
 
1814
                    if unique_lca == _mod_revision.NULL_REVISION:
1824
1815
                        # find_lca will return a plain 'NULL_REVISION' rather
1825
1816
                        # than a key tuple when there is no common ancestor, we
1826
1817
                        # prefer to just use None, because it doesn't confuse
1849
1840
            # We remove NULL_REVISION because it isn't a proper tuple key, and
1850
1841
            # thus confuses things like _get_interesting_texts, and our logic
1851
1842
            # to add the texts into the memory weave.
1852
 
            if NULL_REVISION in parent_map:
1853
 
                parent_map.pop(NULL_REVISION)
 
1843
            if _mod_revision.NULL_REVISION in parent_map:
 
1844
                parent_map.pop(_mod_revision.NULL_REVISION)
1854
1845
        else:
1855
1846
            interesting = set()
1856
1847
            for tip in tip_keys:
2008
1999
        lcas = graph.find_lca(key_prefix + (a_rev,), key_prefix + (b_rev,))
2009
2000
        self.lcas = set()
2010
2001
        for lca in lcas:
2011
 
            if lca == NULL_REVISION:
 
2002
            if lca == _mod_revision.NULL_REVISION:
2012
2003
                self.lcas.add(lca)
2013
2004
            else:
2014
2005
                self.lcas.add(lca[-1])