/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: Martin Pool
  • Date: 2009-03-13 07:54:48 UTC
  • mfrom: (4144 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4189.
  • Revision ID: mbp@sourcefrog.net-20090313075448-jlz1t7baz7gzipqn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
 
71
71
class Merger(object):
72
72
    def __init__(self, this_branch, other_tree=None, base_tree=None,
73
 
                 this_tree=None, pb=DummyProgress(), change_reporter=None,
 
73
                 this_tree=None, pb=None, change_reporter=None,
74
74
                 recurse='down', revision_graph=None):
75
75
        object.__init__(self)
76
76
        self.this_branch = this_branch
89
89
        self.interesting_files = None
90
90
        self.show_base = False
91
91
        self.reprocess = False
 
92
        if pb is None:
 
93
            pb = DummyProgress()
92
94
        self._pb = pb
93
95
        self.pp = None
94
96
        self.recurse = recurse
132
134
                                      _set_base_is_other_ancestor)
133
135
 
134
136
    @staticmethod
135
 
    def from_uncommitted(tree, other_tree, pb, base_tree=None):
 
137
    def from_uncommitted(tree, other_tree, pb=None, base_tree=None):
136
138
        """Return a Merger for uncommitted changes in other_tree.
137
139
 
138
140
        :param tree: The tree to merge into
390
392
            if self._is_criss_cross:
391
393
                warning('Warning: criss-cross merge encountered.  See bzr'
392
394
                        ' help criss-cross.')
 
395
                mutter('Criss-cross lcas: %r' % lcas)
393
396
                interesting_revision_ids = [self.base_rev_id]
394
397
                interesting_revision_ids.extend(lcas)
395
398
                interesting_trees = dict((t.get_revision_id(), t)
405
408
                self.base_tree = self.revision_tree(self.base_rev_id)
406
409
        self.base_is_ancestor = True
407
410
        self.base_is_other_ancestor = True
 
411
        mutter('Base revid: %r' % self.base_rev_id)
408
412
 
409
413
    def set_base(self, base_revision):
410
414
        """Set the base revision to use for the merge.
475
479
                    sub_tree.branch.repository.revision_tree(base_revision)
476
480
                sub_merge.base_rev_id = base_revision
477
481
                sub_merge.do_merge()
478
 
        
 
482
 
479
483
    def do_merge(self):
480
484
        self.this_tree.lock_tree_write()
481
485
        try:
532
536
    winner_idx = {"this": 2, "other": 1, "conflict": 1}
533
537
    supports_lca_trees = True
534
538
 
