mercurial/hg.py
changeset 94 7daef883134f
parent 90 ab9ebff09dcd
child 95 589f507bb259
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -30,42 +30,6 @@ class filelog(revlog):
     def add(self, text, transaction, link, p1=None, p2=None):
         return self.addrevision(text, transaction, link, p1, p2)
 
-    def resolvedag(self, old, new, transaction, link):
-        """resolve unmerged heads in our DAG"""
-        if old == new: return None
-        a = self.ancestor(old, new)
-        if old == a: return None
-        return self.merge3(old, new, a, transaction, link)
-
-    def merge3(self, my, other, base, transaction, link):
-        """perform a 3-way merge and append the result"""
-        def temp(prefix, node):
-            (fd, name) = tempfile.mkstemp(prefix)
-            f = os.fdopen(fd, "w")
-            f.write(self.revision(node))
-            f.close()
-            return name
-
-        a = temp("local", my)
-        b = temp("remote", other)
-        c = temp("parent", base)
-
-        cmd = os.environ["HGMERGE"]
-        r = os.system("%s %s %s %s" % (cmd, a, b, c))
-        if r:
-            raise "Merge failed, implement rollback!"
-
-        t = open(a).read()
-        os.unlink(a)
-        os.unlink(b)
-        os.unlink(c)
-        return self.addrevision(t, transaction, link, my, other)
-
-    def merge(self, other, transaction, linkseq, link):
-        """perform a merge and resolve resulting heads"""
-        (o, n) = self.mergedag(other, transaction, linkseq)
-        return self.resolvedag(o, n, transaction, link)
-
     def annotate(self, node):
         revs = []
         while node != nullid:
@@ -160,9 +124,6 @@ class changelog(revlog):
         text = "\n".join(l)
         return self.addrevision(text, transaction, self.count(), p1, p2)
 
-    def merge3(self, my, other, base):
-        pass
-
 class dircache:
     def __init__(self, opener, ui):
         self.opener = opener
@@ -335,122 +296,6 @@ class localrepository:
     def transaction(self):
         return transaction(self.opener, self.join("journal"))
 
-    def merge(self, other):
-        tr = self.transaction()
-        changed = {}
-        new = {}
-        seqrev = self.changelog.count()
-        # some magic to allow fiddling in nested scope
-        nextrev = [seqrev]
-
-        # helpers for back-linking file revisions to local changeset
-        # revisions so we can immediately get to changeset from annotate
-        def accumulate(text):
-            # track which files are added in which changeset and the
-            # corresponding _local_ changeset revision
-            files = self.changelog.extract(text)[3]
-            for f in files:
-                changed.setdefault(f, []).append(nextrev[0])
-            nextrev[0] += 1
-
-        def seq(start):
-            while 1:
-                yield start
-                start += 1
-
-        def lseq(l):
-            for r in l:
-                yield r
-
-        # begin the import/merge of changesets
-        self.ui.status("merging new changesets\n")
-        (co, cn) = self.changelog.mergedag(other.changelog, tr,
-                                           seq(seqrev), accumulate)
-        resolverev = self.changelog.count()
-
-        # is there anything to do?
-        if co == cn:
-            tr.close()
-            return
-        
-        # do we need to resolve?
-        simple = (co == self.changelog.ancestor(co, cn))
-
-        # merge all files changed by the changesets,
-        # keeping track of the new tips
-        changelist = changed.keys()
-        changelist.sort()
-        for f in changelist:
-            sys.stdout.write(".")
-            sys.stdout.flush()
-            r = self.file(f)
-            node = r.merge(other.file(f), tr, lseq(changed[f]), resolverev)
-            if node:
-                new[f] = node
-        sys.stdout.write("\n")
-
-        # begin the merge of the manifest
-        self.ui.status("merging manifests\n")
-        (mm, mo) = self.manifest.mergedag(other.manifest, tr, seq(seqrev))
-
-        # For simple merges, we don't need to resolve manifests or changesets
-        if simple:
-            tr.close()
-            return
-
-        ma = self.manifest.ancestor(mm, mo)
-
-        # resolve the manifest to point to all the merged files
-        self.ui.status("resolving manifests\n")
-        omap = self.manifest.read(mo) # other
-        amap = self.manifest.read(ma) # ancestor
-        mmap = self.manifest.read(mm) # mine
-        nmap = {}
-
-        for f, mid in mmap.iteritems():
-            if f in omap:
-                if mid != omap[f]: 
-                    nmap[f] = new.get(f, mid) # use merged version
-                else:
-                    nmap[f] = new.get(f, mid) # they're the same
-                del omap[f]
-            elif f in amap:
-                if mid != amap[f]: 
-                    pass # we should prompt here
-                else:
-                    pass # other deleted it
-            else:
-                nmap[f] = new.get(f, mid) # we created it
-                
-        del mmap
-
-        for f, oid in omap.iteritems():
-            if f in amap:
-                if oid != amap[f]:
-                    pass # this is the nasty case, we should prompt
-                else:
-                    pass # probably safe
-            else:
-                nmap[f] = new.get(f, oid) # remote created it
-
-        del omap
-        del amap
-
-        node = self.manifest.add(nmap, tr, resolverev, mm, mo)
-
-        # Now all files and manifests are merged, we add the changed files
-        # and manifest id to the changelog
-        self.ui.status("committing merge changeset\n")
-        new = new.keys()
-        new.sort()
-        if co == cn: cn = -1
-
-        edittext = "\n"+"".join(["HG: changed %s\n" % f for f in new])
-        edittext = self.ui.edit(edittext)
-        n = self.changelog.add(node, new, edittext, tr, co, cn)
-
-        tr.close()
-
     def commit(self, parent, update = None, text = ""):
         tr = self.transaction()
         
