mercurial/repair.py
changeset 5909 f45f7390c1c5
parent 5905 3afbd82a6c82
child 5910 b9a830fa10f6
--- a/mercurial/repair.py	Sat Jan 19 18:01:16 2008 -0200
+++ b/mercurial/repair.py	Sat Jan 19 18:01:16 2008 -0200
@@ -21,9 +21,9 @@
             seen[p] = 1
     return heads
 
-def _bundle(repo, bases, heads, node, suffix):
+def _bundle(repo, bases, heads, node, suffix, extranodes=None):
     """create a bundle with the specified revisions as a backup"""
-    cg = repo.changegroupsubset(bases, heads, 'strip')
+    cg = repo.changegroupsubset(bases, heads, 'strip', extranodes)
     backupdir = repo.join("strip-backup")
     if not os.path.isdir(backupdir):
         os.mkdir(backupdir)
@@ -44,6 +44,42 @@
 
     return filenodes
 
+def _collectextranodes(repo, files, link):
+    """return the nodes that have to be saved before the strip"""
+    def collectone(revlog):
+        extra = []
+        startrev = count = revlog.count()
+        # find the truncation point of the revlog
+        for i in xrange(0, count):
+            node = revlog.node(i)
+            lrev = revlog.linkrev(node)
+            if lrev >= link:
+                startrev = i + 1
+                break
+
+        # see if any revision after that point has a linkrev less than link
+        # (we have to manually save these guys)
+        for i in xrange(startrev, count):
+            node = revlog.node(i)
+            lrev = revlog.linkrev(node)
+            if lrev < link:
+                extra.append((node, cl.node(lrev)))
+
+        return extra
+
+    extranodes = {}
+    cl = repo.changelog
+    extra = collectone(repo.manifest)
+    if extra:
+        extranodes[1] = extra
+    for fname in files:
+        f = repo.file(fname)
+        extra = collectone(f)
+        if extra:
+            extranodes[fname] = extra
+
+    return extranodes
+
 def _stripall(repo, striprev, filenodes):
     """strip the requested nodes from the filelogs"""
     # we go in two steps here so the strip loop happens in a
@@ -102,23 +138,27 @@
                 if cl.rev(x) > striprev:
                     savebases[x] = 1
 
+    filenodes = _collectfilenodes(repo, striprev)
+
+    extranodes = _collectextranodes(repo, filenodes, striprev)
+
     # create a changegroup for all the branches we need to keep
     if backup == "all":
         _bundle(repo, [node], cl.heads(), node, 'backup')
-    if saveheads:
-        chgrpfile = _bundle(repo, savebases.keys(), saveheads, node, 'temp')
+    if saveheads or extranodes:
+        chgrpfile = _bundle(repo, savebases.keys(), saveheads, node, 'temp',
+                            extranodes)
 
-    filenodes = _collectfilenodes(repo, striprev)
     _stripall(repo, striprev, filenodes)
 
     change = cl.read(node)
     cl.strip(striprev, striprev)
     repo.manifest.strip(repo.manifest.rev(change[0]), striprev)
-    if saveheads:
+    if saveheads or extranodes:
         ui.status("adding branch\n")
         f = open(chgrpfile, "rb")
         gen = changegroup.readbundle(f, chgrpfile)
-        repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile)
+        repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
         f.close()
         if backup != "strip":
             os.unlink(chgrpfile)