[PATCH 4 of 9] Keep track of all the heads of a named branch

Alexis S. L. Carvalho alexis at cecm.usp.br
Sun Mar 2 13:01:26 CST 2008


# HG changeset patch
# User Alexis S. L. Carvalho <alexis at cecm.usp.br>
# Date 1204481759 10800
# Node ID 2732432795d01fde336951d15fa6f0f284e82da1
# Parent  d50e75fa6401bc17ae1389b8d72a6dbc6f0db22b
Keep track of all the heads of a named branch

A revision is the head of a named branch if it has no descendants
in that branch.

The branch cache file is moved to .hg/store/cache.branch .

diff -r d50e75fa6401 -r 2732432795d0 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Sun Mar 02 15:15:59 2008 -0300
+++ b/mercurial/localrepo.py	Sun Mar 02 15:15:59 2008 -0300
@@ -384,7 +384,7 @@ class localrepository(repo.repository):
     def _readbranchcache(self):
         partial = {}
         try:
-            f = self.opener("branch.cache")
+            f = self.sopener("cache.branch")
             lines = f.read().split('\n')
             f.close()
         except (IOError, OSError):
@@ -402,7 +402,10 @@ class localrepository(repo.repository):
                     continue
                 node, label = l.split(" ", 1)
                 label = label.strip()
-                partial[label] = [bin(node)]
+                if label in partial:
+                    partial[label].append(bin(node))
+                else:
+                    partial[label] = [bin(node)]
         except (KeyboardInterrupt, util.SignalInterrupt):
             raise
         except Exception, inst:
@@ -413,7 +416,7 @@ class localrepository(repo.repository):
 
     def _writebranchcache(self, branches, tip, tiprev):
         try:
-            f = self.opener("branch.cache", "w", atomictemp=True)
+            f = self.sopener("cache.branch", "w", atomictemp=True)
             f.write("%s %s\n" % (hex(tip), tiprev))
             for label, nodes in branches.iteritems():
                 for n in nodes:
@@ -423,10 +426,51 @@ class localrepository(repo.repository):
             pass
 
     def _updatebranchcache(self, partial, start, end):
+        # save the original heads of multi-headed branches to avoid an
+        # extra scan below.
+        mheads = {}
+        for b, nodes in partial.iteritems():
+            if len(nodes) > 1:
+                mheads[b] = nodes[:]
+
+        cl = self.changelog
+        changectx = self.changectx
+        parentrevs = cl.parentrevs
         for r in xrange(start, end):
-            c = self.changectx(r)
+            c = changectx(r)
+            n = c.node()
             b = c.branch()
-            partial[b] = [c.node()]
+            if b not in partial:
+                partial[b] = []
+            heads = partial[b]
+            # if our parents were in the list of heads, remove them
+            # (they're certainly not heads anymore)
+            for p in parentrevs(r):
+                if p == nullrev:
+                    continue
+                p = cl.node(p)
+                if p in heads:
+                    heads.remove(p)
+            heads.append(n)
+
+        # For each multi-headed branch, scan the DAG to make sure that one
+        # head is not an ancestor of the other. This is required to handle
+        # non-contiguous branches.
+        for b, nodes in partial.items():
+            if len(nodes) == 1 or nodes == mheads.get(b):
+                continue
+            revs = dict.fromkeys([cl.rev(n) for n in nodes])
+            seen = {}
+            heads = []
+            for r in xrange(max(revs), min(revs) - 1, -1):
+                if r in revs and r not in seen:
+                    heads.append(cl.node(r))
+                for p in parentrevs(r):
+                    seen[p] = 1
+
+            # make sure the branch tip is the last element
+            heads.reverse()
+            partial[b] = heads
 
     def lookup(self, key, multi=False):
         if key == '.':
diff -r d50e75fa6401 -r 2732432795d0 tests/test-branches.out
--- a/tests/test-branches.out	Sun Mar 02 15:15:59 2008 -0300
+++ b/tests/test-branches.out	Sun Mar 02 15:15:59 2008 -0300
@@ -4,11 +4,13 @@ 0 files updated, 0 files merged, 1 files
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 marked working directory as branch c
 c                              5:5ca481e59b8c
+b                              3:aee39cd168d0
 a                              1:dd6b440dd85a
 b                              4:22df7444f7c1 (inactive)
 default                        0:19709c5a4e75 (inactive)
 -------
 c                              5:5ca481e59b8c
+b                              3:aee39cd168d0
 a                              1:dd6b440dd85a
 --- Branch a
 changeset:   1:dd6b440dd85a
diff -r d50e75fa6401 -r 2732432795d0 tests/test-inherit-mode.out
--- a/tests/test-inherit-mode.out	Sun Mar 02 15:15:59 2008 -0300
+++ b/tests/test-inherit-mode.out	Sun Mar 02 15:15:59 2008 -0300
@@ -40,11 +40,11 @@ 00770 ../push/.hg/store/
 % group can still write everything
 00770 ../push/.hg/
 00660 ../push/.hg/00changelog.i
-00660 ../push/.hg/branch.cache
 00660 ../push/.hg/requires
 00770 ../push/.hg/store/
 00660 ../push/.hg/store/00changelog.i
 00660 ../push/.hg/store/00manifest.i
+00660 ../push/.hg/store/cache.branch
 00770 ../push/.hg/store/data/
 00770 ../push/.hg/store/data/dir/
 00660 ../push/.hg/store/data/dir/bar.i
diff -r d50e75fa6401 -r 2732432795d0 tests/test-mq-caches
--- a/tests/test-mq-caches	Sun Mar 02 15:15:59 2008 -0300
+++ b/tests/test-mq-caches	Sun Mar 02 15:15:59 2008 -0300
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-branches=.hg/branch.cache
+branches=.hg/store/cache.branch
 echo '[extensions]' >> $HGRCPATH
 echo 'hgext.mq=' >> $HGRCPATH
 
diff -r d50e75fa6401 -r 2732432795d0 tests/test-newbranch
--- a/tests/test-newbranch	Sun Mar 02 15:15:59 2008 -0300
+++ b/tests/test-newbranch	Sun Mar 02 15:15:59 2008 -0300
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-branchcache=.hg/branch.cache
+branchcache='.hg/store/cache.branch'
 
 hg init t
 cd t


More information about the Mercurial-devel mailing list