@@ -640,19 +485,26 @@ class localrepository:
     def newer(self, nodes):
         m = {}
         nl = []
+        pm = {}
         cl = self.changelog
         t = l = cl.count()
+
+        # find the lowest numbered node
         for n in nodes:
             l = min(l, cl.rev(n))
-            for p in cl.parents(n):
-                m[p] = 1
+            m[n] = 1
 
         for i in xrange(l, t):
             n = cl.node(i)
+            if n in m: # explicitly listed
+                pm[n] = 1
+                nl.append(n)
+                continue
             for p in cl.parents(n):
-                if p in m and n not in m:
-                    m[n] = 1
+                if p in pm: # parent listed
+                    pm[n] = 1
                     nl.append(n)
+                    break
 
         return nl
 
@@ -676,13 +528,14 @@ class localrepository:
                 self.ui.debug("found incomplete branch %s\n" % short(n[1]))
                 search.append(n) # schedule branch range for scanning
             else:
+                if n[2] in m and n[3] in m:
+                    if n[1] not in fetch:
+                        self.ui.debug("found new changeset %s\n" %
+                                      short(n[1]))
+                        fetch.append(n[1]) # earliest unknown
+                        continue
                 for b in remote.branches([n[2], n[3]]):
-                    if b[0] in m:
-                        if n[1] not in fetch:
-                            self.ui.debug("found new changeset %s\n" %
-                                          short(n[1]))
-                            fetch.append(n[1]) # earliest unknown
-                    else:
+                    if b[0] not in m:
                         unknown.append(b)
   
         while search:
@@ -707,7 +560,7 @@ class localrepository:
             if f in m:
                 raise "already have", short(f[:4])
 
-        self.ui.note("merging new changesets starting at " +
+        self.ui.note("adding new changesets starting at " +
                      " ".join([short(f) for f in fetch]) + "\n")
 
         return remote.changegroup(fetch)
@@ -767,13 +620,17 @@ class localrepository:
         tr = self.transaction()
         simple = True
 
-        self.ui.status("merging changesets\n")
+        self.ui.status("adding changesets\n")
         # pull off the changeset group
+        def report(x):
+            self.ui.debug("add changeset %s\n" % short(x))
+            return self.changelog.count()
+            
         csg = getchunk()
         co = self.changelog.tip()
-        cn = self.changelog.addgroup(csg, lambda x: self.changelog.count(), tr)
+        cn = self.changelog.addgroup(csg, report, tr)
 
-        self.ui.status("merging manifests\n")
+        self.ui.status("adding manifests\n")
         # pull off the manifest group
         mfg = getchunk()
         mm = self.manifest.tip()
@@ -785,21 +642,21 @@ class localrepository:
             resolverev = self.changelog.count()
 
         # process the files
-        self.ui.status("merging files\n")
+        self.ui.status("adding files\n")
         new = {}
         while 1:
             f = getchunk(4)
             if not f: break
             fg = getchunk()
-
+            self.ui.debug("adding %s revisions\n" % f)
             fl = self.file(f)
             o = fl.tip()
             n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr)
             if not simple:
-                nn = fl.resolvedag(o, n, tr, resolverev)
-                if nn:
-                    self.ui.note("merged %s\n", f)
-                    new[f] = nn
+                if o == n: continue
+                # this file has changed between branches, so it must be
+                # represented in the merge changeset
+                new[f] = self.merge3(fl, f, o, n, tr, resolverev)
 
         # For simple merges, we don't need to resolve manifests or changesets
         if simple:
@@ -821,8 +678,9 @@ class localrepository:
             if f in omap:
                 if mid != omap[f]:
                     self.ui.debug("%s versions differ\n" % f)
-                    if f in new: self.ui.note("%s updated in resolve\n" % f)
-                    nmap[f] = new.get(f, mid) # use merged version
+                    if f in new: self.ui.debug("%s updated in resolve\n" % f)
+                    # use merged version or local version
+                    nmap[f] = new.get(f, mid)
                 else:
                     nmap[f] = mid # keep ours
                 del omap[f]