treemanifests: actually strip directory manifests
authorMartin von Zweigbergk <martinvonz@google.com>
Thu, 30 Jun 2016 13:06:19 -0700
changeset 32084 87c184c9bfef7183eea89a065b7d8953f7fbfee2
parent 32083 4cf0542dcbe747e9acb35e771e033e89eb681bc7
child 32085 00d2bf4137e6fabbfbd596b51b7431ae7a8a4c44
push id270
push usergszorc@mozilla.com
push dateWed, 06 Jul 2016 06:37:04 +0000
treemanifests: actually strip directory manifests Stripping has only partly worked since 7cbb3a01fa38 (repair: use cg3 for treemanifests, 2016-01-19): the bundle seems to have been created correctly, but revlog entries in subdirectory revlogs were not stripped. This meant that e.g. "hg verify" would fail after stripping in a tree manifest repo. To find the revisions to strip, we simply iterate over all directories in the repo (included in store.datafiles()). This is inefficient for stripping few commits, but efficient for stripping many commits. To optimize for stripping few commits, we could instead walk the tree from the root and find modified subdirectories, just like we do in the changegroup code. I'm leaving that for another day.
mercurial/repair.py
tests/test-treemanifest.t
--- a/mercurial/repair.py
+++ b/mercurial/repair.py
@@ -162,16 +162,23 @@ def strip(ui, repo, nodelist, backup=Tru
 
     try:
         with repo.transaction("strip") as tr:
             offset = len(tr.entries)
 
             tr.startgroup()
             cl.strip(striprev, tr)
             mfst.strip(striprev, tr)
+            if 'treemanifest' in repo.requirements: # safe but unnecessary
+                                                    # otherwise
+                for unencoded, encoded, size in repo.store.datafiles():
+                    if (unencoded.startswith('meta/') and
+                        unencoded.endswith('00manifest.i')):
+                        dir = unencoded[5:-12]
+                        repo.dirlog(dir).strip(striprev, tr)
             for fn in files:
                 repo.file(fn).strip(striprev, tr)
             tr.endgroup()
 
             for i in xrange(offset, len(tr.entries)):
                 file, troffset, ignore = tr.entries[i]
                 repo.svfs(file, 'a').truncate(troffset)
                 if troffset == 0:
--- a/tests/test-treemanifest.t
+++ b/tests/test-treemanifest.t
@@ -304,17 +304,26 @@ Turning off treemanifest config has no e
 
 Stripping and recovering changes should work
 
   $ hg st --change tip
   M dir1/a
   $ hg --config extensions.strip= strip tip
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   saved backup bundle to $TESTTMP/repo-mixed/.hg/strip-backup/51cfd7b1e13b-78a2f3ed-backup.hg (glob)
+  $ hg debugindex --dir dir1
+     rev    offset  length  delta linkrev nodeid       p1           p2
+       0         0     127     -1       4 064927a0648a 000000000000 000000000000
+       1       127     111      0       5 25ecb8cb8618 000000000000 000000000000
   $ hg unbundle -q .hg/strip-backup/*
+  $ hg debugindex --dir dir1
+     rev    offset  length  delta linkrev nodeid       p1           p2
+       0         0     127     -1       4 064927a0648a 000000000000 000000000000
+       1       127     111      0       5 25ecb8cb8618 000000000000 000000000000
+       2       238      55      1       6 5b16163a30c6 25ecb8cb8618 000000000000
   $ hg st --change tip
   M dir1/a
 
 Shelving and unshelving should work
 
   $ echo foo >> dir1/a
   $ hg --config extensions.shelve= shelve
   shelved as default