353
356
ensure_null(self.other_basis)]
354
357
if NULL_REVISION in revisions:
355
358
self.base_rev_id = NULL_REVISION
359
self.base_tree = self.revision_tree(self.base_rev_id)
360
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)
362
lcas = self.revision_graph.find_lca(revisions[0], revisions[1])
363
self._is_criss_cross = False
365
self.base_rev_id = NULL_REVISION
367
self.base_rev_id = list(lcas)[0]
368
else: # len(lcas) > 1
370
# find_unique_lca can only handle 2 nodes, so we have to
371
# start back at the beginning. It is a shame to traverse
372
# the graph again, but better than re-implementing
374
self.base_rev_id = self.revision_graph.find_unique_lca(
375
revisions[0], revisions[1])
377
self.base_rev_id = self.revision_graph.find_unique_lca(
379
self._is_criss_cross = True
359
380
if self.base_rev_id == NULL_REVISION:
360
381
raise UnrelatedBranches()
382
if self._is_criss_cross:
362
383
warning('Warning: criss-cross merge encountered. See bzr'
363
384
' help criss-cross.')
364
self.base_tree = self.revision_tree(self.base_rev_id)
385
interesting_revision_ids = [self.base_rev_id]
386
interesting_revision_ids.extend(lcas)
387
interesting_trees = dict((t.get_revision_id(), t)
388
for t in self.this_branch.repository.revision_trees(
389
interesting_revision_ids))
390
self._cached_trees.update(interesting_trees)
391
self.base_tree = interesting_trees.pop(self.base_rev_id)
392
sorted_lca_keys = self.revision_graph.find_merge_order(
394
self._lca_trees = [interesting_trees[key]
395
for key in sorted_lca_keys]
397
self.base_tree = self.revision_tree(self.base_rev_id)
365
398
self.base_is_ancestor = True
366
399
self.base_is_other_ancestor = True
620
688
result.append((file_id, changed, parents3, names3, executable3))
691
def _entries_lca(self):
692
"""Gather data about files modified between multiple trees.
694
This compares OTHER versus all LCA trees, and for interesting entries,
695
it then compares with THIS and BASE.
697
For the multi-valued entries, the format will be (BASE, [lca1, lca2])
698
:return: [(file_id, changed, parents, names, executable)]
699
file_id Simple file_id of the entry
700
changed Boolean, True if the kind or contents changed
702
parents ((base, [parent_id, in, lcas]), parent_id_other,
704
names ((base, [name, in, lcas]), name_in_other, name_in_this)
705
executable ((base, [exec, in, lcas]), exec_in_other, exec_in_this)
707
if self.interesting_files is not None:
708
lookup_trees = [self.this_tree, self.base_tree]
709
lookup_trees.extend(self._lca_trees)
710
# I think we should include the lca trees as well
711
interesting_ids = self.other_tree.paths2ids(self.interesting_files,
714
interesting_ids = self.interesting_ids
716
walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees)
718
base_inventory = self.base_tree.inventory
719
this_inventory = self.this_tree.inventory
720
for path, file_id, other_ie, lca_values in walker.iter_all():
721
# Is this modified at all from any of the other trees?
723
other_ie = _none_entry
724
if interesting_ids is not None and file_id not in interesting_ids:
727
# If other_revision is found in any of the lcas, that means this
728
# node is uninteresting. This is because when merging, if there are
729
# multiple heads(), we have to create a new node. So if we didn't,
730
# we know that the ancestry is linear, and that OTHER did not
732
# See doc/developers/lca_merge_resolution.txt for details
733
other_revision = other_ie.revision
734
if other_revision is not None:
735
# We can't use this shortcut when other_revision is None,
736
# because it may be None because things are WorkingTrees, and
737
# not because it is *actually* None.
738
is_unmodified = False
739
for lca_path, ie in lca_values:
740
if ie is not None and ie.revision == other_revision:
747
for lca_path, lca_ie in lca_values:
749
lca_entries.append(_none_entry)
751
lca_entries.append(lca_ie)
753
if file_id in base_inventory:
754
base_ie = base_inventory[file_id]
756
base_ie = _none_entry
758
if file_id in this_inventory:
759
this_ie = this_inventory[file_id]
761
this_ie = _none_entry
767
for lca_ie in lca_entries:
768
lca_kinds.append(lca_ie.kind)
769
lca_parent_ids.append(lca_ie.parent_id)
770
lca_names.append(lca_ie.name)
771
lca_executable.append(lca_ie.executable)
773
kind_winner = self._lca_multi_way(
774
(base_ie.kind, lca_kinds),
775
other_ie.kind, this_ie.kind)
776
parent_id_winner = self._lca_multi_way(
777
(base_ie.parent_id, lca_parent_ids),
778
other_ie.parent_id, this_ie.parent_id)
779
name_winner = self._lca_multi_way(
780
(base_ie.name, lca_names),
781
other_ie.name, this_ie.name)
783
content_changed = True
784
if kind_winner == 'this':
785
# No kind change in OTHER, see if there are *any* changes
786
if other_ie.kind == None:
787
# No content and 'this' wins the kind, so skip this?
790
elif other_ie.kind == 'directory':
791
if parent_id_winner == 'this' and name_winner == 'this':
792
# No change for this directory in OTHER, skip
794
content_changed = False
795
elif other_ie.kind == 'file':
796
def get_sha1(ie, tree):
797
if ie.kind != 'file':
799
return tree.get_file_sha1(file_id)
800
base_sha1 = get_sha1(base_ie, self.base_tree)
801
lca_sha1s = [get_sha1(ie, tree) for ie, tree
802
in zip(lca_entries, self._lca_trees)]
803
this_sha1 = get_sha1(this_ie, self.this_tree)
804
other_sha1 = get_sha1(other_ie, self.other_tree)
805
sha1_winner = self._lca_multi_way(
806
(base_sha1, lca_sha1s), other_sha1, this_sha1,
807
allow_overriding_lca=False)
808
exec_winner = self._lca_multi_way(
809
(base_ie.executable, lca_executable),
810
other_ie.executable, this_ie.executable)
811
if (parent_id_winner == 'this' and name_winner == 'this'
812
and sha1_winner == 'this' and exec_winner == 'this'):
813
# No kind, parent, name, exec, or content change for
814
# OTHER, so this node is not considered interesting
816
if sha1_winner == 'this':
817
content_changed = False
818
elif other_ie.kind == 'symlink':
819
def get_target(ie, tree):
820
if ie.kind != 'symlink':
822
return tree.get_symlink_target(file_id)
823
base_target = get_target(base_ie, self.base_tree)
824
lca_targets = [get_target(ie, tree) for ie, tree
825
in zip(lca_entries, self._lca_trees)]
826
this_target = get_target(this_ie, self.this_tree)
827
other_target = get_target(other_ie, self.other_tree)
828
target_winner = self._lca_multi_way(
829
(base_target, lca_targets),
830
other_target, this_target)
831
if (parent_id_winner == 'this' and name_winner == 'this'
832
and target_winner == 'this'):
833
# No kind, parent, name, or symlink target change
836
if target_winner == 'this':
837
content_changed = False
838
elif other_ie.kind == 'tree-reference':
839
# The 'changed' information seems to be handled at a higher
840
# level. At least, _entries3 returns False for content
841
# changed, even when at a new revision_id.
842
content_changed = False
843
if (parent_id_winner == 'this' and name_winner == 'this'):
844
# Nothing interesting
847
raise AssertionError('unhandled kind: %s' % other_ie.kind)
848
# XXX: We need to handle kind == 'symlink'
850
# If we have gotten this far, that means something has changed
851
result.append((file_id, content_changed,
852
((base_ie.parent_id, lca_parent_ids),
853
other_ie.parent_id, this_ie.parent_id),
854
((base_ie.name, lca_names),
855
other_ie.name, this_ie.name),
856
((base_ie.executable, lca_executable),
857
other_ie.executable, this_ie.executable)
623
862
def fix_root(self):
625
864
self.tt.final_kind(self.tt.root)
956
def _lca_multi_way(bases, other, this, allow_overriding_lca=True):
957
"""Consider LCAs when determining whether a change has occurred.
959
If LCAS are all identical, this is the same as a _three_way comparison.
961
:param bases: value in (BASE, [LCAS])
962
:param other: value in OTHER
963
:param this: value in THIS
964
:param allow_overriding_lca: If there is more than one unique lca
965
value, allow OTHER to override THIS if it has a new value, and
966
THIS only has an lca value, or vice versa. This is appropriate for
967
truly scalar values, not as much for non-scalars.
968
:return: 'this', 'other', or 'conflict' depending on whether an entry
971
# See doc/developers/lca_merge_resolution.txt for details about this
974
# Either Ambiguously clean, or nothing was actually changed. We
977
base_val, lca_vals = bases
978
# Remove 'base_val' from the lca_vals, because it is not interesting
979
filtered_lca_vals = [lca_val for lca_val in lca_vals
980
if lca_val != base_val]
981
if len(filtered_lca_vals) == 0:
982
return Merge3Merger._three_way(base_val, other, this)
984
unique_lca_vals = set(filtered_lca_vals)
985
if len(unique_lca_vals) == 1:
986
return Merge3Merger._three_way(unique_lca_vals.pop(), other, this)
988
if allow_overriding_lca:
989
if other in unique_lca_vals:
990
if this in unique_lca_vals:
991
# Each side picked a different lca, conflict
994
# This has a value which supersedes both lca values, and
995
# other only has an lca value
997
elif this in unique_lca_vals:
998
# OTHER has a value which supersedes both lca values, and this
999
# only has an lca value
1002
# At this point, the lcas disagree, and the tips disagree
717
1006
def scalar_three_way(this_tree, base_tree, other_tree, file_id, key):
718
1007
"""Do a three-way test on a scalar.
719
1008
Return "this", "other" or "conflict", depending whether a value wins.