379
353
ensure_null(self.other_basis)]
380
354
if NULL_REVISION in revisions:
381
355
self.base_rev_id = NULL_REVISION
382
self.base_tree = self.revision_tree(self.base_rev_id)
383
self._is_criss_cross = False
385
lcas = self.revision_graph.find_lca(revisions[0], revisions[1])
386
self._is_criss_cross = False
388
self.base_rev_id = NULL_REVISION
390
self.base_rev_id = list(lcas)[0]
391
else: # len(lcas) > 1
393
# find_unique_lca can only handle 2 nodes, so we have to
394
# start back at the beginning. It is a shame to traverse
395
# the graph again, but better than re-implementing
397
self.base_rev_id = self.revision_graph.find_unique_lca(
398
revisions[0], revisions[1])
400
self.base_rev_id = self.revision_graph.find_unique_lca(
402
self._is_criss_cross = True
357
self.base_rev_id, steps = self.revision_graph.find_unique_lca(
358
revisions[0], revisions[1], count_steps=True)
403
359
if self.base_rev_id == NULL_REVISION:
404
360
raise UnrelatedBranches()
405
if self._is_criss_cross:
406
362
warning('Warning: criss-cross merge encountered. See bzr'
407
363
' help criss-cross.')
408
mutter('Criss-cross lcas: %r' % lcas)
409
interesting_revision_ids = [self.base_rev_id]
410
interesting_revision_ids.extend(lcas)
411
interesting_trees = dict((t.get_revision_id(), t)
412
for t in self.this_branch.repository.revision_trees(
413
interesting_revision_ids))
414
self._cached_trees.update(interesting_trees)
415
self.base_tree = interesting_trees.pop(self.base_rev_id)
416
sorted_lca_keys = self.revision_graph.find_merge_order(
418
self._lca_trees = [interesting_trees[key]
419
for key in sorted_lca_keys]
421
self.base_tree = self.revision_tree(self.base_rev_id)
364
self.base_tree = self.revision_tree(self.base_rev_id)
422
365
self.base_is_ancestor = True
423
366
self.base_is_other_ancestor = True
424
mutter('Base revid: %r' % self.base_rev_id)
426
368
def set_base(self, base_revision):
427
369
"""Set the base revision to use for the merge.
718
620
result.append((file_id, changed, parents3, names3, executable3))
721
def _entries_lca(self):
722
"""Gather data about files modified between multiple trees.
724
This compares OTHER versus all LCA trees, and for interesting entries,
725
it then compares with THIS and BASE.
727
For the multi-valued entries, the format will be (BASE, [lca1, lca2])
728
:return: [(file_id, changed, parents, names, executable)]
729
file_id Simple file_id of the entry
730
changed Boolean, True if the kind or contents changed
732
parents ((base, [parent_id, in, lcas]), parent_id_other,
734
names ((base, [name, in, lcas]), name_in_other, name_in_this)
735
executable ((base, [exec, in, lcas]), exec_in_other, exec_in_this)
737
if self.interesting_files is not None:
738
lookup_trees = [self.this_tree, self.base_tree]
739
lookup_trees.extend(self._lca_trees)
740
# I think we should include the lca trees as well
741
interesting_ids = self.other_tree.paths2ids(self.interesting_files,
744
interesting_ids = self.interesting_ids
746
walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees)
748
base_inventory = self.base_tree.inventory
749
this_inventory = self.this_tree.inventory
750
for path, file_id, other_ie, lca_values in walker.iter_all():
751
# Is this modified at all from any of the other trees?
753
other_ie = _none_entry
754
if interesting_ids is not None and file_id not in interesting_ids:
757
# If other_revision is found in any of the lcas, that means this
758
# node is uninteresting. This is because when merging, if there are
759
# multiple heads(), we have to create a new node. So if we didn't,
760
# we know that the ancestry is linear, and that OTHER did not
762
# See doc/developers/lca_merge_resolution.txt for details
763
other_revision = other_ie.revision
764
if other_revision is not None:
765
# We can't use this shortcut when other_revision is None,
766
# because it may be None because things are WorkingTrees, and
767
# not because it is *actually* None.
768
is_unmodified = False
769
for lca_path, ie in lca_values:
770
if ie is not None and ie.revision == other_revision:
777
for lca_path, lca_ie in lca_values:
779
lca_entries.append(_none_entry)
781
lca_entries.append(lca_ie)
783
if file_id in base_inventory:
784
base_ie = base_inventory[file_id]
786
base_ie = _none_entry
788
if file_id in this_inventory:
789
this_ie = this_inventory[file_id]
791
this_ie = _none_entry
797
for lca_ie in lca_entries:
798
lca_kinds.append(lca_ie.kind)
799
lca_parent_ids.append(lca_ie.parent_id)
800
lca_names.append(lca_ie.name)
801
lca_executable.append(lca_ie.executable)
803
kind_winner = self._lca_multi_way(
804
(base_ie.kind, lca_kinds),
805
other_ie.kind, this_ie.kind)
806
parent_id_winner = self._lca_multi_way(
807
(base_ie.parent_id, lca_parent_ids),
808
other_ie.parent_id, this_ie.parent_id)
809
name_winner = self._lca_multi_way(
810
(base_ie.name, lca_names),
811
other_ie.name, this_ie.name)
813
content_changed = True
814
if kind_winner == 'this':
815
# No kind change in OTHER, see if there are *any* changes
816
if other_ie.kind == 'directory':
817
if parent_id_winner == 'this' and name_winner == 'this':
818
# No change for this directory in OTHER, skip
820
content_changed = False
821
elif other_ie.kind is None or other_ie.kind == 'file':
822
def get_sha1(ie, tree):
823
if ie.kind != 'file':
825
return tree.get_file_sha1(file_id)
826
base_sha1 = get_sha1(base_ie, self.base_tree)
827
lca_sha1s = [get_sha1(ie, tree) for ie, tree
828
in zip(lca_entries, self._lca_trees)]
829
this_sha1 = get_sha1(this_ie, self.this_tree)
830
other_sha1 = get_sha1(other_ie, self.other_tree)
831
sha1_winner = self._lca_multi_way(
832
(base_sha1, lca_sha1s), other_sha1, this_sha1,
833
allow_overriding_lca=False)
834
exec_winner = self._lca_multi_way(
835
(base_ie.executable, lca_executable),
836
other_ie.executable, this_ie.executable)
837
if (parent_id_winner == 'this' and name_winner == 'this'
838
and sha1_winner == 'this' and exec_winner == 'this'):
839
# No kind, parent, name, exec, or content change for
840
# OTHER, so this node is not considered interesting
842
if sha1_winner == 'this':
843
content_changed = False
844
elif other_ie.kind == 'symlink':
845
def get_target(ie, tree):
846
if ie.kind != 'symlink':
848
return tree.get_symlink_target(file_id)
849
base_target = get_target(base_ie, self.base_tree)
850
lca_targets = [get_target(ie, tree) for ie, tree
851
in zip(lca_entries, self._lca_trees)]
852
this_target = get_target(this_ie, self.this_tree)
853
other_target = get_target(other_ie, self.other_tree)
854
target_winner = self._lca_multi_way(
855
(base_target, lca_targets),
856
other_target, this_target)
857
if (parent_id_winner == 'this' and name_winner == 'this'
858
and target_winner == 'this'):
859
# No kind, parent, name, or symlink target change
862
if target_winner == 'this':
863
content_changed = False
864
elif other_ie.kind == 'tree-reference':
865
# The 'changed' information seems to be handled at a higher
866
# level. At least, _entries3 returns False for content
867
# changed, even when at a new revision_id.
868
content_changed = False
869
if (parent_id_winner == 'this' and name_winner == 'this'):
870
# Nothing interesting
873
raise AssertionError('unhandled kind: %s' % other_ie.kind)
874
# XXX: We need to handle kind == 'symlink'
876
# If we have gotten this far, that means something has changed
877
result.append((file_id, content_changed,
878
((base_ie.parent_id, lca_parent_ids),
879
other_ie.parent_id, this_ie.parent_id),
880
((base_ie.name, lca_names),
881
other_ie.name, this_ie.name),
882
((base_ie.executable, lca_executable),
883
other_ie.executable, this_ie.executable)
888
623
def fix_root(self):
890
625
self.tt.final_kind(self.tt.root)
891
626
except NoSuchFile:
892
627
self.tt.cancel_deletion(self.tt.root)
893
628
if self.tt.final_file_id(self.tt.root) is None:
894
self.tt.version_file(self.tt.tree_file_id(self.tt.root),
629
self.tt.version_file(self.tt.tree_file_id(self.tt.root),
631
if self.other_tree.inventory.root is None:
896
633
other_root_file_id = self.other_tree.get_root_id()
897
if other_root_file_id is None:
899
634
other_root = self.tt.trans_id_file_id(other_root_file_id)
900
635
if other_root == self.tt.root:
982
def _lca_multi_way(bases, other, this, allow_overriding_lca=True):
983
"""Consider LCAs when determining whether a change has occurred.
985
If LCAS are all identical, this is the same as a _three_way comparison.
987
:param bases: value in (BASE, [LCAS])
988
:param other: value in OTHER
989
:param this: value in THIS
990
:param allow_overriding_lca: If there is more than one unique lca
991
value, allow OTHER to override THIS if it has a new value, and
992
THIS only has an lca value, or vice versa. This is appropriate for
993
truly scalar values, not as much for non-scalars.
994
:return: 'this', 'other', or 'conflict' depending on whether an entry
997
# See doc/developers/lca_tree_merging.txt for details about this
1000
# Either Ambiguously clean, or nothing was actually changed. We
1003
base_val, lca_vals = bases
1004
# Remove 'base_val' from the lca_vals, because it is not interesting
1005
filtered_lca_vals = [lca_val for lca_val in lca_vals
1006
if lca_val != base_val]
1007
if len(filtered_lca_vals) == 0:
1008
return Merge3Merger._three_way(base_val, other, this)
1010
unique_lca_vals = set(filtered_lca_vals)
1011
if len(unique_lca_vals) == 1:
1012
return Merge3Merger._three_way(unique_lca_vals.pop(), other, this)
1014
if allow_overriding_lca:
1015
if other in unique_lca_vals:
1016
if this in unique_lca_vals:
1017
# Each side picked a different lca, conflict
1020
# This has a value which supersedes both lca values, and
1021
# other only has an lca value
1023
elif this in unique_lca_vals:
1024
# OTHER has a value which supersedes both lca values, and this
1025
# only has an lca value
1028
# At this point, the lcas disagree, and the tips disagree
1032
717
def scalar_three_way(this_tree, base_tree, other_tree, file_id, key):
1033
718
"""Do a three-way test on a scalar.
1034
719
Return "this", "other" or "conflict", depending whether a value wins.
1136
820
base_pair = contents_pair(self.base_tree)
1137
821
other_pair = contents_pair(self.other_tree)
1139
this_pair = contents_pair(self.this_tree)
1140
lca_pairs = [contents_pair(tree) for tree in self._lca_trees]
1141
winner = self._lca_multi_way((base_pair, lca_pairs), other_pair,
1142
this_pair, allow_overriding_lca=False)
1144
if base_pair == other_pair:
1147
# We delayed evaluating this_pair as long as we can to avoid
1148
# unnecessary sha1 calculation
1149
this_pair = contents_pair(self.this_tree)
1150
winner = self._three_way(base_pair, other_pair, this_pair)
1151
if winner == 'this':
1152
# No interesting changes introduced by OTHER
1154
trans_id = self.tt.trans_id_file_id(file_id)
1155
if winner == 'other':
1156
# OTHER is a straight winner, so replace this contents with other
1157
file_in_this = file_id in self.this_tree
1159
# Remove any existing contents
1160
self.tt.delete_contents(trans_id)
1161
if file_id in self.other_tree:
1162
# OTHER changed the file
1163
create_from_tree(self.tt, trans_id,
1164
self.other_tree, file_id)
1165
if not file_in_this:
1166
self.tt.version_file(file_id, trans_id)
1169
# OTHER deleted the file
1170
self.tt.unversion_file(trans_id)
1173
# We have a hypothetical conflict, but if we have files, then we
1174
# can try to merge the content
1175
if this_pair[0] == 'file' and other_pair[0] == 'file':
822
if base_pair == other_pair:
823
# OTHER introduced no changes
825
this_pair = contents_pair(self.this_tree)
826
if this_pair == other_pair:
827
# THIS and OTHER introduced the same changes
830
trans_id = self.tt.trans_id_file_id(file_id)
831
if this_pair == base_pair:
832
# only OTHER introduced changes
833
if file_id in self.this_tree:
834
# Remove any existing contents
835
self.tt.delete_contents(trans_id)
836
if file_id in self.other_tree:
837
# OTHER changed the file
838
create_by_entry(self.tt,
839
self.other_tree.inventory[file_id],
840
self.other_tree, trans_id)
841
if file_id not in self.this_tree.inventory:
842
self.tt.version_file(file_id, trans_id)
844
elif file_id in self.this_tree.inventory:
845
# OTHER deleted the file
846
self.tt.unversion_file(trans_id)
848
#BOTH THIS and OTHER introduced changes; scalar conflict
849
elif this_pair[0] == "file" and other_pair[0] == "file":
1176
850
# THIS and OTHER are both files, so text merge. Either
1177
851
# BASE is a file, or both converted to files, so at least we
1178
852
# have agreement that output should be a file.
1265
940
self.tt.version_file(file_id, trans_id)
1266
941
versioned = True
1267
942
return file_group
1269
def _conflict_file(self, name, parent_id, tree, file_id, suffix,
944
def _conflict_file(self, name, parent_id, tree, file_id, suffix,
1271
946
"""Emit a single conflict file."""
1272
947
name = name + '.' + suffix
1273
948
trans_id = self.tt.create_path(name, parent_id)
1274
create_from_tree(self.tt, trans_id, tree, file_id, lines)
949
entry = tree.inventory[file_id]
950
create_by_entry(self.tt, entry, tree, trans_id, lines)
1277
953
def merge_executable(self, file_id, file_status):
1278
954
"""Perform a merge on the execute bit."""
1279
955
executable = [self.executable(t, file_id) for t in (self.base_tree,
1280
956
self.other_tree, self.this_tree)]
1281
self._merge_executable(file_id, executable, file_status,
1282
resolver=self._three_way)
957
self._merge_executable(file_id, executable, file_status)
1284
def _merge_executable(self, file_id, executable, file_status,
959
def _merge_executable(self, file_id, executable, file_status):
1286
960
"""Perform a merge on the execute bit."""
1287
961
base_executable, other_executable, this_executable = executable
1288
962
if file_status == "deleted":
1290
winner = resolver(*executable)
964
winner = self._three_way(*executable)
1291
965
if winner == "conflict":
1292
966
# There must be a None in here, if we have a conflict, but we
1293
967
# need executability since file status was not deleted.