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
532
536
winner_idx = {"this": 2, "other": 1, "conflict": 1}
533
537
supports_lca_trees = True
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?
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
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':
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.
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))
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
1126
this_pair = contents_pair(self.this_tree)
1127
if this_pair == other_pair:
1128
# THIS and OTHER introduced the same changes
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)
1144
elif file_id in self.this_tree.inventory:
1145
# OTHER deleted the file
1146
self.tt.unversion_file(trans_id)
1148
#BOTH THIS and OTHER introduced changes; scalar conflict
1149
elif this_pair[0] == "file" and other_pair[0] == "file":
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)
1129
if base_pair == other_pair:
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
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
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)
1154
# OTHER deleted the file
1155
self.tt.unversion_file(trans_id)
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.
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,
1218
1228
file_group.append(trans_id)
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.
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))
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,
1309
1319
if conflict_type == 'contents conflict':
1310
1320
for trans_id in conflict[1]:
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,
1401
1411
file_group.append(trans_id)