git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 0/2] A new merge algorithm, take 3

From
Fredrik Kuivinen <freku045@student.liu.se>
Date
Sep 7, 2005, 16:47 UTC
Message-ID
<20050907164734.GA20198@c165.ib.student.liu.se>
Hi,
Here is the new version of the merge algorithm patch.
The major changes compared to the previous patch are:
* No more messing around with merge-cache. git-ls-files used to get
  the unmerged entries instead.
* The python code is now contained in two files, git-merge-script and
  gitMergeCommon.py.
* The user interface is identical to the interface provided by
  git-resolve-script
* In the non-clean case the unmerged cache entries will not be
  removed from the cache.

I have also attached a test script which can redo every merge in a repository with both git-resolve-script and git-merge-script. It will report any non-clean merges and non-identical results for clean merges. Do _not_ use this script in repositories you care about. It calls 'git reset --hard' repeatedly and will probably not leave the repository in its original state when it's done.

Of the 500 merge commits that currently exists in the kernel repository 19 produces non-clean merges with git-merge-script. The four merge cases listed in <20050827014009.GB18880@c165.ib.student.liu.se> are cleanly merged by git-merge-script. Every merge commit which is cleanly merged by git-resolve-script is also cleanly merged by git-merge-script, furthermore the results are identical. There are currently two merges in the kernel repository which are not cleanly merged by git-resolve-script but are cleanly merged by git-merge-script.

I guess the need for this has decreased with Daniel's new read-tree code. Is there any chance of getting this code merged into mainline git?

- Fredrik
#!/usr/bin/env python

import sys, math, random, os, re, signal, tempfile, time from heapq import heappush, heappop from sets import Set from gitMergeCommon import *

def mergeMerge(a, b):
    print 'Running merge-script HEAD', b.sha, '...'
    [out, code] = runProgram(['git-merge-script', 'HEAD', b.sha, 'merge message'],
                             returnCode=True, pipeOutput=False)
    if code == 0:
        return True
    else:
        return False
    
def gitResolveMerge(a, b):
    print 'Running git resolve HEAD', b.sha, '...'
    [out, code] = runProgram(['git', 'resolve', 'HEAD', b.sha, 'merge message'],
                             returnCode=True, pipeOutput=False)
    if code == 0:
        return True
    else:
        return False
def doWork(graph, commits):
    print 'commits:', repr(commits)
    result = []
    totalMergeTime = 0
    totalResolveTime = 0
    numCommits = 0
    try:
        for commit in graph.commits:
            if len(commits) > 0 and not (commit.sha in commits):
                continue
            if len(commit.parents) > 1:
                res = commit.sha + ' : '
                if len(commit.parents) == 2:
                    numCommits += 1
                    print '---------------------------------------'
                    print 'Testing commit', commit.sha, '(tree)', commit.tree()
                    a = commit.parents[0]
                    b = commit.parents[1]
                    runProgram(['git-reset-script', '--hard', a.sha])
                    print 'Running git resolve...'
                    stdout.flush()
                    startTime = time.time()
                    resResolve = gitResolveMerge(a, b)
                    timeResolve = time.time() - startTime
                    totalResolveTime += timeResolve
                    
                    if resResolve:
                        resolveHead = Commit(runProgram(['git-rev-parse', '--verify', 'HEAD']).rstrip(), [a, b])
                    runProgram(['git-reset-script', '--hard', a.sha])
                    print 'Running merge...'
                    stdout.flush()
                    startTime = time.time()
                    resMerge = mergeMerge(a, b)
                    timeMerge = time.time() - startTime
                    totalMergeTime += timeMerge
                    
                    if resMerge:
                        mergeHead = Commit(runProgram(['git-rev-parse', '--verify', 'HEAD']).rstrip(), [a, b])
                    res += 'time r: ' + str(int(timeResolve)) + ' m: ' + str(int(timeMerge)) + '\t'
                    if resResolve and resMerge:
                        if resolveHead.tree() == mergeHead.tree():
                            res += 'Identical result'
                        else:
                            res += 'Non-identical results! resolve: ' + resolveHead.sha + \
                                   ' merge: ' + mergeHead.sha
                    else:
                        if resResolve:
                            res += 'resolve succeeded (' + resolveHead.sha + '), '
                        else:
                            res += 'resolve failed, '
                        if resMerge:
                            res += 'merge succeeded (' + mergeHead.sha + ')'
                        else:
                            res += 'merge failed'
                else:
                    res += 'Ignoring octupus merge'
                print res
                result.append(res)
                stdout.flush()
    finally:
        print '\n\n\nResults:'
        for r in result:
            print r
        print 'Avg resolve time:', float(totalResolveTime) / numCommits
        print 'Avg merge time:', float(totalMergeTime) / numCommits
