353
364
ensure_null(self.other_basis)]
354
365
if NULL_REVISION in revisions:
355
366
self.base_rev_id = NULL_REVISION
367
self.base_tree = self.revision_tree(self.base_rev_id)
368
self._is_criss_cross = False
357
self.base_rev_id, steps = self.revision_graph.find_unique_lca(
358
revisions[0], revisions[1], count_steps=True)
370
lcas = self.revision_graph.find_lca(revisions[0], revisions[1])
371
self._is_criss_cross = False
373
self.base_rev_id = NULL_REVISION
375
self.base_rev_id = list(lcas)[0]
376
else: # len(lcas) > 1
378
# find_unique_lca can only handle 2 nodes, so we have to
379
# start back at the beginning. It is a shame to traverse
380
# the graph again, but better than re-implementing
382
self.base_rev_id = self.revision_graph.find_unique_lca(
383
revisions[0], revisions[1])
385
self.base_rev_id = self.revision_graph.find_unique_lca(
387
self._is_criss_cross = True
359
388
if self.base_rev_id == NULL_REVISION:
360
389
raise UnrelatedBranches()
390
if self._is_criss_cross:
362
391
warning('Warning: criss-cross merge encountered. See bzr'
363
392
' help criss-cross.')
364
self.base_tree = self.revision_tree(self.base_rev_id)
393
interesting_revision_ids = [self.base_rev_id]
394
interesting_revision_ids.extend(lcas)
395
interesting_trees = dict((t.get_revision_id(), t)
396
for t in self.this_branch.repository.revision_trees(
397
interesting_revision_ids))
398
self._cached_trees.update(interesting_trees)
399
self.base_tree = interesting_trees.pop(self.base_rev_id)
400
sorted_lca_keys = self.revision_graph.find_merge_order(
402
self._lca_trees = [interesting_trees[key]
403
for key in sorted_lca_keys]
405
self.base_tree = self.revision_tree(self.base_rev_id)
365
406
self.base_is_ancestor = True
366
407
self.base_is_other_ancestor = True
620
699
result.append((file_id, changed, parents3, names3, executable3))
702
def _entries_lca(self):
703
"""Gather data about files modified between multiple trees.
705
This compares OTHER versus all LCA trees, and for interesting entries,
706
it then compares with THIS and BASE.
708
For the multi-valued entries, the format will be (BASE, [lca1, lca2])
709
:return: [(file_id, changed, parents, names, executable)]
710
file_id Simple file_id of the entry
711
changed Boolean, True if the kind or contents changed
713
parents ((base, [parent_id, in, lcas]), parent_id_other,
715
names ((base, [name, in, lcas]), name_in_other, name_in_this)
716
executable ((base, [exec, in, lcas]), exec_in_other, exec_in_this)
718
if self.interesting_files is not None:
719
lookup_trees = [self.this_tree, self.base_tree]
720
lookup_trees.extend(self._lca_trees)
721
# I think we should include the lca trees as well
722
interesting_ids = self.other_tree.paths2ids(self.interesting_files,
725
interesting_ids = self.interesting_ids
727
walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees)
729
base_inventory = self.base_tree.inventory
730
this_inventory = self.this_tree.inventory
731
for path, file_id, other_ie, lca_values in walker.iter_all():
732
# Is this modified at all from any of the other trees?
734
other_ie = _none_entry
735
if interesting_ids is not None and file_id not in interesting_ids:
738
# If other_revision is found in any of the lcas, that means this
739
# node is uninteresting. This is because when merging, if there are
740
# multiple heads(), we have to create a new node. So if we didn't,
741
# we know that the ancestry is linear, and that OTHER did not
743
# See doc/developers/lca_merge_resolution.txt for details
744
other_revision = other_ie.revision
745
if other_revision is not None:
746
# We can't use this shortcut when other_revision is None,
747
# because it may be None because things are WorkingTrees, and
748
# not because it is *actually* None.
749
is_unmodified = False
750
for lca_path, ie in lca_values:
751
if ie is not None and ie.revision == other_revision:
758
for lca_path, lca_ie in lca_values:
760
lca_entries.append(_none_entry)
762
lca_entries.append(lca_ie)
764
if file_id in base_inventory:
765
base_ie = base_inventory[file_id]
767
base_ie = _none_entry
769
if file_id in this_inventory:
770
this_ie = this_inventory[file_id]
772
this_ie = _none_entry
778
for lca_ie in lca_entries:
779
lca_kinds.append(lca_ie.kind)
780
lca_parent_ids.append(lca_ie.parent_id)
781
lca_names.append(lca_ie.name)
782
lca_executable.append(lca_ie.executable)
784
kind_winner = self._lca_multi_way(
785
(base_ie.kind, lca_kinds),
786
other_ie.kind, this_ie.kind)
787
parent_id_winner = self._lca_multi_way(
788
(base_ie.parent_id, lca_parent_ids),
789
other_ie.parent_id, this_ie.parent_id)
790
name_winner = self._lca_multi_way(
791
(base_ie.name, lca_names),
792
other_ie.name, this_ie.name)
794
content_changed = True
795
if kind_winner == 'this':
796
# 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':
802
if parent_id_winner == 'this' and name_winner == 'this':
803
# No change for this directory in OTHER, skip
805
content_changed = False
806
elif other_ie.kind == 'file':
807
def get_sha1(ie, tree):
808
if ie.kind != 'file':
810
return tree.get_file_sha1(file_id)
811
base_sha1 = get_sha1(base_ie, self.base_tree)
812
lca_sha1s = [get_sha1(ie, tree) for ie, tree
813
in zip(lca_entries, self._lca_trees)]
814
this_sha1 = get_sha1(this_ie, self.this_tree)
815
other_sha1 = get_sha1(other_ie, self.other_tree)
816
sha1_winner = self._lca_multi_way(
817
(base_sha1, lca_sha1s), other_sha1, this_sha1,
818
allow_overriding_lca=False)
819
exec_winner = self._lca_multi_way(
820
(base_ie.executable, lca_executable),
821
other_ie.executable, this_ie.executable)
822
if (parent_id_winner == 'this' and name_winner == 'this'
823
and sha1_winner == 'this' and exec_winner == 'this'):
824
# No kind, parent, name, exec, or content change for
825
# OTHER, so this node is not considered interesting
827
if sha1_winner == 'this':
828
content_changed = False
829
elif other_ie.kind == 'symlink':
830
def get_target(ie, tree):
831
if ie.kind != 'symlink':
833
return tree.get_symlink_target(file_id)
834
base_target = get_target(base_ie, self.base_tree)
835
lca_targets = [get_target(ie, tree) for ie, tree
836
in zip(lca_entries, self._lca_trees)]
837
this_target = get_target(this_ie, self.this_tree)
838
other_target = get_target(other_ie, self.other_tree)
839
target_winner = self._lca_multi_way(
840
(base_target, lca_targets),
841
other_target, this_target)
842
if (parent_id_winner == 'this' and name_winner == 'this'
843
and target_winner == 'this'):
844
# No kind, parent, name, or symlink target change
847
if target_winner == 'this':
848
content_changed = False
849
elif other_ie.kind == 'tree-reference':
850
# The 'changed' information seems to be handled at a higher
851
# level. At least, _entries3 returns False for content
852
# changed, even when at a new revision_id.
853
content_changed = False
854
if (parent_id_winner == 'this' and name_winner == 'this'):
855
# Nothing interesting
858
raise AssertionError('unhandled kind: %s' % other_ie.kind)
859
# XXX: We need to handle kind == 'symlink'
861
# If we have gotten this far, that means something has changed
862
result.append((file_id, content_changed,
863
((base_ie.parent_id, lca_parent_ids),
864
other_ie.parent_id, this_ie.parent_id),
865
((base_ie.name, lca_names),
866
other_ie.name, this_ie.name),
867
((base_ie.executable, lca_executable),
868
other_ie.executable, this_ie.executable)
623
873
def fix_root(self):
625
875
self.tt.final_kind(self.tt.root)
967
def _lca_multi_way(bases, other, this, allow_overriding_lca=True):
968
"""Consider LCAs when determining whether a change has occurred.
970
If LCAS are all identical, this is the same as a _three_way comparison.
972
:param bases: value in (BASE, [LCAS])
973
:param other: value in OTHER
974
:param this: value in THIS
975
:param allow_overriding_lca: If there is more than one unique lca
976
value, allow OTHER to override THIS if it has a new value, and
977
THIS only has an lca value, or vice versa. This is appropriate for
978
truly scalar values, not as much for non-scalars.
979
:return: 'this', 'other', or 'conflict' depending on whether an entry
982
# See doc/developers/lca_merge_resolution.txt for details about this
985
# Either Ambiguously clean, or nothing was actually changed. We
988
base_val, lca_vals = bases
989
# Remove 'base_val' from the lca_vals, because it is not interesting
990
filtered_lca_vals = [lca_val for lca_val in lca_vals
991
if lca_val != base_val]
992
if len(filtered_lca_vals) == 0:
993
return Merge3Merger._three_way(base_val, other, this)
995
unique_lca_vals = set(filtered_lca_vals)
996
if len(unique_lca_vals) == 1:
997
return Merge3Merger._three_way(unique_lca_vals.pop(), other, this)
999
if allow_overriding_lca:
1000
if other in unique_lca_vals:
1001
if this in unique_lca_vals:
1002
# Each side picked a different lca, conflict
1005
# This has a value which supersedes both lca values, and
1006
# other only has an lca value
1008
elif this in unique_lca_vals:
1009
# OTHER has a value which supersedes both lca values, and this
1010
# only has an lca value
1013
# At this point, the lcas disagree, and the tips disagree
717
1017
def scalar_three_way(this_tree, base_tree, other_tree, file_id, key):
718
1018
"""Do a three-way test on a scalar.
719
1019
Return "this", "other" or "conflict", depending whether a value wins.
941
1241
versioned = True
942
1242
return file_group
944
def _conflict_file(self, name, parent_id, tree, file_id, suffix,
1244
def _conflict_file(self, name, parent_id, tree, file_id, suffix,
946
1246
"""Emit a single conflict file."""
947
1247
name = name + '.' + suffix
948
1248
trans_id = self.tt.create_path(name, parent_id)
949
entry = tree.inventory[file_id]
950
create_by_entry(self.tt, entry, tree, trans_id, lines)
1249
create_from_tree(self.tt, trans_id, tree, file_id, lines)
953
1252
def merge_executable(self, file_id, file_status):
954
1253
"""Perform a merge on the execute bit."""
955
1254
executable = [self.executable(t, file_id) for t in (self.base_tree,
956
1255
self.other_tree, self.this_tree)]
957
self._merge_executable(file_id, executable, file_status)
1256
self._merge_executable(file_id, executable, file_status,
1257
resolver=self._three_way)
959
def _merge_executable(self, file_id, executable, file_status):
1259
def _merge_executable(self, file_id, executable, file_status,
960
1261
"""Perform a merge on the execute bit."""
961
1262
base_executable, other_executable, this_executable = executable
962
1263
if file_status == "deleted":
964
winner = self._three_way(*executable)
1265
winner = resolver(*executable)
965
1266
if winner == "conflict":
966
1267
# There must be a None in here, if we have a conflict, but we
967
1268
# need executability since file status was not deleted.