535
 
    def __init__(self, working_tree, this_tree, base_tree, other_tree, 
 
539
    def __init__(self, working_tree, this_tree, base_tree, other_tree,
536
540
                 interesting_ids=None, reprocess=False, show_base=False,
537
541
                 pb=DummyProgress(), pp=None, change_reporter=None,
538
542
                 interesting_files=None, do_merge=True,
794
798
            content_changed = True
795
799
            if kind_winner == 'this':
796
800
                # No kind change in OTHER, see if there are *any* changes
797
 
                if other_ie.kind == None:
798
 
                    # No content and 'this' wins the kind, so skip this?
799
 
                    # continue
800
 
                    pass
801
 
                elif other_ie.kind == 'directory':
 
801
                if other_ie.kind == 'directory':
802
802
                    if parent_id_winner == 'this' and name_winner == 'this':
803
803
                        # No change for this directory in OTHER, skip
804
804
                        continue
805
805
                    content_changed = False
806
 
                elif other_ie.kind == 'file':
 
806
                elif other_ie.kind is None or other_ie.kind == 'file':
807
807
                    def get_sha1(ie, tree):
808
808
                        if ie.kind != 'file':
809
809
                            return None
876
876
        except NoSuchFile:
877
877
            self.tt.cancel_deletion(self.tt.root)
878
878
        if self.tt.final_file_id(self.tt.root) is None:
879
 
            self.tt.version_file(self.tt.tree_file_id(self.tt.root), 
 
879
            self.tt.version_file(self.tt.tree_file_id(self.tt.root),
880
880
                                 self.tt.root)
881
881
        other_root_file_id = self.other_tree.get_root_id()
882
882
        if other_root_file_id is None:
925
925
        if entry is None:
926
926
            return None
927
927
        return entry.name
928
 
    
 
928
 
929
929
    @staticmethod
930
930
    def contents_sha1(tree, file_id):
931
931
        """Determine the sha1 of the file contents (used as a key method)."""
979
979
        :return: 'this', 'other', or 'conflict' depending on whether an entry
980
980
            changed or not.
981
981
        """
982
 
        # See doc/developers/lca_merge_resolution.txt for details about this
 
982
        # See doc/developers/lca_tree_merging.txt for details about this
983
983
        # algorithm.
984
984
        if other == this:
985
985
            # Either Ambiguously clean, or nothing was actually changed. We
1071
1071
            return
1072
1072
        if name_winner == "conflict":
1073
1073
            trans_id = self.tt.trans_id_file_id(file_id)
1074
 
            self._raw_conflicts.append(('name conflict', trans_id, 
 
1074
            self._raw_conflicts.append(('name conflict', trans_id,
1075
1075
                                        this_name, other_name))
1076
1076
        if parent_id_winner == "conflict":
1077
1077
            trans_id = self.tt.trans_id_file_id(file_id)
1078
 
            self._raw_conflicts.append(('parent conflict', trans_id, 
 
1078
            self._raw_conflicts.append(('parent conflict', trans_id,
1079
1079
                                        this_parent, other_parent))
1080
1080
        if other_name is None:
1081
 
            # it doesn't matter whether the result was 'other' or 
 
1081
            # it doesn't matter whether the result was 'other' or
1082
1082
            # 'conflict'-- if there's no 'other', we leave it alone.
1083
1083
            return
1084
1084
        # if we get here, name_winner and parent_winner are set to safe values.
1111
1111
                self.tt.unversion_file(trans_id)
1112
1112
                if file_id in self.this_tree:
1113
1113
                    self.tt.delete_contents(trans_id)
1114
 
            file_group = self._dump_conflicts(name, parent_id, file_id, 
 
1114
            file_group = self._dump_conflicts(name, parent_id, file_id,
1115
1115
                                              set_version=True)
1116
1116
            self._raw_conflicts.append(('contents conflict', file_group))
1117
1117
 
1120
1120
        # file kind...
1121
1121
        base_pair = contents_pair(self.base_tree)
1122
1122
        other_pair = contents_pair(self.other_tree)
1123
 
        if base_pair == other_pair:
1124
 
            # OTHER introduced no changes
1125
 
            return "unmodified"
1126
 
        this_pair = contents_pair(self.this_tree)
1127
 
        if this_pair == other_pair:
1128
 
            # THIS and OTHER introduced the same changes
1129
 
            return "unmodified"
1130
 
        else:
1131
 
            trans_id = self.tt.trans_id_file_id(file_id)
1132
 
            if this_pair == base_pair:
1133
 
                # only OTHER introduced changes
1134
 
                if file_id in self.this_tree:
1135
 
                    # Remove any existing contents
1136
 
                    self.tt.delete_contents(trans_id)
1137
 
                if file_id in self.other_tree:
1138
 
                    # OTHER changed the file
1139
 
                    create_from_tree(self.tt, trans_id,
1140
 
                                     self.other_tree, file_id)
1141
 
                    if file_id not in self.this_tree:
1142
 
                        self.tt.version_file(file_id, trans_id)
1143
 
                    return "modified"
1144
 
                elif file_id in self.this_tree.inventory:
1145
 
                    # OTHER deleted the file
1146
 
                    self.tt.unversion_file(trans_id)
1147
 
                    return "deleted"
1148
 
            #BOTH THIS and OTHER introduced changes; scalar conflict
1149
 
            elif this_pair[0] == "file" and other_pair[0] == "file":
 
1123
        if self._lca_trees:
 
1124
            this_pair = contents_pair(self.this_tree)
 
1125
            lca_pairs = [contents_pair(tree) for tree in self._lca_trees]
 
1126
            winner = self._lca_multi_way((base_pair, lca_pairs), other_pair,
 
1127
                                         this_pair, allow_overriding_lca=False)
 
1128
        else:
 
1129
            if base_pair == other_pair:
 
1130
                winner = 'this'
 
1131
            else:
 
1132
                # We delayed evaluating this_pair as long as we can to avoid
 
1133
                # unnecessary sha1 calculation
 
1134
                this_pair = contents_pair(self.this_tree)
 
1135
                winner = self._three_way(base_pair, other_pair, this_pair)
 
1136
        if winner == 'this':
 
1137
            # No interesting changes introduced by OTHER
 
1138
            return "unmodified"
 
1139
        trans_id = self.tt.trans_id_file_id(file_id)
 
1140
        if winner == 'other':
 
1141
            # OTHER is a straight winner, so replace this contents with other
 
1142
            file_in_this = file_id in self.this_tree
 
1143
            if file_in_this:
 
1144
                # Remove any existing contents
 
1145
                self.tt.delete_contents(trans_id)
 
1146
            if file_id in self.other_tree:
 
1147
                # OTHER changed the file
 
1148
                create_from_tree(self.tt, trans_id,
 
1149
                                 self.other_tree, file_id)
 
1150
                if not file_in_this:
 
1151
                    self.tt.version_file(file_id, trans_id)
 
1152
                return "modified"
 
1153
            elif file_in_this:
 
1154
                # OTHER deleted the file
 
1155
                self.tt.unversion_file(trans_id)
 
1156
                return "deleted"
 
1157
        else:
 
1158
            # We have a hypothetical conflict, but if we have files, then we
 
1159
            # can try to merge the content
 
1160
            if this_pair[0] == 'file' and other_pair[0] == 'file':
1150
1161
                # THIS and OTHER are both files, so text merge.  Either
1151
1162
                # BASE is a file, or both converted to files, so at least we
1152
1163
                # have agreement that output should be a file.
1163
1174
                    pass
1164
1175
                return "modified"
1165
1176
            else:
1166
 
                # Scalar conflict, can't text merge.  Dump conflicts
1167
1177
                return contents_conflict()
1168
1178
 
1169
1179
    def get_lines(self, tree, file_id):
1194
1204
 
1195
1205
        def iter_merge3(retval):
1196
1206
            retval["text_conflicts"] = False
1197
 
            for line in m3.merge_lines(name_a = "TREE", 
1198
 
                                       name_b = "MERGE-SOURCE", 
 
1207
            for line in m3.merge_lines(name_a = "TREE",
 
1208
                                       name_b = "MERGE-SOURCE",
1199
1209
                                       name_base = "BASE-REVISION",
1200
 
                                       start_marker=start_marker, 
 
1210
                                       start_marker=start_marker,
1201
1211
                                       base_marker=base_marker,
1202
1212
                                       reprocess=self.reprocess):
1203
1213
                if line.startswith(start_marker):
1212
1222
            self._raw_conflicts.append(('text conflict', trans_id))
1213
1223
            name = self.tt.final_name(trans_id)
1214
1224
            parent_id = self.tt.final_parent(trans_id)
1215
 
            file_group = self._dump_conflicts(name, parent_id, file_id, 
 
1225
            file_group = self._dump_conflicts(name, parent_id, file_id,
1216
1226
                                              this_lines, base_lines,
1217
1227
                                              other_lines)
1218
1228
            file_group.append(trans_id)
1219
1229
 
1220
 
    def _dump_conflicts(self, name, parent_id, file_id, this_lines=None, 
 
1230
    def _dump_conflicts(self, name, parent_id, file_id, this_lines=None,
1221
1231
                        base_lines=None, other_lines=None, set_version=False,
1222
1232
                        no_base=False):
1223
1233
        """Emit conflict files.
1225
1235
        determined automatically.  If set_version is true, the .OTHER, .THIS
1226
1236
        or .BASE (in that order) will be created as versioned files.
1227
1237
        """
1228
 
        data = [('OTHER', self.other_tree, other_lines), 
 
1238
        data = [('OTHER', self.other_tree, other_lines),
1229
1239
                ('THIS', self.this_tree, this_lines)]
1230
1240
        if not no_base:
1231
1241
            data.append(('BASE', self.base_tree, base_lines))
1240
1250
                    self.tt.version_file(file_id, trans_id)
1241
1251
                    versioned = True
1242
1252
        return file_group
1243
 
           
 
1253
 
1244
1254
    def _conflict_file(self, name, parent_id, tree, file_id, suffix,
1245
1255
                       lines=None):
1246
1256
        """Emit a single conflict file."""
1304
1314
                conflict_args = conflict[2:]
1305
1315
                if trans_id not in name_conflicts:
1306
1316
                    name_conflicts[trans_id] = {}
1307
 
                unique_add(name_conflicts[trans_id], conflict_type, 
 
1317
                unique_add(name_conflicts[trans_id], conflict_type,
1308
1318
                           conflict_args)
1309
1319
            if conflict_type == 'contents conflict':
1310
1320
                for trans_id in conflict[1]:
1388
1398
        """
1389
1399
        lines, conflicts = self._merged_lines(file_id)
1390
1400
        lines = list(lines)
1391
 
        # Note we're checking whether the OUTPUT is binary in this case, 
 
1401
        # Note we're checking whether the OUTPUT is binary in this case,
1392
1402
        # because we don't want to get into weave merge guts.
1393
1403
        check_text_lines(lines)
1394
1404
        self.tt.create_file(lines, trans_id)
1396
1406
            self._raw_conflicts.append(('text conflict', trans_id))
1397
1407
            name = self.tt.final_name(trans_id)
1398
1408
            parent_id = self.tt.final_parent(trans_id)
1399
 
            file_group = self._dump_conflicts(name, parent_id, file_id, 
 
1409
            file_group = self._dump_conflicts(name, parent_id, file_id,
1400
1410
                                              no_base=True)
1401
1411
            file_group.append(trans_id)
1402
1412
 
1479
1489
                this_tree=None,
1480
1490
                pb=DummyProgress(),
1481
1491
                change_reporter=None):
1482
 
    """Primary interface for merging. 
 
1492
    """Primary interface for merging.
1483
1493
 
1484
 
        typical use is probably 
 
1494
        typical use is probably
1485
1495
        'merge_inner(branch, branch.get_revision_tree(other_revision),
1486
1496
                     branch.get_revision_tree(base_revision))'
1487
1497
        """
1784
1794
 
1785
1795
    def _find_unique_parents(self, tip_keys, base_key):
1786
1796
        """Find ancestors of tip that aren't ancestors of base.
1787
 
        
 
1797
 
1788
1798
        :param tip_keys: Nodes that are interesting
1789
1799
        :param base_key: Cull all ancestors of this node
1790
1800
        :return: The parent map for all revisions between tip_keys and
1850
1860
    @staticmethod
1851
1861
    def _prune_tails(parent_map, child_map, tails_to_remove):
1852
1862
        """Remove tails from the parent map.
1853
 
        
 
1863
 
1854
1864
        This will remove the supplied revisions until no more children have 0
1855
1865
        parents.
1856
1866