make pull work for multiple heads
authormpm@selenic.com
Thu, 02 Jun 2005 18:46:49 -0800
changeset 222 87484f627422
parent 221 2bfe525ef6ca
child 223 1aaa49039a6b
make pull work for multiple heads -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 make pull work for multiple heads add repository.heads() teach remoterepository and hgweb about heads command teach getchangegroup about multiple heads break apart addchangegroup and merge (cleaning up merge saved for later) after this change, it is now possible to pull and get multiple heads, but not possible to merge the heads manifest hash: 86fe3ede296254698fdd4c97df02944993ef2cbb -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCn8SZywK+sNU5EO8RAkSvAJ9NOA4UZ3cFyyzymlYBZnV+PpGRcACeLL+R PFaSgJHGKvxsXpvPYiZA0O0= =L2Xr -----END PGP SIGNATURE-----
mercurial/hg.py
mercurial/hgweb.py
--- a/mercurial/hg.py	Thu Jun 02 18:07:01 2005 -0800
+++ b/mercurial/hg.py	Thu Jun 02 18:46:49 2005 -0800
@@ -594,6 +594,9 @@
             else:
                 self.dirstate.update([f], "r")
 
+    def heads(self):
+        return self.changelog.heads()
+
     def branches(self, nodes):
         if not nodes: nodes = [self.changelog.tip()]
         b = []
@@ -659,22 +662,24 @@
         seen = {}
         seenbranch = {}
 
-        self.ui.status("searching for changes\n")
-        tip = remote.branches([])[0]
-        self.ui.debug("remote tip branch is %s:%s\n" %
-                      (short(tip[0]), short(tip[1])))
-
         # if we have an empty repo, fetch everything
         if self.changelog.tip() == nullid:
+            self.ui.status("requesting all changes\n")
             return remote.changegroup([nullid])
 
         # otherwise, assume we're closer to the tip than the root
-        unknown = [tip]
+        self.ui.status("searching for changes\n")
+        heads = remote.heads()
+        unknown = []
+        for h in heads:
+            if h not in m:
+                unknown.append(h)
 
-        if tip[0] in m:
+        if not unknown:
             self.ui.status("nothing to do!\n")
             return None
-
+            
+        unknown = remote.branches(unknown)
         while unknown:
             n = unknown.pop(0)
             seen[n[0]] = 1
@@ -766,6 +771,77 @@
                 yield y
 
     def addchangegroup(self, generator):
+
+        class genread:
+            def __init__(self, generator):
+                self.g = generator
+                self.buf = ""
+            def read(self, l):
+                while l > len(self.buf):
+                    try:
+                        self.buf += self.g.next()
+                    except StopIteration:
+                        break
+                d, self.buf = self.buf[:l], self.buf[l:]
+                return d
+                
+        def getchunk():
+            d = source.read(4)
+            if not d: return ""
+            l = struct.unpack(">l", d)[0]
+            if l <= 4: return ""
+            return source.read(l - 4)
+
+        def getgroup():
+            while 1:
+                c = getchunk()
+                if not c: break
+                yield c
+
+        def csmap(x):
+            self.ui.debug("add changeset %s\n" % short(x))
+            return self.changelog.count()
+
+        def revmap(x):
+            return self.changelog.rev(x)
+
+        if not generator: return
+        changesets = files = revisions = 0
+        self.lock()
+        source = genread(generator)
+        tr = self.transaction()
+
+        # pull off the changeset group
+        self.ui.status("adding changesets\n")
+        co = self.changelog.tip()
+        cn = self.changelog.addgroup(getgroup(), csmap, tr)
+        changesets = self.changelog.rev(cn) - self.changelog.rev(co)
+
+        # pull off the manifest group
+        self.ui.status("adding manifests\n")
+        mm = self.manifest.tip()
+        mo = self.manifest.addgroup(getgroup(), revmap, tr)
+
+        # process the files
+        self.ui.status("adding file revisions\n")
+        while 1:
+            f = getchunk()
+            if not f: break
+            self.ui.debug("adding %s revisions\n" % f)
+            fl = self.file(f)
+            o = fl.tip()
+            n = fl.addgroup(getgroup(), revmap, tr)
+            revisions += fl.rev(n) - fl.rev(o)
+            files += 1
+
+        self.ui.status(("modified %d files, added %d changesets" +
+                        " and %d new revisions\n")
+                       % (files, changesets, revisions))
+
+        tr.close()
+        return
+
+    def merge(self, generator):
         changesets = files = revisions = 0
 
         self.lock()
@@ -980,6 +1056,14 @@
         cu = "%s?%s" % (self.url, qs)
         return urllib.urlopen(cu)
 
+    def heads(self):
+        d = self.do_cmd("heads").read()
+        try:
+            return map(bin, d[:-1].split(" "))
+        except:
+            self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
+            raise
+
     def branches(self, nodes):
         n = " ".join(map(hex, nodes))
         d = self.do_cmd("branches", nodes=n).read()
--- a/mercurial/hgweb.py	Thu Jun 02 18:07:01 2005 -0800
+++ b/mercurial/hgweb.py	Thu Jun 02 18:46:49 2005 -0800
@@ -608,6 +608,11 @@
         elif args['cmd'][0] == 'filelog':
             write(self.filelog(args['file'][0], args['filenode'][0]))
 
+        elif args['cmd'][0] == 'heads':
+            httphdr("text/plain")
+            h = self.repo.heads()
+            sys.stdout.write(" ".join(map(hex, h)) + "\n")
+
         elif args['cmd'][0] == 'branches':
             httphdr("text/plain")
             nodes = []