def test_tree_traversal(self): # low level tree tarversal odb = self.rorepo.odb H = self.rorepo.tree('29eb123beb1c55e5db4aa652d843adccbd09ae18') # head tree M = self.rorepo.tree('e14e3f143e7260de9581aee27e5a9b2645db72de') # merge tree B = self.rorepo.tree('f606937a7a21237c866efafcad33675e6539c103') # base tree B_old = self.rorepo.tree('1f66cfbbce58b4b552b041707a12d437cc5f400a') # old base tree # two very different trees entries = traverse_trees_recursive(odb, [B_old.binsha, H.binsha], '') self._assert_tree_entries(entries, 2) oentries = traverse_trees_recursive(odb, [H.binsha, B_old.binsha], '') assert len(oentries) == len(entries) self._assert_tree_entries(oentries, 2) # single tree is_no_tree = lambda i, d: i.type != 'tree' entries = traverse_trees_recursive(odb, [B.binsha], '') assert len(entries) == len(list(B.traverse(predicate=is_no_tree))) self._assert_tree_entries(entries, 1) # two trees entries = traverse_trees_recursive(odb, [B.binsha, H.binsha], '') self._assert_tree_entries(entries, 2) # tree trees entries = traverse_trees_recursive(odb, [B.binsha, H.binsha, M.binsha], '') self._assert_tree_entries(entries, 3)
def test_tree_traversal(self): # low level tree tarversal odb = self.rorepo.odb H = self.rorepo.tree( '29eb123beb1c55e5db4aa652d843adccbd09ae18') # head tree M = self.rorepo.tree( 'e14e3f143e7260de9581aee27e5a9b2645db72de') # merge tree B = self.rorepo.tree( 'f606937a7a21237c866efafcad33675e6539c103') # base tree B_old = self.rorepo.tree( '1f66cfbbce58b4b552b041707a12d437cc5f400a') # old base tree # two very different trees entries = traverse_trees_recursive(odb, [B_old.binsha, H.binsha], '') self._assert_tree_entries(entries, 2) oentries = traverse_trees_recursive(odb, [H.binsha, B_old.binsha], '') assert len(oentries) == len(entries) self._assert_tree_entries(oentries, 2) # single tree is_no_tree = lambda i, d: i.type != 'tree' entries = traverse_trees_recursive(odb, [B.binsha], '') assert len(entries) == len(list(B.traverse(predicate=is_no_tree))) self._assert_tree_entries(entries, 1) # two trees entries = traverse_trees_recursive(odb, [B.binsha, H.binsha], '') self._assert_tree_entries(entries, 2) # tree trees entries = traverse_trees_recursive(odb, [B.binsha, H.binsha, M.binsha], '') self._assert_tree_entries(entries, 3)
def aggressive_tree_merge(odb, tree_shas): """ :return: list of BaseIndexEntries representing the aggressive merge of the given trees. All valid entries are on stage 0, whereas the conflicting ones are left on stage 1, 2 or 3, whereas stage 1 corresponds to the common ancestor tree, 2 to our tree and 3 to 'their' tree. :param tree_shas: 1, 2 or 3 trees as identified by their binary 20 byte shas If 1 or two, the entries will effectively correspond to the last given tree If 3 are given, a 3 way merge is performed""" out = list() out_append = out.append # one and two way is the same for us, as we don't have to handle an existing # index, instrea if len(tree_shas) in (1, 2): for entry in traverse_tree_recursive(odb, tree_shas[-1], ''): out_append(_tree_entry_to_baseindexentry(entry, 0)) # END for each entry return out # END handle single tree if len(tree_shas) > 3: raise ValueError("Cannot handle %i trees at once" % len(tree_shas)) # three trees for base, ours, theirs in traverse_trees_recursive(odb, tree_shas, ''): if base is not None: # base version exists if ours is not None: # ours exists if theirs is not None: # it exists in all branches, if it was changed in both # its a conflict, otherwise we take the changed version # This should be the most common branch, so it comes first if( base[0] != ours[0] and base[0] != theirs[0] and ours[0] != theirs[0] ) or \ ( base[1] != ours[1] and base[1] != theirs[1] and ours[1] != theirs[1] ): # changed by both out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(ours, 2)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) elif base[0] != ours[0] or base[1] != ours[1]: # only we changed it out_append(_tree_entry_to_baseindexentry(ours, 0)) else: # either nobody changed it, or they did. In either # case, use theirs out_append(_tree_entry_to_baseindexentry(theirs, 0)) # END handle modification else: if ours[0] != base[0] or ours[1] != base[1]: # they deleted it, we changed it, conflict out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(ours, 2)) # else: # we didn't change it, ignore # pass # END handle our change # END handle theirs else: if theirs is None: # deleted in both, its fine - its out pass else: if theirs[0] != base[0] or theirs[1] != base[1]: # deleted in ours, changed theirs, conflict out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) # END theirs changed #else: # theirs didnt change # pass # END handle theirs # END handle ours else: # all three can't be None if ours is None: # added in their branch out_append(_tree_entry_to_baseindexentry(theirs, 0)) elif theirs is None: # added in our branch out_append(_tree_entry_to_baseindexentry(ours, 0)) else: # both have it, except for the base, see whether it changed if ours[0] != theirs[0] or ours[1] != theirs[1]: out_append(_tree_entry_to_baseindexentry(ours, 2)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) else: # it was added the same in both out_append(_tree_entry_to_baseindexentry(ours, 0)) # END handle two items # END handle heads # END handle base exists # END for each entries tuple return out
def aggressive_tree_merge(odb, tree_shas): """ :return: list of BaseIndexEntries representing the aggressive merge of the given trees. All valid entries are on stage 0, whereas the conflicting ones are left on stage 1, 2 or 3, whereas stage 1 corresponds to the common ancestor tree, 2 to our tree and 3 to 'their' tree. :param tree_shas: 1, 2 or 3 trees as identified by their binary 20 byte shas If 1 or two, the entries will effectively correspond to the last given tree If 3 are given, a 3 way merge is performed""" out = list() out_append = out.append # one and two way is the same for us, as we don't have to handle an existing # index, instrea if len(tree_shas) in (1, 2): for entry in traverse_tree_recursive(odb, tree_shas[-1], ''): out_append(_tree_entry_to_baseindexentry(entry, 0)) # END for each entry return out # END handle single tree if len(tree_shas) > 3: raise ValueError("Cannot handle %i trees at once" % len(tree_shas)) # three trees for base, ours, theirs in traverse_trees_recursive(odb, tree_shas, ''): if base is not None: # base version exists if ours is not None: # ours exists if theirs is not None: # it exists in all branches, if it was changed in both # its a conflict, otherwise we take the changed version # This should be the most common branch, so it comes first if(base[0] != ours[0] and base[0] != theirs[0] and ours[0] != theirs[0]) or \ (base[1] != ours[1] and base[1] != theirs[1] and ours[1] != theirs[1]): # changed by both out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(ours, 2)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) elif base[0] != ours[0] or base[1] != ours[1]: # only we changed it out_append(_tree_entry_to_baseindexentry(ours, 0)) else: # either nobody changed it, or they did. In either # case, use theirs out_append(_tree_entry_to_baseindexentry(theirs, 0)) # END handle modification else: if ours[0] != base[0] or ours[1] != base[1]: # they deleted it, we changed it, conflict out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(ours, 2)) # else: # we didn't change it, ignore # pass # END handle our change # END handle theirs else: if theirs is None: # deleted in both, its fine - its out pass else: if theirs[0] != base[0] or theirs[1] != base[1]: # deleted in ours, changed theirs, conflict out_append(_tree_entry_to_baseindexentry(base, 1)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) # END theirs changed # else: # theirs didnt change # pass # END handle theirs # END handle ours else: # all three can't be None if ours is None: # added in their branch out_append(_tree_entry_to_baseindexentry(theirs, 0)) elif theirs is None: # added in our branch out_append(_tree_entry_to_baseindexentry(ours, 0)) else: # both have it, except for the base, see whether it changed if ours[0] != theirs[0] or ours[1] != theirs[1]: out_append(_tree_entry_to_baseindexentry(ours, 2)) out_append(_tree_entry_to_baseindexentry(theirs, 3)) else: # it was added the same in both out_append(_tree_entry_to_baseindexentry(ours, 0)) # END handle two items # END handle heads # END handle base exists # END for each entries tuple return out