1149
1150
self.tt.delete_contents(trans_id)
1150
1151
if file_id in self.other_tree:
1151
1152
# OTHER changed the file
1153
if wt.supports_content_filtering():
1154
# We get the path from the working tree if it exists.
1155
# That fails though when OTHER is adding a file, so
1156
# we fall back to the other tree to find the path if
1157
# it doesn't exist locally.
1159
filter_tree_path = wt.id2path(file_id)
1160
except errors.NoSuchId:
1161
filter_tree_path = self.other_tree.id2path(file_id)
1163
# Skip the id2path lookup for older formats
1164
filter_tree_path = None
1165
1153
transform.create_from_tree(self.tt, trans_id,
1166
self.other_tree, file_id,
1167
filter_tree_path=filter_tree_path)
1154
self.other_tree, file_id)
1168
1155
if not file_in_this:
1169
1156
self.tt.version_file(file_id, trans_id)
1170
1157
return "modified"
1257
1244
('THIS', self.this_tree, this_lines)]
1258
1245
if not no_base:
1259
1246
data.append(('BASE', self.base_tree, base_lines))
1261
# We need to use the actual path in the working tree of the file here,
1262
# ignoring the conflict suffixes
1264
if wt.supports_content_filtering():
1266
filter_tree_path = wt.id2path(file_id)
1267
except errors.NoSuchId:
1268
# file has been deleted
1269
filter_tree_path = None
1271
# Skip the id2path lookup for older formats
1272
filter_tree_path = None
1274
1247
versioned = False
1275
1248
file_group = []
1276
1249
for suffix, tree, lines in data:
1277
1250
if file_id in tree:
1278
1251
trans_id = self._conflict_file(name, parent_id, tree, file_id,
1279
suffix, lines, filter_tree_path)
1280
1253
file_group.append(trans_id)
1281
1254
if set_version and not versioned:
1282
1255
self.tt.version_file(file_id, trans_id)
1284
1257
return file_group
1286
1259
def _conflict_file(self, name, parent_id, tree, file_id, suffix,
1287
lines=None, filter_tree_path=None):
1288
1261
"""Emit a single conflict file."""
1289
1262
name = name + '.' + suffix
1290
1263
trans_id = self.tt.create_path(name, parent_id)
1291
transform.create_from_tree(self.tt, trans_id, tree, file_id, lines,
1264
transform.create_from_tree(self.tt, trans_id, tree, file_id, lines)
1293
1265
return trans_id
1295
1267
def merge_executable(self, file_id, file_status):
1406
1378
supports_reverse_cherrypick = False
1407
1379
history_based = True
1409
def _generate_merge_plan(self, file_id, base):
1410
return self.this_tree.plan_file_merge(file_id, self.other_tree,
1381
def _merged_lines(self, file_id):
1382
"""Generate the merged lines.
1383
There is no distinction between lines that are meant to contain <<<<<<<
1387
base = self.base_tree
1390
plan = self.this_tree.plan_file_merge(file_id, self.other_tree,
1413
def _merged_lines(self, file_id):
1414
"""Generate the merged lines.
1415
There is no distinction between lines that are meant to contain <<<<<<<
1419
base = self.base_tree
1422
plan = self._generate_merge_plan(file_id, base)
1423
1392
if 'merge' in debug.debug_flags:
1424
1393
plan = list(plan)
1425
1394
trans_id = self.tt.trans_id_file_id(file_id)
1426
1395
name = self.tt.final_name(trans_id) + '.plan'
1427
contents = ('%11s|%s' % l for l in plan)
1396
contents = ('%10s|%s' % l for l in plan)
1428
1397
self.tt.new_file(name, self.tt.final_parent(trans_id), contents)
1429
1398
textmerge = versionedfile.PlanWeaveMerge(plan, '<<<<<<< TREE\n',
1430
1399
'>>>>>>> MERGE-SOURCE\n')
1431
lines, conflicts = textmerge.merge_lines(self.reprocess)
1433
base_lines = textmerge.base_from_plan()
1436
return lines, base_lines
1400
return textmerge.merge_lines(self.reprocess)
1438
1402
def text_merge(self, file_id, trans_id):
1439
1403
"""Perform a (weave) text merge for a given file and file-id.
1440
1404
If conflicts are encountered, .THIS and .OTHER files will be emitted,
1441
1405
and a conflict will be noted.
1443
lines, base_lines = self._merged_lines(file_id)
1407
lines, conflicts = self._merged_lines(file_id)
1444
1408
lines = list(lines)
1445
1409
# Note we're checking whether the OUTPUT is binary in this case,
1446
1410
# because we don't want to get into weave merge guts.
1447
1411
textfile.check_text_lines(lines)
1448
1412
self.tt.create_file(lines, trans_id)
1449
if base_lines is not None:
1451
1414
self._raw_conflicts.append(('text conflict', trans_id))
1452
1415
name = self.tt.final_name(trans_id)
1453
1416
parent_id = self.tt.final_parent(trans_id)
1454
1417
file_group = self._dump_conflicts(name, parent_id, file_id,
1456
base_lines=base_lines)
1457
1419
file_group.append(trans_id)
1460
1422
class LCAMerger(WeaveMerger):
1462
def _generate_merge_plan(self, file_id, base):
1463
return self.this_tree.plan_file_lca_merge(file_id, self.other_tree,
1424
def _merged_lines(self, file_id):
1425
"""Generate the merged lines.
1426
There is no distinction between lines that are meant to contain <<<<<<<
1430
base = self.base_tree
1433
plan = self.this_tree.plan_file_lca_merge(file_id, self.other_tree,
1435
if 'merge' in debug.debug_flags:
1437
trans_id = self.tt.trans_id_file_id(file_id)
1438
name = self.tt.final_name(trans_id) + '.plan'
1439
contents = ('%10s|%s' % l for l in plan)
1440
self.tt.new_file(name, self.tt.final_parent(trans_id), contents)
1441
textmerge = versionedfile.PlanWeaveMerge(plan, '<<<<<<< TREE\n',
1442
'>>>>>>> MERGE-SOURCE\n')
1443
return textmerge.merge_lines(self.reprocess)
1466
1446
class Diff3Merger(Merge3Merger):
1467
1447
"""Three-way merger using external diff3 for text merging"""