def writeHead(head, sha):
    if sha[-1] != '\n':
        sha += '\n'
    try:
        f = open(os.environ['GIT_DIR'] + '/' + head, 'w')
        f.write(sha)
        f.close()
    except IOError, e:
        print 'Failed to write to', os.environ['GIT_DIR'] + '/' + head + ':', e.strerror
        sys.exit(1)
    return True

stdout = sys.stdout setupEnvironment() repoValid()

head = runProgram(['git-rev-parse', '--verify', 'HEAD^0']).rstrip()
print 'Building graph...'
stdout.flush()
graph = buildGraph([head])
print 'Graph building done.'
stdout.flush()
print 'Processing', len(graph.commits), 'commits (' + \
      str(len([x for x in graph.commits if len(x.parents) > 1])) + ' merge commits)...'

originalHead = open('.git/HEAD', 'r').read() print 'Original head:', originalHead stdout.flush()

writeHead('original-head', originalHead)
try:
    doWork(graph, sys.argv[1:])
finally:
    writeHead('HEAD', originalHead)
Next: Fredrik Kuivinen
Message 1 of 40 in “A new merge algorithm, take 3”
  1. 0/2 A new merge algorithm, take 3Fredrik Kuivinen, Sep 7, 2005
  2. 1/2 Add '-i' flag to read-tree to make it ignore whats in the working directory.Fredrik Kuivinen, Sep 7, 2005
  3. Unified merge driver pushed out to "master" branchJunio C Hamano, Sep 11, 2005
  4. Fredrik KuivinenSep 11, 2005
  5. Junio C HamanoSep 12, 2005
  6. Another merge test case from the kernel tree.Junio C Hamano, Sep 14, 2005
  7. Daniel BarkalowSep 14, 2005
  8. Junio C HamanoSep 14, 2005
  9. Fredrik KuivinenSep 14, 2005
  10. Junio C HamanoSep 14, 2005
  11. Yet another set of merge test cases from the kernel tree.Junio C Hamano, Sep 15, 2005
  12. Fredrik KuivinenSep 19, 2005
  13. Junio C HamanoSep 20, 2005
  14. Fredrik KuivinenSep 20, 2005
  15. 2/2 A new merge algorithmFredrik Kuivinen, Sep 7, 2005
  16. Daniel BarkalowSep 7, 2005
  17. Fredrik KuivinenSep 8, 2005
  18. Daniel BarkalowSep 8, 2005
  19. Fredrik KuivinenSep 8, 2005
  20. Daniel BarkalowSep 8, 2005
  21. Junio C HamanoSep 7, 2005
  22. Junio C HamanoSep 8, 2005
  23. A Large Angry SCMSep 8, 2005
  24. Chuck LeverSep 8, 2005
  25. Junio C HamanoSep 8, 2005
  26. Linus TorvaldsSep 8, 2005
  27. Junio C HamanoSep 8, 2005
  28. Chuck LeverSep 8, 2005
  29. Linus TorvaldsSep 8, 2005
  30. Chuck LeverSep 8, 2005
  31. Linus TorvaldsSep 8, 2005
  32. [RFH] Merge driverJunio C Hamano, Sep 9, 2005
  33. Daniel BarkalowSep 9, 2005
  34. Junio C HamanoSep 9, 2005
  35. Daniel BarkalowSep 9, 2005
  36. [RFH] Merge driverJunio C Hamano, Sep 11, 2005
  37. Fredrik KuivinenSep 12, 2005
  38. Junio C HamanoSep 12, 2005
  39. Fredrik KuivinenSep 13, 2005
  40. Junio C HamanoSep 13, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.