def merge_trees(store, base, mine, theirs): ''' takes tree ids for base, mine, and theirs. merge trees into current working tee''' num_conflicts = 0 added = [] removed = [] w = walk_trees(store, [base, mine, theirs], True) count = 0 for b, m, t in w: if _is_tree(b) or _is_tree(m) or _is_tree(t): #todo... handle mkdir, rmdir continue # if mine == theirs match, use either elif m == t: if not b.path: print ' ', m.path, 'was added, but matches already' continue #leave workng tree alone # if base==theirs, but not mine, already deleted (do nothing) elif b == t and not m.path: print ' ', b.path, ' already deleted in head' continue # if base==mine, but not theirs, delete elif b == m and not t.path: print ' -', m.path, ' was deleted in theirs.' os.remove(m.path) removed.append(m.path) elif not b.path and m.path and not t.path: #add in mine print ' ', m.path, 'added in mine' continue elif not b.path and t.path and not m.path: # add theirs to mine # add theirs print ' +', t.path, ': adding to head' with open(t.path, 'w') as f: f.write(store[t.sha].data) added.append(t.path) elif not m == t: # conflict print ' ?', m.path, ': merging conflicts' result = diff3.merge( store[m.sha].data.splitlines(True), store[b.sha].data.splitlines(True) if b.sha else [''], store[t.sha].data.splitlines(True)) mergedfile = result['body'] had_conflict = result['conflict'] with open(m.path, 'w') as f: for line in mergedfile: f.write(line) if had_conflict: num_conflicts += 1 print( ' !!! {} had a conflict that could not be resolved.\n conflict markers added to file in working tree.\n you need to resolve manually ' .format(m.path)) added.append(m.path) return num_conflicts, added, removed
def merge_trees(store, base, mine, theirs): ''' takes tree ids for base, mine, and theirs. merge trees into current working tee''' num_conflicts=0 added=[] removed=[] w=walk_trees(store,[base,mine, theirs],True) count = 0 for b,m,t in w: if _is_tree(b) or _is_tree(m) or _is_tree(t): #todo... handle mkdir, rmdir continue # if mine == theirs match, use either elif m==t: if not b.path: print ' ',m.path, 'was added, but matches already' continue #leave workng tree alone # if base==theirs, but not mine, already deleted (do nothing) elif b==t and not m.path: print ' ',b.path, ' already deleted in head' continue # if base==mine, but not theirs, delete elif b==m and not t.path: print ' -',m.path, ' was deleted in theirs.' os.remove(m.path) removed.append(m.path) elif not b.path and m.path and not t.path: #add in mine print ' ',m.path ,'added in mine' continue elif not b.path and t.path and not m.path: # add theirs to mine # add theirs print ' +',t.path, ': adding to head' with open(t.path,'w') as f: f.write(store[t.sha].data) added.append(t.path) elif not m == t: # conflict print ' ?',m.path, ': merging conflicts' result=diff3.merge(store[m.sha].data.splitlines(True) ,store[b.sha].data.splitlines(True) if b.sha else [''] ,store[t.sha].data.splitlines(True)) mergedfile=result['body'] had_conflict=result['conflict'] with open(m.path,'w') as f: for line in mergedfile: f.write(line) if had_conflict: num_conflicts+=1 print(' !!! {} had a conflict that could not be resolved.\n conflict markers added to file in working tree.\n you need to resolve manually '.format(m.path)) added.append(m.path) return num_conflicts, added, removed
def walk_trees(store, tree_ids,prune_identical=False): """Recursively walk all the entries of N trees. Iteration is depth-first pre-order, as in e.g. os.walk. :param store: An ObjectStore for looking up objects. :param trees: iterable of SHAs for N trees :param prune_identical: If True, identical subtrees will not be walked. :return: Iterator over tuple contsining N TreeEntry objects for each of entries in the trees and their subtrees recursively. If an entry exists in one tree but not the other, the other entry will have all attributes set to None. If neither entry's path is None, they are guaranteed to match. """ # This could be fairly easily generalized to >2 trees if we find a use # case. modes= [tree_id and stat.S_IFDIR or None for tree_id in tree_ids] todo = [[TreeEntry(b'', mode, tree_id) for mode,tree_id in zip(modes,tree_ids)]] while todo: entries = todo.pop() is_trees = [_is_tree(entry) for entry in entries] if prune_identical and all(is_trees) and all_eq(entries): continue trees = [is_tree and store[entry.sha] or None for is_tree,entry in zip(is_trees,entries)] path = first_nonempty([entry.path for entry in entries]) todo.extend(reversed(_merge_entries(path, trees))) yield tuple(entries)