def test_merge_conflict(self): logging.debug('Testing a file blob merge conflict') reset_storage() f_branch_A=open('../resource/branch_A_conflict.txt','rb') f_branch_B=open('../resource/branch_B_conflict.txt','rb') f_ancest=open('../resource/common_ancestor.txt','rb') result = file_blob.merge(f_branch_A.read(), f_branch_B.read(), f_ancest.read()) print result
def test_merge_conflict(self): logging.debug('Testing a file blob merge conflict') reset_storage() f_branch_A = open('../resource/branch_A_conflict.txt', 'rb') f_branch_B = open('../resource/branch_B_conflict.txt', 'rb') f_ancest = open('../resource/common_ancestor.txt', 'rb') result = file_blob.merge(f_branch_A.read(), f_branch_B.read(), f_ancest.read()) print result
def merge(tb_A, tb_B, tb_C, merge_method = 'dupe_on_conflict'): """Merges two trees. C is common ancestor merge_method determines how conflicts are handled. dupe_on_conflict: default. try merging. if a conflict can't be resolved automatically save both file versions. dupe_always: if two folders/files need to be merged always save both copies force_merge: try merging. in case of conflict resolve automatically even if result contains unified diff sections. """ """ Algorithm -------------- A: update commit B: old commit C: common ancestor commit N: new tree -store trees from A, B, C, and N in easily traversable data structure -iterate through folders and files from A (from top down. these iterations only add to wd) -if B has it -no change necessary -add to N as is -if C has it, but B doesn't -means B deleted file/folder -don't add to N -if neither C nor B have it -means A added it -push change to wd -add to N -if B has same file name and path, but different hash as A -attempt merge -add merged file(s) to N -iterate through folders and files from B (from bottom up. these iterations only delete from wd) -if neither C nor A have it -means B added it -add to N -no change necessary -if C has it, but A doesn't -means A deleted file/folder -delete file/folder from wd -commit wd as merge -issues with algorithm -B moves file, A edits file """ merge_tb = tree_blob() merge_tb.root_node = tree_blob.TreeNode() merge_tb.root_node.name = tb_A.root_node.name merge_tb.root_node.node_type = 'folder' merge_tb.root_node.size=0 print 'walking tree' for path, node in tb_A.walk(): print path if path == merge_tb.root_node.name: continue if tb_B.has_node(path, node.node_type) and (tb_B.get_node(path, node.node_type)).hash_hex == node.hash_hex: #not modified merge_tb.add_node(path, node.node_type, node.hash_hex, int(node.size)) continue if tb_B.has_node(path, node.node_type) and (tb_B.get_node(path, node.node_type)).hash_hex != node.hash_hex: #merge files hash_hex_B = (tb_B.get_node(path, node.node_type)).hash_hex fb_B = file_blob() fb_B.load(key, storage, hash_hex_B) fb_A = file_blob() fb_A.load(key, storage, node.hash_hex) if tb_C.has_node(path, node.node_type): hash_hex_C = (tb_C.get_node(path, node.node_type)).hash_hex fb_C = file_blob() fb_C.load(key, storage, hash_hex_C) else: fb_C = fb_B merge_text = file_blob.merge(fb_A.apply_delta(key, storage), fb_B.apply_delta(key, storage), fb_C.apply_delta(key, storage)) fb_merge = file_blob() fb_merge.compute_delta(key, merge_text, fb_A, storage) merge_tb.add_node(path, node.node_type, node.hash_hex, int(node.size)) continue if tb_C.has_node(path, node.node_type): #B deleted continue merge_tb.add_node(path, node.node_type, node.hash_hex, int(node.size)) #A added for path, node in tb_B.walk(): print path if path == merge_tb.root_node.name: continue if (not tb_C.has_node(path, node.node_type)) and (not tb_A.has_node(path, node.node_type)): #B added merge_tb.add_node(path, node.node_type, node.hash_hex, int(node.size)) return merge_tb