##// END OF EJS Templates
treemanifests: actually strip directory manifests...
Martin von Zweigbergk -
r29464:87c184c9 default
parent child Browse files
Show More
@@ -1,347 +1,354
1 1 # repair.py - functions for repository repair for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 4 # Copyright 2007 Matt Mackall
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 import errno
12 12 import hashlib
13 13
14 14 from .i18n import _
15 15 from .node import short
16 16 from . import (
17 17 bundle2,
18 18 changegroup,
19 19 error,
20 20 exchange,
21 21 obsolete,
22 22 util,
23 23 )
24 24
25 25 def _bundle(repo, bases, heads, node, suffix, compress=True):
26 26 """create a bundle with the specified revisions as a backup"""
27 27 cgversion = changegroup.safeversion(repo)
28 28
29 29 cg = changegroup.changegroupsubset(repo, bases, heads, 'strip',
30 30 version=cgversion)
31 31 backupdir = "strip-backup"
32 32 vfs = repo.vfs
33 33 if not vfs.isdir(backupdir):
34 34 vfs.mkdir(backupdir)
35 35
36 36 # Include a hash of all the nodes in the filename for uniqueness
37 37 allcommits = repo.set('%ln::%ln', bases, heads)
38 38 allhashes = sorted(c.hex() for c in allcommits)
39 39 totalhash = hashlib.sha1(''.join(allhashes)).hexdigest()
40 40 name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix)
41 41
42 42 comp = None
43 43 if cgversion != '01':
44 44 bundletype = "HG20"
45 45 if compress:
46 46 comp = 'BZ'
47 47 elif compress:
48 48 bundletype = "HG10BZ"
49 49 else:
50 50 bundletype = "HG10UN"
51 51 return bundle2.writebundle(repo.ui, cg, name, bundletype, vfs,
52 52 compression=comp)
53 53
54 54 def _collectfiles(repo, striprev):
55 55 """find out the filelogs affected by the strip"""
56 56 files = set()
57 57
58 58 for x in xrange(striprev, len(repo)):
59 59 files.update(repo[x].files())
60 60
61 61 return sorted(files)
62 62
63 63 def _collectbrokencsets(repo, files, striprev):
64 64 """return the changesets which will be broken by the truncation"""
65 65 s = set()
66 66 def collectone(revlog):
67 67 _, brokenset = revlog.getstrippoint(striprev)
68 68 s.update([revlog.linkrev(r) for r in brokenset])
69 69
70 70 collectone(repo.manifest)
71 71 for fname in files:
72 72 collectone(repo.file(fname))
73 73
74 74 return s
75 75
76 76 def strip(ui, repo, nodelist, backup=True, topic='backup'):
77 77 # This function operates within a transaction of its own, but does
78 78 # not take any lock on the repo.
79 79 # Simple way to maintain backwards compatibility for this
80 80 # argument.
81 81 if backup in ['none', 'strip']:
82 82 backup = False
83 83
84 84 repo = repo.unfiltered()
85 85 repo.destroying()
86 86
87 87 cl = repo.changelog
88 88 # TODO handle undo of merge sets
89 89 if isinstance(nodelist, str):
90 90 nodelist = [nodelist]
91 91 striplist = [cl.rev(node) for node in nodelist]
92 92 striprev = min(striplist)
93 93
94 94 # Some revisions with rev > striprev may not be descendants of striprev.
95 95 # We have to find these revisions and put them in a bundle, so that
96 96 # we can restore them after the truncations.
97 97 # To create the bundle we use repo.changegroupsubset which requires
98 98 # the list of heads and bases of the set of interesting revisions.
99 99 # (head = revision in the set that has no descendant in the set;
100 100 # base = revision in the set that has no ancestor in the set)
101 101 tostrip = set(striplist)
102 102 for rev in striplist:
103 103 for desc in cl.descendants([rev]):
104 104 tostrip.add(desc)
105 105
106 106 files = _collectfiles(repo, striprev)
107 107 saverevs = _collectbrokencsets(repo, files, striprev)
108 108
109 109 # compute heads
110 110 saveheads = set(saverevs)
111 111 for r in xrange(striprev + 1, len(cl)):
112 112 if r not in tostrip:
113 113 saverevs.add(r)
114 114 saveheads.difference_update(cl.parentrevs(r))
115 115 saveheads.add(r)
116 116 saveheads = [cl.node(r) for r in saveheads]
117 117
118 118 # compute base nodes
119 119 if saverevs:
120 120 descendants = set(cl.descendants(saverevs))
121 121 saverevs.difference_update(descendants)
122 122 savebases = [cl.node(r) for r in saverevs]
123 123 stripbases = [cl.node(r) for r in tostrip]
124 124
125 125 # For a set s, max(parents(s) - s) is the same as max(heads(::s - s)), but
126 126 # is much faster
127 127 newbmtarget = repo.revs('max(parents(%ld) - (%ld))', tostrip, tostrip)
128 128 if newbmtarget:
129 129 newbmtarget = repo[newbmtarget.first()].node()
130 130 else:
131 131 newbmtarget = '.'
132 132
133 133 bm = repo._bookmarks
134 134 updatebm = []
135 135 for m in bm:
136 136 rev = repo[bm[m]].rev()
137 137 if rev in tostrip:
138 138 updatebm.append(m)
139 139
140 140 # create a changegroup for all the branches we need to keep
141 141 backupfile = None
142 142 vfs = repo.vfs
143 143 node = nodelist[-1]
144 144 if backup:
145 145 backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
146 146 repo.ui.status(_("saved backup bundle to %s\n") %
147 147 vfs.join(backupfile))
148 148 repo.ui.log("backupbundle", "saved backup bundle to %s\n",
149 149 vfs.join(backupfile))
150 150 if saveheads or savebases:
151 151 # do not compress partial bundle if we remove it from disk later
152 152 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
153 153 compress=False)
154 154
155 155 mfst = repo.manifest
156 156
157 157 curtr = repo.currenttransaction()
158 158 if curtr is not None:
159 159 del curtr # avoid carrying reference to transaction for nothing
160 160 msg = _('programming error: cannot strip from inside a transaction')
161 161 raise error.Abort(msg, hint=_('contact your extension maintainer'))
162 162
163 163 try:
164 164 with repo.transaction("strip") as tr:
165 165 offset = len(tr.entries)
166 166
167 167 tr.startgroup()
168 168 cl.strip(striprev, tr)
169 169 mfst.strip(striprev, tr)
170 if 'treemanifest' in repo.requirements: # safe but unnecessary
171 # otherwise
172 for unencoded, encoded, size in repo.store.datafiles():
173 if (unencoded.startswith('meta/') and
174 unencoded.endswith('00manifest.i')):
175 dir = unencoded[5:-12]
176 repo.dirlog(dir).strip(striprev, tr)
170 177 for fn in files:
171 178 repo.file(fn).strip(striprev, tr)
172 179 tr.endgroup()
173 180
174 181 for i in xrange(offset, len(tr.entries)):
175 182 file, troffset, ignore = tr.entries[i]
176 183 repo.svfs(file, 'a').truncate(troffset)
177 184 if troffset == 0:
178 185 repo.store.markremoved(file)
179 186
180 187 if saveheads or savebases:
181 188 ui.note(_("adding branch\n"))
182 189 f = vfs.open(chgrpfile, "rb")
183 190 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
184 191 if not repo.ui.verbose:
185 192 # silence internal shuffling chatter
186 193 repo.ui.pushbuffer()
187 194 if isinstance(gen, bundle2.unbundle20):
188 195 with repo.transaction('strip') as tr:
189 196 tr.hookargs = {'source': 'strip',
190 197 'url': 'bundle:' + vfs.join(chgrpfile)}
191 198 bundle2.applybundle(repo, gen, tr, source='strip',
192 199 url='bundle:' + vfs.join(chgrpfile))
193 200 else:
194 201 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
195 202 if not repo.ui.verbose:
196 203 repo.ui.popbuffer()
197 204 f.close()
198 205 repo._phasecache.invalidate()
199 206
200 207 for m in updatebm:
201 208 bm[m] = repo[newbmtarget].node()
202 209 lock = tr = None
203 210 try:
204 211 lock = repo.lock()
205 212 tr = repo.transaction('repair')
206 213 bm.recordchange(tr)
207 214 tr.close()
208 215 finally:
209 216 tr.release()
210 217 lock.release()
211 218
212 219 # remove undo files
213 220 for undovfs, undofile in repo.undofiles():
214 221 try:
215 222 undovfs.unlink(undofile)
216 223 except OSError as e:
217 224 if e.errno != errno.ENOENT:
218 225 ui.warn(_('error removing %s: %s\n') %
219 226 (undovfs.join(undofile), str(e)))
220 227
221 228 except: # re-raises
222 229 if backupfile:
223 230 ui.warn(_("strip failed, full bundle stored in '%s'\n")
224 231 % vfs.join(backupfile))
225 232 elif saveheads:
226 233 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
227 234 % vfs.join(chgrpfile))
228 235 raise
229 236 else:
230 237 if saveheads or savebases:
231 238 # Remove partial backup only if there were no exceptions
232 239 vfs.unlink(chgrpfile)
233 240
234 241 repo.destroyed()
235 242
236 243 def rebuildfncache(ui, repo):
237 244 """Rebuilds the fncache file from repo history.
238 245
239 246 Missing entries will be added. Extra entries will be removed.
240 247 """
241 248 repo = repo.unfiltered()
242 249
243 250 if 'fncache' not in repo.requirements:
244 251 ui.warn(_('(not rebuilding fncache because repository does not '
245 252 'support fncache)\n'))
246 253 return
247 254
248 255 with repo.lock():
249 256 fnc = repo.store.fncache
250 257 # Trigger load of fncache.
251 258 if 'irrelevant' in fnc:
252 259 pass
253 260
254 261 oldentries = set(fnc.entries)
255 262 newentries = set()
256 263 seenfiles = set()
257 264
258 265 repolen = len(repo)
259 266 for rev in repo:
260 267 ui.progress(_('rebuilding'), rev, total=repolen,
261 268 unit=_('changesets'))
262 269
263 270 ctx = repo[rev]
264 271 for f in ctx.files():
265 272 # This is to minimize I/O.
266 273 if f in seenfiles:
267 274 continue
268 275 seenfiles.add(f)
269 276
270 277 i = 'data/%s.i' % f
271 278 d = 'data/%s.d' % f
272 279
273 280 if repo.store._exists(i):
274 281 newentries.add(i)
275 282 if repo.store._exists(d):
276 283 newentries.add(d)
277 284
278 285 ui.progress(_('rebuilding'), None)
279 286
280 287 if 'treemanifest' in repo.requirements: # safe but unnecessary otherwise
281 288 for dir in util.dirs(seenfiles):
282 289 i = 'meta/%s/00manifest.i' % dir
283 290 d = 'meta/%s/00manifest.d' % dir
284 291
285 292 if repo.store._exists(i):
286 293 newentries.add(i)
287 294 if repo.store._exists(d):
288 295 newentries.add(d)
289 296
290 297 addcount = len(newentries - oldentries)
291 298 removecount = len(oldentries - newentries)
292 299 for p in sorted(oldentries - newentries):
293 300 ui.write(_('removing %s\n') % p)
294 301 for p in sorted(newentries - oldentries):
295 302 ui.write(_('adding %s\n') % p)
296 303
297 304 if addcount or removecount:
298 305 ui.write(_('%d items added, %d removed from fncache\n') %
299 306 (addcount, removecount))
300 307 fnc.entries = newentries
301 308 fnc._dirty = True
302 309
303 310 with repo.transaction('fncache') as tr:
304 311 fnc.write(tr)
305 312 else:
306 313 ui.write(_('fncache already up to date\n'))
307 314
308 315 def stripbmrevset(repo, mark):
309 316 """
310 317 The revset to strip when strip is called with -B mark
311 318
312 319 Needs to live here so extensions can use it and wrap it even when strip is
313 320 not enabled or not present on a box.
314 321 """
315 322 return repo.revs("ancestors(bookmark(%s)) - "
316 323 "ancestors(head() and not bookmark(%s)) - "
317 324 "ancestors(bookmark() and not bookmark(%s))",
318 325 mark, mark, mark)
319 326
320 327 def deleteobsmarkers(obsstore, indices):
321 328 """Delete some obsmarkers from obsstore and return how many were deleted
322 329
323 330 'indices' is a list of ints which are the indices
324 331 of the markers to be deleted.
325 332
326 333 Every invocation of this function completely rewrites the obsstore file,
327 334 skipping the markers we want to be removed. The new temporary file is
328 335 created, remaining markers are written there and on .close() this file
329 336 gets atomically renamed to obsstore, thus guaranteeing consistency."""
330 337 if not indices:
331 338 # we don't want to rewrite the obsstore with the same content
332 339 return
333 340
334 341 left = []
335 342 current = obsstore._all
336 343 n = 0
337 344 for i, m in enumerate(current):
338 345 if i in indices:
339 346 n += 1
340 347 continue
341 348 left.append(m)
342 349
343 350 newobsstorefile = obsstore.svfs('obsstore', 'w', atomictemp=True)
344 351 for bytes in obsolete.encodemarkers(left, True, obsstore._version):
345 352 newobsstorefile.write(bytes)
346 353 newobsstorefile.close()
347 354 return n
@@ -1,786 +1,795
1 1 #require killdaemons
2 2
3 3 $ cat << EOF >> $HGRCPATH
4 4 > [format]
5 5 > usegeneraldelta=yes
6 6 > [ui]
7 7 > ssh=python "$TESTDIR/dummyssh"
8 8 > EOF
9 9
10 10 Set up repo
11 11
12 12 $ hg --config experimental.treemanifest=True init repo
13 13 $ cd repo
14 14
15 15 Requirements get set on init
16 16
17 17 $ grep treemanifest .hg/requires
18 18 treemanifest
19 19
20 20 Without directories, looks like any other repo
21 21
22 22 $ echo 0 > a
23 23 $ echo 0 > b
24 24 $ hg ci -Aqm initial
25 25 $ hg debugdata -m 0
26 26 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
27 27 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
28 28
29 29 Submanifest is stored in separate revlog
30 30
31 31 $ mkdir dir1
32 32 $ echo 1 > dir1/a
33 33 $ echo 1 > dir1/b
34 34 $ echo 1 > e
35 35 $ hg ci -Aqm 'add dir1'
36 36 $ hg debugdata -m 1
37 37 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
38 38 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
39 39 dir1\x008b3ffd73f901e83304c83d33132c8e774ceac44et (esc)
40 40 e\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
41 41 $ hg debugdata --dir dir1 0
42 42 a\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
43 43 b\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
44 44
45 45 Can add nested directories
46 46
47 47 $ mkdir dir1/dir1
48 48 $ echo 2 > dir1/dir1/a
49 49 $ echo 2 > dir1/dir1/b
50 50 $ mkdir dir1/dir2
51 51 $ echo 2 > dir1/dir2/a
52 52 $ echo 2 > dir1/dir2/b
53 53 $ hg ci -Aqm 'add dir1/dir1'
54 54 $ hg files -r .
55 55 a
56 56 b
57 57 dir1/a (glob)
58 58 dir1/b (glob)
59 59 dir1/dir1/a (glob)
60 60 dir1/dir1/b (glob)
61 61 dir1/dir2/a (glob)
62 62 dir1/dir2/b (glob)
63 63 e
64 64
65 65 Revision is not created for unchanged directory
66 66
67 67 $ mkdir dir2
68 68 $ echo 3 > dir2/a
69 69 $ hg add dir2
70 70 adding dir2/a (glob)
71 71 $ hg debugindex --dir dir1 > before
72 72 $ hg ci -qm 'add dir2'
73 73 $ hg debugindex --dir dir1 > after
74 74 $ diff before after
75 75 $ rm before after
76 76
77 77 Removing directory does not create an revlog entry
78 78
79 79 $ hg rm dir1/dir1
80 80 removing dir1/dir1/a (glob)
81 81 removing dir1/dir1/b (glob)
82 82 $ hg debugindex --dir dir1/dir1 > before
83 83 $ hg ci -qm 'remove dir1/dir1'
84 84 $ hg debugindex --dir dir1/dir1 > after
85 85 $ diff before after
86 86 $ rm before after
87 87
88 88 Check that hg files (calls treemanifest.walk()) works
89 89 without loading all directory revlogs
90 90
91 91 $ hg co 'desc("add dir2")'
92 92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 93 $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup
94 94 $ hg files -r . dir1
95 95 dir1/a (glob)
96 96 dir1/b (glob)
97 97 dir1/dir1/a (glob)
98 98 dir1/dir1/b (glob)
99 99 dir1/dir2/a (glob)
100 100 dir1/dir2/b (glob)
101 101
102 102 Check that status between revisions works (calls treemanifest.matches())
103 103 without loading all directory revlogs
104 104
105 105 $ hg status --rev 'desc("add dir1")' --rev . dir1
106 106 A dir1/dir1/a
107 107 A dir1/dir1/b
108 108 A dir1/dir2/a
109 109 A dir1/dir2/b
110 110 $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2
111 111
112 112 Merge creates 2-parent revision of directory revlog
113 113
114 114 $ echo 5 > dir1/a
115 115 $ hg ci -Aqm 'modify dir1/a'
116 116 $ hg co '.^'
117 117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 118 $ echo 6 > dir1/b
119 119 $ hg ci -Aqm 'modify dir1/b'
120 120 $ hg merge 'desc("modify dir1/a")'
121 121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 122 (branch merge, don't forget to commit)
123 123 $ hg ci -m 'conflict-free merge involving dir1/'
124 124 $ cat dir1/a
125 125 5
126 126 $ cat dir1/b
127 127 6
128 128 $ hg debugindex --dir dir1
129 129 rev offset length delta linkrev nodeid p1 p2
130 130 0 0 54 -1 1 8b3ffd73f901 000000000000 000000000000
131 131 1 54 68 0 2 68e9d057c5a8 8b3ffd73f901 000000000000
132 132 2 122 12 1 4 4698198d2624 68e9d057c5a8 000000000000
133 133 3 134 55 1 5 44844058ccce 68e9d057c5a8 000000000000
134 134 4 189 55 1 6 bf3d9b744927 68e9d057c5a8 000000000000
135 135 5 244 55 4 7 dde7c0af2a03 bf3d9b744927 44844058ccce
136 136
137 137 Merge keeping directory from parent 1 does not create revlog entry. (Note that
138 138 dir1's manifest does change, but only because dir1/a's filelog changes.)
139 139
140 140 $ hg co 'desc("add dir2")'
141 141 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 142 $ echo 8 > dir2/a
143 143 $ hg ci -m 'modify dir2/a'
144 144 created new head
145 145
146 146 $ hg debugindex --dir dir2 > before
147 147 $ hg merge 'desc("modify dir1/a")'
148 148 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 149 (branch merge, don't forget to commit)
150 150 $ hg revert -r 'desc("modify dir2/a")' .
151 151 reverting dir1/a (glob)
152 152 $ hg ci -m 'merge, keeping parent 1'
153 153 $ hg debugindex --dir dir2 > after
154 154 $ diff before after
155 155 $ rm before after
156 156
157 157 Merge keeping directory from parent 2 does not create revlog entry. (Note that
158 158 dir2's manifest does change, but only because dir2/a's filelog changes.)
159 159
160 160 $ hg co 'desc("modify dir2/a")'
161 161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 162 $ hg debugindex --dir dir1 > before
163 163 $ hg merge 'desc("modify dir1/a")'
164 164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 165 (branch merge, don't forget to commit)
166 166 $ hg revert -r 'desc("modify dir1/a")' .
167 167 reverting dir2/a (glob)
168 168 $ hg ci -m 'merge, keeping parent 2'
169 169 created new head
170 170 $ hg debugindex --dir dir1 > after
171 171 $ diff before after
172 172 $ rm before after
173 173
174 174 Create flat source repo for tests with mixed flat/tree manifests
175 175
176 176 $ cd ..
177 177 $ hg init repo-flat
178 178 $ cd repo-flat
179 179
180 180 Create a few commits with flat manifest
181 181
182 182 $ echo 0 > a
183 183 $ echo 0 > b
184 184 $ echo 0 > e
185 185 $ for d in dir1 dir1/dir1 dir1/dir2 dir2
186 186 > do
187 187 > mkdir $d
188 188 > echo 0 > $d/a
189 189 > echo 0 > $d/b
190 190 > done
191 191 $ hg ci -Aqm initial
192 192
193 193 $ echo 1 > a
194 194 $ echo 1 > dir1/a
195 195 $ echo 1 > dir1/dir1/a
196 196 $ hg ci -Aqm 'modify on branch 1'
197 197
198 198 $ hg co 0
199 199 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 200 $ echo 2 > b
201 201 $ echo 2 > dir1/b
202 202 $ echo 2 > dir1/dir1/b
203 203 $ hg ci -Aqm 'modify on branch 2'
204 204
205 205 $ hg merge 1
206 206 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 207 (branch merge, don't forget to commit)
208 208 $ hg ci -m 'merge of flat manifests to new flat manifest'
209 209
210 210 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
211 211 $ cat hg.pid >> $DAEMON_PIDS
212 212
213 213 Create clone with tree manifests enabled
214 214
215 215 $ cd ..
216 216 $ hg clone --config experimental.treemanifest=1 \
217 217 > http://localhost:$HGPORT repo-mixed -r 1
218 218 adding changesets
219 219 adding manifests
220 220 adding file changes
221 221 added 2 changesets with 14 changes to 11 files
222 222 updating to branch default
223 223 11 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 224 $ cd repo-mixed
225 225 $ test -d .hg/store/meta
226 226 [1]
227 227 $ grep treemanifest .hg/requires
228 228 treemanifest
229 229
230 230 Should be possible to push updates from flat to tree manifest repo
231 231
232 232 $ hg -R ../repo-flat push ssh://user@dummy/repo-mixed
233 233 pushing to ssh://user@dummy/repo-mixed
234 234 searching for changes
235 235 remote: adding changesets
236 236 remote: adding manifests
237 237 remote: adding file changes
238 238 remote: added 2 changesets with 3 changes to 3 files
239 239
240 240 Commit should store revlog per directory
241 241
242 242 $ hg co 1
243 243 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 244 $ echo 3 > a
245 245 $ echo 3 > dir1/a
246 246 $ echo 3 > dir1/dir1/a
247 247 $ hg ci -m 'first tree'
248 248 created new head
249 249 $ find .hg/store/meta | sort
250 250 .hg/store/meta
251 251 .hg/store/meta/dir1
252 252 .hg/store/meta/dir1/00manifest.i
253 253 .hg/store/meta/dir1/dir1
254 254 .hg/store/meta/dir1/dir1/00manifest.i
255 255 .hg/store/meta/dir1/dir2
256 256 .hg/store/meta/dir1/dir2/00manifest.i
257 257 .hg/store/meta/dir2
258 258 .hg/store/meta/dir2/00manifest.i
259 259
260 260 Merge of two trees
261 261
262 262 $ hg co 2
263 263 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 264 $ hg merge 1
265 265 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 266 (branch merge, don't forget to commit)
267 267 $ hg ci -m 'merge of flat manifests to new tree manifest'
268 268 created new head
269 269 $ hg diff -r 3
270 270
271 271 Parent of tree root manifest should be flat manifest, and two for merge
272 272
273 273 $ hg debugindex -m
274 274 rev offset length delta linkrev nodeid p1 p2
275 275 0 0 80 -1 0 40536115ed9e 000000000000 000000000000
276 276 1 80 83 0 1 f3376063c255 40536115ed9e 000000000000
277 277 2 163 89 0 2 5d9b9da231a2 40536115ed9e 000000000000
278 278 3 252 83 2 3 d17d663cbd8a 5d9b9da231a2 f3376063c255
279 279 4 335 124 1 4 51e32a8c60ee f3376063c255 000000000000
280 280 5 459 126 2 5 cc5baa78b230 5d9b9da231a2 f3376063c255
281 281
282 282
283 283 Status across flat/tree boundary should work
284 284
285 285 $ hg status --rev '.^' --rev .
286 286 M a
287 287 M dir1/a
288 288 M dir1/dir1/a
289 289
290 290
291 291 Turning off treemanifest config has no effect
292 292
293 293 $ hg debugindex --dir dir1
294 294 rev offset length delta linkrev nodeid p1 p2
295 295 0 0 127 -1 4 064927a0648a 000000000000 000000000000
296 296 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
297 297 $ echo 2 > dir1/a
298 298 $ hg --config experimental.treemanifest=False ci -qm 'modify dir1/a'
299 299 $ hg debugindex --dir dir1
300 300 rev offset length delta linkrev nodeid p1 p2
301 301 0 0 127 -1 4 064927a0648a 000000000000 000000000000
302 302 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
303 303 2 238 55 1 6 5b16163a30c6 25ecb8cb8618 000000000000
304 304
305 305 Stripping and recovering changes should work
306 306
307 307 $ hg st --change tip
308 308 M dir1/a
309 309 $ hg --config extensions.strip= strip tip
310 310 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 311 saved backup bundle to $TESTTMP/repo-mixed/.hg/strip-backup/51cfd7b1e13b-78a2f3ed-backup.hg (glob)
312 $ hg debugindex --dir dir1
313 rev offset length delta linkrev nodeid p1 p2
314 0 0 127 -1 4 064927a0648a 000000000000 000000000000
315 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
312 316 $ hg unbundle -q .hg/strip-backup/*
317 $ hg debugindex --dir dir1
318 rev offset length delta linkrev nodeid p1 p2
319 0 0 127 -1 4 064927a0648a 000000000000 000000000000
320 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
321 2 238 55 1 6 5b16163a30c6 25ecb8cb8618 000000000000
313 322 $ hg st --change tip
314 323 M dir1/a
315 324
316 325 Shelving and unshelving should work
317 326
318 327 $ echo foo >> dir1/a
319 328 $ hg --config extensions.shelve= shelve
320 329 shelved as default
321 330 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 331 $ hg --config extensions.shelve= unshelve
323 332 unshelving change 'default'
324 333 $ hg diff --nodates
325 334 diff -r 708a273da119 dir1/a
326 335 --- a/dir1/a
327 336 +++ b/dir1/a
328 337 @@ -1,1 +1,2 @@
329 338 1
330 339 +foo
331 340
332 341 Pushing from treemanifest repo to an empty repo makes that a treemanifest repo
333 342
334 343 $ cd ..
335 344 $ hg init empty-repo
336 345 $ cat << EOF >> empty-repo/.hg/hgrc
337 346 > [experimental]
338 347 > changegroup3=yes
339 348 > EOF
340 349 $ grep treemanifest empty-repo/.hg/requires
341 350 [1]
342 351 $ hg push -R repo -r 0 empty-repo
343 352 pushing to empty-repo
344 353 searching for changes
345 354 adding changesets
346 355 adding manifests
347 356 adding file changes
348 357 added 1 changesets with 2 changes to 2 files
349 358 $ grep treemanifest empty-repo/.hg/requires
350 359 treemanifest
351 360
352 361 Pushing to an empty repo works
353 362
354 363 $ hg --config experimental.treemanifest=1 init clone
355 364 $ grep treemanifest clone/.hg/requires
356 365 treemanifest
357 366 $ hg push -R repo clone
358 367 pushing to clone
359 368 searching for changes
360 369 adding changesets
361 370 adding manifests
362 371 adding file changes
363 372 added 11 changesets with 15 changes to 10 files (+3 heads)
364 373 $ grep treemanifest clone/.hg/requires
365 374 treemanifest
366 375 $ hg -R clone verify
367 376 checking changesets
368 377 checking manifests
369 378 checking directory manifests
370 379 crosschecking files in changesets and manifests
371 380 checking files
372 381 10 files, 11 changesets, 15 total revisions
373 382
374 383 Create deeper repo with tree manifests.
375 384
376 385 $ hg --config experimental.treemanifest=True init deeprepo
377 386 $ cd deeprepo
378 387
379 388 $ mkdir .A
380 389 $ mkdir b
381 390 $ mkdir b/bar
382 391 $ mkdir b/bar/orange
383 392 $ mkdir b/bar/orange/fly
384 393 $ mkdir b/foo
385 394 $ mkdir b/foo/apple
386 395 $ mkdir b/foo/apple/bees
387 396
388 397 $ touch .A/one.txt
389 398 $ touch .A/two.txt
390 399 $ touch b/bar/fruits.txt
391 400 $ touch b/bar/orange/fly/gnat.py
392 401 $ touch b/bar/orange/fly/housefly.txt
393 402 $ touch b/foo/apple/bees/flower.py
394 403 $ touch c.txt
395 404 $ touch d.py
396 405
397 406 $ hg ci -Aqm 'initial'
398 407
399 408 We'll see that visitdir works by removing some treemanifest revlogs and running
400 409 the files command with various parameters.
401 410
402 411 Test files from the root.
403 412
404 413 $ hg files -r .
405 414 .A/one.txt (glob)
406 415 .A/two.txt (glob)
407 416 b/bar/fruits.txt (glob)
408 417 b/bar/orange/fly/gnat.py (glob)
409 418 b/bar/orange/fly/housefly.txt (glob)
410 419 b/foo/apple/bees/flower.py (glob)
411 420 c.txt
412 421 d.py
413 422
414 423 Excludes with a glob should not exclude everything from the glob's root
415 424
416 425 $ hg files -r . -X 'b/fo?' b
417 426 b/bar/fruits.txt (glob)
418 427 b/bar/orange/fly/gnat.py (glob)
419 428 b/bar/orange/fly/housefly.txt (glob)
420 429 $ cp -r .hg/store .hg/store-copy
421 430
422 431 Test files for a subdirectory.
423 432
424 433 $ rm -r .hg/store/meta/~2e_a
425 434 $ hg files -r . b
426 435 b/bar/fruits.txt (glob)
427 436 b/bar/orange/fly/gnat.py (glob)
428 437 b/bar/orange/fly/housefly.txt (glob)
429 438 b/foo/apple/bees/flower.py (glob)
430 439 $ cp -r .hg/store-copy/. .hg/store
431 440
432 441 Test files with just includes and excludes.
433 442
434 443 $ rm -r .hg/store/meta/~2e_a
435 444 $ rm -r .hg/store/meta/b/bar/orange/fly
436 445 $ rm -r .hg/store/meta/b/foo/apple/bees
437 446 $ hg files -r . -I path:b/bar -X path:b/bar/orange/fly -I path:b/foo -X path:b/foo/apple/bees
438 447 b/bar/fruits.txt (glob)
439 448 $ cp -r .hg/store-copy/. .hg/store
440 449
441 450 Test files for a subdirectory, excluding a directory within it.
442 451
443 452 $ rm -r .hg/store/meta/~2e_a
444 453 $ rm -r .hg/store/meta/b/foo
445 454 $ hg files -r . -X path:b/foo b
446 455 b/bar/fruits.txt (glob)
447 456 b/bar/orange/fly/gnat.py (glob)
448 457 b/bar/orange/fly/housefly.txt (glob)
449 458 $ cp -r .hg/store-copy/. .hg/store
450 459
451 460 Test files for a sub directory, including only a directory within it, and
452 461 including an unrelated directory.
453 462
454 463 $ rm -r .hg/store/meta/~2e_a
455 464 $ rm -r .hg/store/meta/b/foo
456 465 $ hg files -r . -I path:b/bar/orange -I path:a b
457 466 b/bar/orange/fly/gnat.py (glob)
458 467 b/bar/orange/fly/housefly.txt (glob)
459 468 $ cp -r .hg/store-copy/. .hg/store
460 469
461 470 Test files for a pattern, including a directory, and excluding a directory
462 471 within that.
463 472
464 473 $ rm -r .hg/store/meta/~2e_a
465 474 $ rm -r .hg/store/meta/b/foo
466 475 $ rm -r .hg/store/meta/b/bar/orange
467 476 $ hg files -r . glob:**.txt -I path:b/bar -X path:b/bar/orange
468 477 b/bar/fruits.txt (glob)
469 478 $ cp -r .hg/store-copy/. .hg/store
470 479
471 480 Add some more changes to the deep repo
472 481 $ echo narf >> b/bar/fruits.txt
473 482 $ hg ci -m narf
474 483 $ echo troz >> b/bar/orange/fly/gnat.py
475 484 $ hg ci -m troz
476 485
477 486 Verify works
478 487 $ hg verify
479 488 checking changesets
480 489 checking manifests
481 490 checking directory manifests
482 491 crosschecking files in changesets and manifests
483 492 checking files
484 493 8 files, 3 changesets, 10 total revisions
485 494
486 495 Dirlogs are included in fncache
487 496 $ grep meta/.A/00manifest.i .hg/store/fncache
488 497 meta/.A/00manifest.i
489 498
490 499 Rebuilt fncache includes dirlogs
491 500 $ rm .hg/store/fncache
492 501 $ hg debugrebuildfncache
493 502 adding data/.A/one.txt.i
494 503 adding data/.A/two.txt.i
495 504 adding data/b/bar/fruits.txt.i
496 505 adding data/b/bar/orange/fly/gnat.py.i
497 506 adding data/b/bar/orange/fly/housefly.txt.i
498 507 adding data/b/foo/apple/bees/flower.py.i
499 508 adding data/c.txt.i
500 509 adding data/d.py.i
501 510 adding meta/.A/00manifest.i
502 511 adding meta/b/00manifest.i
503 512 adding meta/b/bar/00manifest.i
504 513 adding meta/b/bar/orange/00manifest.i
505 514 adding meta/b/bar/orange/fly/00manifest.i
506 515 adding meta/b/foo/00manifest.i
507 516 adding meta/b/foo/apple/00manifest.i
508 517 adding meta/b/foo/apple/bees/00manifest.i
509 518 16 items added, 0 removed from fncache
510 519
511 520 Finish first server
512 521 $ killdaemons.py
513 522
514 523 Back up the recently added revlogs
515 524 $ cp -r .hg/store .hg/store-newcopy
516 525
517 526 Verify reports missing dirlog
518 527 $ rm .hg/store/meta/b/00manifest.*
519 528 $ hg verify
520 529 checking changesets
521 530 checking manifests
522 531 checking directory manifests
523 532 0: empty or missing b/
524 533 b/@0: parent-directory manifest refers to unknown revision 67688a370455
525 534 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
526 535 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
527 536 warning: orphan revlog 'meta/b/bar/00manifest.i'
528 537 warning: orphan revlog 'meta/b/bar/orange/00manifest.i'
529 538 warning: orphan revlog 'meta/b/bar/orange/fly/00manifest.i'
530 539 warning: orphan revlog 'meta/b/foo/00manifest.i'
531 540 warning: orphan revlog 'meta/b/foo/apple/00manifest.i'
532 541 warning: orphan revlog 'meta/b/foo/apple/bees/00manifest.i'
533 542 crosschecking files in changesets and manifests
534 543 b/bar/fruits.txt@0: in changeset but not in manifest
535 544 b/bar/orange/fly/gnat.py@0: in changeset but not in manifest
536 545 b/bar/orange/fly/housefly.txt@0: in changeset but not in manifest
537 546 b/foo/apple/bees/flower.py@0: in changeset but not in manifest
538 547 checking files
539 548 8 files, 3 changesets, 10 total revisions
540 549 6 warnings encountered!
541 550 8 integrity errors encountered!
542 551 (first damaged changeset appears to be 0)
543 552 [1]
544 553 $ cp -r .hg/store-newcopy/. .hg/store
545 554
546 555 Verify reports missing dirlog entry
547 556 $ mv -f .hg/store-copy/meta/b/00manifest.* .hg/store/meta/b/
548 557 $ hg verify
549 558 checking changesets
550 559 checking manifests
551 560 checking directory manifests
552 561 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
553 562 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
554 563 b/bar/@?: rev 1 points to unexpected changeset 1
555 564 b/bar/@?: 5e03c4ee5e4a not in parent-directory manifest
556 565 b/bar/@?: rev 2 points to unexpected changeset 2
557 566 b/bar/@?: 1b16940d66d6 not in parent-directory manifest
558 567 b/bar/orange/@?: rev 1 points to unexpected changeset 2
559 568 (expected None)
560 569 b/bar/orange/fly/@?: rev 1 points to unexpected changeset 2
561 570 (expected None)
562 571 crosschecking files in changesets and manifests
563 572 checking files
564 573 8 files, 3 changesets, 10 total revisions
565 574 2 warnings encountered!
566 575 8 integrity errors encountered!
567 576 (first damaged changeset appears to be 1)
568 577 [1]
569 578 $ cp -r .hg/store-newcopy/. .hg/store
570 579
571 580 Test cloning a treemanifest repo over http.
572 581 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
573 582 $ cat hg.pid >> $DAEMON_PIDS
574 583 $ cd ..
575 584 We can clone even with the knob turned off and we'll get a treemanifest repo.
576 585 $ hg clone --config experimental.treemanifest=False \
577 586 > --config experimental.changegroup3=True \
578 587 > http://localhost:$HGPORT deepclone
579 588 requesting all changes
580 589 adding changesets
581 590 adding manifests
582 591 adding file changes
583 592 added 3 changesets with 10 changes to 8 files
584 593 updating to branch default
585 594 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
586 595 No server errors.
587 596 $ cat deeprepo/errors.log
588 597 requires got updated to include treemanifest
589 598 $ cat deepclone/.hg/requires | grep treemanifest
590 599 treemanifest
591 600 Tree manifest revlogs exist.
592 601 $ find deepclone/.hg/store/meta | sort
593 602 deepclone/.hg/store/meta
594 603 deepclone/.hg/store/meta/b
595 604 deepclone/.hg/store/meta/b/00manifest.i
596 605 deepclone/.hg/store/meta/b/bar
597 606 deepclone/.hg/store/meta/b/bar/00manifest.i
598 607 deepclone/.hg/store/meta/b/bar/orange
599 608 deepclone/.hg/store/meta/b/bar/orange/00manifest.i
600 609 deepclone/.hg/store/meta/b/bar/orange/fly
601 610 deepclone/.hg/store/meta/b/bar/orange/fly/00manifest.i
602 611 deepclone/.hg/store/meta/b/foo
603 612 deepclone/.hg/store/meta/b/foo/00manifest.i
604 613 deepclone/.hg/store/meta/b/foo/apple
605 614 deepclone/.hg/store/meta/b/foo/apple/00manifest.i
606 615 deepclone/.hg/store/meta/b/foo/apple/bees
607 616 deepclone/.hg/store/meta/b/foo/apple/bees/00manifest.i
608 617 deepclone/.hg/store/meta/~2e_a
609 618 deepclone/.hg/store/meta/~2e_a/00manifest.i
610 619 Verify passes.
611 620 $ cd deepclone
612 621 $ hg verify
613 622 checking changesets
614 623 checking manifests
615 624 checking directory manifests
616 625 crosschecking files in changesets and manifests
617 626 checking files
618 627 8 files, 3 changesets, 10 total revisions
619 628 $ cd ..
620 629
621 630 Create clones using old repo formats to use in later tests
622 631 $ hg clone --config format.usestore=False \
623 632 > --config experimental.changegroup3=True \
624 633 > http://localhost:$HGPORT deeprepo-basicstore
625 634 requesting all changes
626 635 adding changesets
627 636 adding manifests
628 637 adding file changes
629 638 added 3 changesets with 10 changes to 8 files
630 639 updating to branch default
631 640 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
632 641 $ cd deeprepo-basicstore
633 642 $ grep store .hg/requires
634 643 [1]
635 644 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --errorlog=errors.log
636 645 $ cat hg.pid >> $DAEMON_PIDS
637 646 $ cd ..
638 647 $ hg clone --config format.usefncache=False \
639 648 > --config experimental.changegroup3=True \
640 649 > http://localhost:$HGPORT deeprepo-encodedstore
641 650 requesting all changes
642 651 adding changesets
643 652 adding manifests
644 653 adding file changes
645 654 added 3 changesets with 10 changes to 8 files
646 655 updating to branch default
647 656 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 657 $ cd deeprepo-encodedstore
649 658 $ grep fncache .hg/requires
650 659 [1]
651 660 $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --errorlog=errors.log
652 661 $ cat hg.pid >> $DAEMON_PIDS
653 662 $ cd ..
654 663
655 664 Local clone with basicstore
656 665 $ hg clone -U deeprepo-basicstore local-clone-basicstore
657 666 $ hg -R local-clone-basicstore verify
658 667 checking changesets
659 668 checking manifests
660 669 checking directory manifests
661 670 crosschecking files in changesets and manifests
662 671 checking files
663 672 8 files, 3 changesets, 10 total revisions
664 673
665 674 Local clone with encodedstore
666 675 $ hg clone -U deeprepo-encodedstore local-clone-encodedstore
667 676 $ hg -R local-clone-encodedstore verify
668 677 checking changesets
669 678 checking manifests
670 679 checking directory manifests
671 680 crosschecking files in changesets and manifests
672 681 checking files
673 682 8 files, 3 changesets, 10 total revisions
674 683
675 684 Local clone with fncachestore
676 685 $ hg clone -U deeprepo local-clone-fncachestore
677 686 $ hg -R local-clone-fncachestore verify
678 687 checking changesets
679 688 checking manifests
680 689 checking directory manifests
681 690 crosschecking files in changesets and manifests
682 691 checking files
683 692 8 files, 3 changesets, 10 total revisions
684 693
685 694 Stream clone with basicstore
686 695 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
687 696 > http://localhost:$HGPORT1 stream-clone-basicstore
688 697 streaming all changes
689 698 18 files to transfer, * of data (glob)
690 699 transferred * in * seconds (*) (glob)
691 700 searching for changes
692 701 no changes found
693 702 $ hg -R stream-clone-basicstore verify
694 703 checking changesets
695 704 checking manifests
696 705 checking directory manifests
697 706 crosschecking files in changesets and manifests
698 707 checking files
699 708 8 files, 3 changesets, 10 total revisions
700 709
701 710 Stream clone with encodedstore
702 711 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
703 712 > http://localhost:$HGPORT2 stream-clone-encodedstore
704 713 streaming all changes
705 714 18 files to transfer, * of data (glob)
706 715 transferred * in * seconds (*) (glob)
707 716 searching for changes
708 717 no changes found
709 718 $ hg -R stream-clone-encodedstore verify
710 719 checking changesets
711 720 checking manifests
712 721 checking directory manifests
713 722 crosschecking files in changesets and manifests
714 723 checking files
715 724 8 files, 3 changesets, 10 total revisions
716 725
717 726 Stream clone with fncachestore
718 727 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
719 728 > http://localhost:$HGPORT stream-clone-fncachestore
720 729 streaming all changes
721 730 18 files to transfer, * of data (glob)
722 731 transferred * in * seconds (*) (glob)
723 732 searching for changes
724 733 no changes found
725 734 $ hg -R stream-clone-fncachestore verify
726 735 checking changesets
727 736 checking manifests
728 737 checking directory manifests
729 738 crosschecking files in changesets and manifests
730 739 checking files
731 740 8 files, 3 changesets, 10 total revisions
732 741
733 742 Packed bundle
734 743 $ hg -R deeprepo debugcreatestreamclonebundle repo-packed.hg
735 744 writing 3349 bytes for 18 files
736 745 bundle requirements: generaldelta, revlogv1, treemanifest
737 746 $ hg debugbundle --spec repo-packed.hg
738 747 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Ctreemanifest
739 748
740 749 Bundle with changegroup2 is not supported
741 750
742 751 $ hg -R deeprepo bundle --all -t v2 deeprepo.bundle
743 752 abort: repository does not support bundle version 02
744 753 [255]
745 754
746 755 Pull does not include changegroup for manifest the client already has from
747 756 other branch
748 757
749 758 $ mkdir grafted-dir-repo
750 759 $ cd grafted-dir-repo
751 760 $ hg --config experimental.treemanifest=1 init
752 761 $ mkdir dir
753 762 $ echo a > dir/file
754 763 $ echo a > file
755 764 $ hg ci -Am initial
756 765 adding dir/file
757 766 adding file
758 767 $ echo b > dir/file
759 768 $ hg ci -m updated
760 769 $ hg co '.^'
761 770 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 771 $ hg revert -r tip dir/
763 772 reverting dir/file (glob)
764 773 $ echo b > file # to make sure root manifest is sent
765 774 $ hg ci -m grafted
766 775 created new head
767 776 $ cd ..
768 777
769 778 $ hg --config experimental.treemanifest=1 clone --pull -r 1 \
770 779 > grafted-dir-repo grafted-dir-repo-clone
771 780 adding changesets
772 781 adding manifests
773 782 adding file changes
774 783 added 2 changesets with 3 changes to 2 files
775 784 updating to branch default
776 785 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
777 786 $ cd grafted-dir-repo-clone
778 787 $ hg pull -r 2
779 788 pulling from $TESTTMP/grafted-dir-repo (glob)
780 789 searching for changes
781 790 adding changesets
782 791 adding manifests
783 792 adding file changes
784 793 added 1 changesets with 1 changes to 1 files (+1 heads)
785 794 (run 'hg heads' to see heads, 'hg merge' to merge)
786 795
General Comments 0
You need to be logged in to leave comments. Login now