X-Git-Url: https://git.octo.it/?p=git.git;a=blobdiff_plain;f=git-merge-recursive.py;h=ce8a31fda050f36b24b8dffa5ee29e7dde074963;hp=767b13c927114d06986dfbab8b98b76340569deb;hb=HEAD;hpb=28e77a81647584bfbe112f19e12e9952ab0b2fab diff --git a/git-merge-recursive.py b/git-merge-recursive.py index 767b13c9..ce8a31fd 100755 --- a/git-merge-recursive.py +++ b/git-merge-recursive.py @@ -45,11 +45,10 @@ cacheOnly = False # The entry point to the merge code # --------------------------------- -def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0): +def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0, ancestor=None): '''Merge the commits h1 and h2, return the resulting virtual commit object and a flag indicating the cleaness of the merge.''' assert(isinstance(h1, Commit) and isinstance(h2, Commit)) - assert(isinstance(graph, Graph)) global outputIndent @@ -58,7 +57,11 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0): output(h2) sys.stdout.flush() - ca = getCommonAncestors(graph, h1, h2) + if ancestor: + ca = [ancestor] + else: + assert(isinstance(graph, Graph)) + ca = getCommonAncestors(graph, h1, h2) output('found', len(ca), 'common ancestor(s):') for x in ca: output(x) @@ -86,7 +89,7 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0): [shaRes, clean] = mergeTrees(h1.tree(), h2.tree(), mergedCA.tree(), branch1Name, branch2Name) - if clean or cacheOnly: + if graph and (clean or cacheOnly): res = Commit(None, [h1, h2], tree=shaRes) graph.addNode(res) else: @@ -205,11 +208,16 @@ def mergeFile(oPath, oSha, oMode, aPath, aSha, aMode, bPath, bSha, bMode, orig = runProgram(['git-unpack-file', oSha]).rstrip() src1 = runProgram(['git-unpack-file', aSha]).rstrip() src2 = runProgram(['git-unpack-file', bSha]).rstrip() - [out, code] = runProgram(['merge', - '-L', branch1Name + '/' + aPath, - '-L', 'orig/' + oPath, - '-L', branch2Name + '/' + bPath, - src1, orig, src2], returnCode=True) + try: + [out, code] = runProgram(['merge', + '-L', branch1Name + '/' + aPath, + '-L', 'orig/' + oPath, + '-L', branch2Name + '/' + bPath, + src1, orig, src2], returnCode=True) + except ProgramError, e: + print >>sys.stderr, e + die("Failed to execute 'merge'. merge(1) is used as the " + "file-level merge tool. Is 'merge' in your path?") sha = runProgram(['git-hash-object', '-t', 'blob', '-w', src1]).rstrip() @@ -283,18 +291,20 @@ def updateFileExt(sha, mode, path, updateCache, updateWd): def setIndexStages(path, oSHA1, oMode, aSHA1, aMode, - bSHA1, bMode): - prog = ['git-update-index', '-z', '--index-info'] - proc = subprocess.Popen(prog, stdin=subprocess.PIPE) - pipe = proc.stdin - # Clear stages first. - pipe.write("0 " + ("0" * 40) + "\t" + path + "\0") - # Set stages - pipe.write("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path)) - pipe.write("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path)) - pipe.write("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path)) - pipe.close() - proc.wait() + bSHA1, bMode, + clear=True): + istring = [] + if clear: + istring.append("0 " + ("0" * 40) + "\t" + path + "\0") + if oMode: + istring.append("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path)) + if aMode: + istring.append("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path)) + if bMode: + istring.append("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path)) + + runProgram(['git-update-index', '-z', '--index-info'], + input="".join(istring)) def removeFile(clean, path): updateCache = cacheOnly or clean @@ -576,7 +586,7 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB): continue ren1.processed = True - removeFile(True, ren1.srcName) + if ren2: # Renamed in 1 and renamed in 2 assert(ren1.srcName == ren2.srcName) @@ -604,13 +614,19 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB): 'adding as', dstName2, 'instead.') removeFile(False, ren2.dstName) else: - dstName2 = ren1.dstName + dstName2 = ren2.dstName + setIndexStages(dstName1, + None, None, + ren1.dstSha, ren1.dstMode, + None, None) + setIndexStages(dstName2, + None, None, + None, None, + ren2.dstSha, ren2.dstMode) - # NEEDSWORK: place dstNameA at stage 2 and dstNameB at stage 3 - # What about other stages??? - updateFile(False, ren1.dstSha, ren1.dstMode, dstName1) - updateFile(False, ren2.dstSha, ren2.dstMode, dstName2) else: + removeFile(True, ren1.srcName) + [resSha, resMode, clean, merge] = \ mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode, ren1.dstName, ren1.dstSha, ren1.dstMode, @@ -636,6 +652,8 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB): updateFile(clean, resSha, resMode, ren1.dstName) else: + removeFile(True, ren1.srcName) + # Renamed in 1, maybe changed in 2 if renamesA == renames1: stage = 3 @@ -724,7 +742,6 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB): cleanMerge = False if not cacheOnly: - # Stuff stage1/2/3 setIndexStages(ren1.dstName, oSHA1, oMode, aSHA1, aMode, @@ -877,12 +894,11 @@ def usage(): # main entry point as merge strategy module # The first parameters up to -- are merge bases, and the rest are heads. -# This strategy module figures out merge bases itself, so we only -# get heads. if len(sys.argv) < 4: usage() +bases = [] for nextArg in xrange(1, len(sys.argv)): if sys.argv[nextArg] == '--': if len(sys.argv) != nextArg + 3: @@ -893,6 +909,8 @@ for nextArg in xrange(1, len(sys.argv)): except IndexError: usage() break + else: + bases.append(sys.argv[nextArg]) print 'Merging', h1, 'with', h2 @@ -900,10 +918,17 @@ try: h1 = runProgram(['git-rev-parse', '--verify', h1 + '^0']).rstrip() h2 = runProgram(['git-rev-parse', '--verify', h2 + '^0']).rstrip() - graph = buildGraph([h1, h2]) - - [dummy, clean] = merge(graph.shaMap[h1], graph.shaMap[h2], - firstBranch, secondBranch, graph) + if len(bases) == 1: + base = runProgram(['git-rev-parse', '--verify', + bases[0] + '^0']).rstrip() + ancestor = Commit(base, None) + [dummy, clean] = merge(Commit(h1, None), Commit(h2, None), + firstBranch, secondBranch, None, 0, + ancestor) + else: + graph = buildGraph([h1, h2]) + [dummy, clean] = merge(graph.shaMap[h1], graph.shaMap[h2], + firstBranch, secondBranch, graph) print '' except: