##// END OF EJS Templates
branchmap: handle nullrev in setcachedata...
Durham Goode -
r31454:a5bad127 default
parent child Browse files
Show More
@@ -1,519 +1,521 b''
1 1 # branchmap.py - logic to computes, maintain and stores branchmap for local repo
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import struct
11 11
12 12 from .node import (
13 13 bin,
14 14 hex,
15 15 nullid,
16 16 nullrev,
17 17 )
18 18 from . import (
19 19 encoding,
20 20 error,
21 21 scmutil,
22 22 util,
23 23 )
24 24
25 25 calcsize = struct.calcsize
26 26 pack_into = struct.pack_into
27 27 unpack_from = struct.unpack_from
28 28
29 29 def _filename(repo):
30 30 """name of a branchcache file for a given repo or repoview"""
31 31 filename = "cache/branch2"
32 32 if repo.filtername:
33 33 filename = '%s-%s' % (filename, repo.filtername)
34 34 return filename
35 35
36 36 def read(repo):
37 37 try:
38 38 f = repo.vfs(_filename(repo))
39 39 lines = f.read().split('\n')
40 40 f.close()
41 41 except (IOError, OSError):
42 42 return None
43 43
44 44 try:
45 45 cachekey = lines.pop(0).split(" ", 2)
46 46 last, lrev = cachekey[:2]
47 47 last, lrev = bin(last), int(lrev)
48 48 filteredhash = None
49 49 if len(cachekey) > 2:
50 50 filteredhash = bin(cachekey[2])
51 51 partial = branchcache(tipnode=last, tiprev=lrev,
52 52 filteredhash=filteredhash)
53 53 if not partial.validfor(repo):
54 54 # invalidate the cache
55 55 raise ValueError('tip differs')
56 56 cl = repo.changelog
57 57 for l in lines:
58 58 if not l:
59 59 continue
60 60 node, state, label = l.split(" ", 2)
61 61 if state not in 'oc':
62 62 raise ValueError('invalid branch state')
63 63 label = encoding.tolocal(label.strip())
64 64 node = bin(node)
65 65 if not cl.hasnode(node):
66 66 raise ValueError('node %s does not exist' % hex(node))
67 67 partial.setdefault(label, []).append(node)
68 68 if state == 'c':
69 69 partial._closednodes.add(node)
70 70 except KeyboardInterrupt:
71 71 raise
72 72 except Exception as inst:
73 73 if repo.ui.debugflag:
74 74 msg = 'invalid branchheads cache'
75 75 if repo.filtername is not None:
76 76 msg += ' (%s)' % repo.filtername
77 77 msg += ': %s\n'
78 78 repo.ui.debug(msg % inst)
79 79 partial = None
80 80 return partial
81 81
82 82 ### Nearest subset relation
83 83 # Nearest subset of filter X is a filter Y so that:
84 84 # * Y is included in X,
85 85 # * X - Y is as small as possible.
86 86 # This create and ordering used for branchmap purpose.
87 87 # the ordering may be partial
88 88 subsettable = {None: 'visible',
89 89 'visible': 'served',
90 90 'served': 'immutable',
91 91 'immutable': 'base'}
92 92
93 93 def updatecache(repo):
94 94 cl = repo.changelog
95 95 filtername = repo.filtername
96 96 partial = repo._branchcaches.get(filtername)
97 97
98 98 revs = []
99 99 if partial is None or not partial.validfor(repo):
100 100 partial = read(repo)
101 101 if partial is None:
102 102 subsetname = subsettable.get(filtername)
103 103 if subsetname is None:
104 104 partial = branchcache()
105 105 else:
106 106 subset = repo.filtered(subsetname)
107 107 partial = subset.branchmap().copy()
108 108 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
109 109 revs.extend(r for r in extrarevs if r <= partial.tiprev)
110 110 revs.extend(cl.revs(start=partial.tiprev + 1))
111 111 if revs:
112 112 partial.update(repo, revs)
113 113 partial.write(repo)
114 114
115 115 assert partial.validfor(repo), filtername
116 116 repo._branchcaches[repo.filtername] = partial
117 117
118 118 def replacecache(repo, bm):
119 119 """Replace the branchmap cache for a repo with a branch mapping.
120 120
121 121 This is likely only called during clone with a branch map from a remote.
122 122 """
123 123 rbheads = []
124 124 closed = []
125 125 for bheads in bm.itervalues():
126 126 rbheads.extend(bheads)
127 127 for h in bheads:
128 128 r = repo.changelog.rev(h)
129 129 b, c = repo.changelog.branchinfo(r)
130 130 if c:
131 131 closed.append(h)
132 132
133 133 if rbheads:
134 134 rtiprev = max((int(repo.changelog.rev(node))
135 135 for node in rbheads))
136 136 cache = branchcache(bm,
137 137 repo[rtiprev].node(),
138 138 rtiprev,
139 139 closednodes=closed)
140 140
141 141 # Try to stick it as low as possible
142 142 # filter above served are unlikely to be fetch from a clone
143 143 for candidate in ('base', 'immutable', 'served'):
144 144 rview = repo.filtered(candidate)
145 145 if cache.validfor(rview):
146 146 repo._branchcaches[candidate] = cache
147 147 cache.write(rview)
148 148 break
149 149
150 150 class branchcache(dict):
151 151 """A dict like object that hold branches heads cache.
152 152
153 153 This cache is used to avoid costly computations to determine all the
154 154 branch heads of a repo.
155 155
156 156 The cache is serialized on disk in the following format:
157 157
158 158 <tip hex node> <tip rev number> [optional filtered repo hex hash]
159 159 <branch head hex node> <open/closed state> <branch name>
160 160 <branch head hex node> <open/closed state> <branch name>
161 161 ...
162 162
163 163 The first line is used to check if the cache is still valid. If the
164 164 branch cache is for a filtered repo view, an optional third hash is
165 165 included that hashes the hashes of all filtered revisions.
166 166
167 167 The open/closed state is represented by a single letter 'o' or 'c'.
168 168 This field can be used to avoid changelog reads when determining if a
169 169 branch head closes a branch or not.
170 170 """
171 171
172 172 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
173 173 filteredhash=None, closednodes=None):
174 174 super(branchcache, self).__init__(entries)
175 175 self.tipnode = tipnode
176 176 self.tiprev = tiprev
177 177 self.filteredhash = filteredhash
178 178 # closednodes is a set of nodes that close their branch. If the branch
179 179 # cache has been updated, it may contain nodes that are no longer
180 180 # heads.
181 181 if closednodes is None:
182 182 self._closednodes = set()
183 183 else:
184 184 self._closednodes = closednodes
185 185
186 186 def validfor(self, repo):
187 187 """Is the cache content valid regarding a repo
188 188
189 189 - False when cached tipnode is unknown or if we detect a strip.
190 190 - True when cache is up to date or a subset of current repo."""
191 191 try:
192 192 return ((self.tipnode == repo.changelog.node(self.tiprev))
193 193 and (self.filteredhash == \
194 194 scmutil.filteredhash(repo, self.tiprev)))
195 195 except IndexError:
196 196 return False
197 197
198 198 def _branchtip(self, heads):
199 199 '''Return tuple with last open head in heads and false,
200 200 otherwise return last closed head and true.'''
201 201 tip = heads[-1]
202 202 closed = True
203 203 for h in reversed(heads):
204 204 if h not in self._closednodes:
205 205 tip = h
206 206 closed = False
207 207 break
208 208 return tip, closed
209 209
210 210 def branchtip(self, branch):
211 211 '''Return the tipmost open head on branch head, otherwise return the
212 212 tipmost closed head on branch.
213 213 Raise KeyError for unknown branch.'''
214 214 return self._branchtip(self[branch])[0]
215 215
216 216 def branchheads(self, branch, closed=False):
217 217 heads = self[branch]
218 218 if not closed:
219 219 heads = [h for h in heads if h not in self._closednodes]
220 220 return heads
221 221
222 222 def iterbranches(self):
223 223 for bn, heads in self.iteritems():
224 224 yield (bn, heads) + self._branchtip(heads)
225 225
226 226 def copy(self):
227 227 """return an deep copy of the branchcache object"""
228 228 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
229 229 self._closednodes)
230 230
231 231 def write(self, repo):
232 232 try:
233 233 f = repo.vfs(_filename(repo), "w", atomictemp=True)
234 234 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
235 235 if self.filteredhash is not None:
236 236 cachekey.append(hex(self.filteredhash))
237 237 f.write(" ".join(cachekey) + '\n')
238 238 nodecount = 0
239 239 for label, nodes in sorted(self.iteritems()):
240 240 for node in nodes:
241 241 nodecount += 1
242 242 if node in self._closednodes:
243 243 state = 'c'
244 244 else:
245 245 state = 'o'
246 246 f.write("%s %s %s\n" % (hex(node), state,
247 247 encoding.fromlocal(label)))
248 248 f.close()
249 249 repo.ui.log('branchcache',
250 250 'wrote %s branch cache with %d labels and %d nodes\n',
251 251 repo.filtername, len(self), nodecount)
252 252 except (IOError, OSError, error.Abort) as inst:
253 253 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
254 254 # Abort may be raise by read only opener
255 255 pass
256 256
257 257 def update(self, repo, revgen):
258 258 """Given a branchhead cache, self, that may have extra nodes or be
259 259 missing heads, and a generator of nodes that are strictly a superset of
260 260 heads missing, this function updates self to be correct.
261 261 """
262 262 starttime = util.timer()
263 263 cl = repo.changelog
264 264 # collect new branch entries
265 265 newbranches = {}
266 266 getbranchinfo = repo.revbranchcache().branchinfo
267 267 for r in revgen:
268 268 branch, closesbranch = getbranchinfo(r)
269 269 newbranches.setdefault(branch, []).append(r)
270 270 if closesbranch:
271 271 self._closednodes.add(cl.node(r))
272 272
273 273 # fetch current topological heads to speed up filtering
274 274 topoheads = set(cl.headrevs())
275 275
276 276 # if older branchheads are reachable from new ones, they aren't
277 277 # really branchheads. Note checking parents is insufficient:
278 278 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
279 279 for branch, newheadrevs in newbranches.iteritems():
280 280 bheads = self.setdefault(branch, [])
281 281 bheadset = set(cl.rev(node) for node in bheads)
282 282
283 283 # This have been tested True on all internal usage of this function.
284 284 # run it again in case of doubt
285 285 # assert not (set(bheadrevs) & set(newheadrevs))
286 286 newheadrevs.sort()
287 287 bheadset.update(newheadrevs)
288 288
289 289 # This prunes out two kinds of heads - heads that are superseded by
290 290 # a head in newheadrevs, and newheadrevs that are not heads because
291 291 # an existing head is their descendant.
292 292 uncertain = bheadset - topoheads
293 293 if uncertain:
294 294 floorrev = min(uncertain)
295 295 ancestors = set(cl.ancestors(newheadrevs, floorrev))
296 296 bheadset -= ancestors
297 297 bheadrevs = sorted(bheadset)
298 298 self[branch] = [cl.node(rev) for rev in bheadrevs]
299 299 tiprev = bheadrevs[-1]
300 300 if tiprev > self.tiprev:
301 301 self.tipnode = cl.node(tiprev)
302 302 self.tiprev = tiprev
303 303
304 304 if not self.validfor(repo):
305 305 # cache key are not valid anymore
306 306 self.tipnode = nullid
307 307 self.tiprev = nullrev
308 308 for heads in self.values():
309 309 tiprev = max(cl.rev(node) for node in heads)
310 310 if tiprev > self.tiprev:
311 311 self.tipnode = cl.node(tiprev)
312 312 self.tiprev = tiprev
313 313 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
314 314
315 315 duration = util.timer() - starttime
316 316 repo.ui.log('branchcache', 'updated %s branch cache in %.4f seconds\n',
317 317 repo.filtername, duration)
318 318
319 319 # Revision branch info cache
320 320
321 321 _rbcversion = '-v1'
322 322 _rbcnames = 'cache/rbc-names' + _rbcversion
323 323 _rbcrevs = 'cache/rbc-revs' + _rbcversion
324 324 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
325 325 _rbcrecfmt = '>4sI'
326 326 _rbcrecsize = calcsize(_rbcrecfmt)
327 327 _rbcnodelen = 4
328 328 _rbcbranchidxmask = 0x7fffffff
329 329 _rbccloseflag = 0x80000000
330 330
331 331 class revbranchcache(object):
332 332 """Persistent cache, mapping from revision number to branch name and close.
333 333 This is a low level cache, independent of filtering.
334 334
335 335 Branch names are stored in rbc-names in internal encoding separated by 0.
336 336 rbc-names is append-only, and each branch name is only stored once and will
337 337 thus have a unique index.
338 338
339 339 The branch info for each revision is stored in rbc-revs as constant size
340 340 records. The whole file is read into memory, but it is only 'parsed' on
341 341 demand. The file is usually append-only but will be truncated if repo
342 342 modification is detected.
343 343 The record for each revision contains the first 4 bytes of the
344 344 corresponding node hash, and the record is only used if it still matches.
345 345 Even a completely trashed rbc-revs fill thus still give the right result
346 346 while converging towards full recovery ... assuming no incorrectly matching
347 347 node hashes.
348 348 The record also contains 4 bytes where 31 bits contains the index of the
349 349 branch and the last bit indicate that it is a branch close commit.
350 350 The usage pattern for rbc-revs is thus somewhat similar to 00changelog.i
351 351 and will grow with it but be 1/8th of its size.
352 352 """
353 353
354 354 def __init__(self, repo, readonly=True):
355 355 assert repo.filtername is None
356 356 self._repo = repo
357 357 self._names = [] # branch names in local encoding with static index
358 358 self._rbcrevs = bytearray()
359 359 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
360 360 try:
361 361 bndata = repo.vfs.read(_rbcnames)
362 362 self._rbcsnameslen = len(bndata) # for verification before writing
363 363 if bndata:
364 364 self._names = [encoding.tolocal(bn)
365 365 for bn in bndata.split('\0')]
366 366 except (IOError, OSError):
367 367 if readonly:
368 368 # don't try to use cache - fall back to the slow path
369 369 self.branchinfo = self._branchinfo
370 370
371 371 if self._names:
372 372 try:
373 373 data = repo.vfs.read(_rbcrevs)
374 374 self._rbcrevs[:] = data
375 375 except (IOError, OSError) as inst:
376 376 repo.ui.debug("couldn't read revision branch cache: %s\n" %
377 377 inst)
378 378 # remember number of good records on disk
379 379 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
380 380 len(repo.changelog))
381 381 if self._rbcrevslen == 0:
382 382 self._names = []
383 383 self._rbcnamescount = len(self._names) # number of names read at
384 384 # _rbcsnameslen
385 385 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
386 386
387 387 def _clear(self):
388 388 self._rbcsnameslen = 0
389 389 del self._names[:]
390 390 self._rbcnamescount = 0
391 391 self._namesreverse.clear()
392 392 self._rbcrevslen = len(self._repo.changelog)
393 393 self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
394 394
395 395 def branchinfo(self, rev):
396 396 """Return branch name and close flag for rev, using and updating
397 397 persistent cache."""
398 398 changelog = self._repo.changelog
399 399 rbcrevidx = rev * _rbcrecsize
400 400
401 401 # avoid negative index, changelog.read(nullrev) is fast without cache
402 402 if rev == nullrev:
403 403 return changelog.branchinfo(rev)
404 404
405 405 # if requested rev isn't allocated, grow and cache the rev info
406 406 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
407 407 return self._branchinfo(rev)
408 408
409 409 # fast path: extract data from cache, use it if node is matching
410 410 reponode = changelog.node(rev)[:_rbcnodelen]
411 411 cachenode, branchidx = unpack_from(
412 412 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx)
413 413 close = bool(branchidx & _rbccloseflag)
414 414 if close:
415 415 branchidx &= _rbcbranchidxmask
416 416 if cachenode == '\0\0\0\0':
417 417 pass
418 418 elif cachenode == reponode:
419 419 try:
420 420 return self._names[branchidx], close
421 421 except IndexError:
422 422 # recover from invalid reference to unknown branch
423 423 self._repo.ui.debug("referenced branch names not found"
424 424 " - rebuilding revision branch cache from scratch\n")
425 425 self._clear()
426 426 else:
427 427 # rev/node map has changed, invalidate the cache from here up
428 428 self._repo.ui.debug("history modification detected - truncating "
429 429 "revision branch cache to revision %s\n" % rev)
430 430 truncate = rbcrevidx + _rbcrecsize
431 431 del self._rbcrevs[truncate:]
432 432 self._rbcrevslen = min(self._rbcrevslen, truncate)
433 433
434 434 # fall back to slow path and make sure it will be written to disk
435 435 return self._branchinfo(rev)
436 436
437 437 def _branchinfo(self, rev):
438 438 """Retrieve branch info from changelog and update _rbcrevs"""
439 439 changelog = self._repo.changelog
440 440 b, close = changelog.branchinfo(rev)
441 441 if b in self._namesreverse:
442 442 branchidx = self._namesreverse[b]
443 443 else:
444 444 branchidx = len(self._names)
445 445 self._names.append(b)
446 446 self._namesreverse[b] = branchidx
447 447 reponode = changelog.node(rev)
448 448 if close:
449 449 branchidx |= _rbccloseflag
450 450 self._setcachedata(rev, reponode, branchidx)
451 451 return b, close
452 452
453 453 def _setcachedata(self, rev, node, branchidx):
454 454 """Writes the node's branch data to the in-memory cache data."""
455 if rev == nullrev:
456 return
455 457 rbcrevidx = rev * _rbcrecsize
456 458 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
457 459 self._rbcrevs.extend('\0' *
458 460 (len(self._repo.changelog) * _rbcrecsize -
459 461 len(self._rbcrevs)))
460 462 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
461 463 self._rbcrevslen = min(self._rbcrevslen, rev)
462 464
463 465 tr = self._repo.currenttransaction()
464 466 if tr:
465 467 tr.addfinalize('write-revbranchcache', self.write)
466 468
467 469 def write(self, tr=None):
468 470 """Save branch cache if it is dirty."""
469 471 repo = self._repo
470 472 wlock = None
471 473 step = ''
472 474 try:
473 475 if self._rbcnamescount < len(self._names):
474 476 step = ' names'
475 477 wlock = repo.wlock(wait=False)
476 478 if self._rbcnamescount != 0:
477 479 f = repo.vfs.open(_rbcnames, 'ab')
478 480 if f.tell() == self._rbcsnameslen:
479 481 f.write('\0')
480 482 else:
481 483 f.close()
482 484 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames)
483 485 self._rbcnamescount = 0
484 486 self._rbcrevslen = 0
485 487 if self._rbcnamescount == 0:
486 488 # before rewriting names, make sure references are removed
487 489 repo.vfs.unlinkpath(_rbcrevs, ignoremissing=True)
488 490 f = repo.vfs.open(_rbcnames, 'wb')
489 491 f.write('\0'.join(encoding.fromlocal(b)
490 492 for b in self._names[self._rbcnamescount:]))
491 493 self._rbcsnameslen = f.tell()
492 494 f.close()
493 495 self._rbcnamescount = len(self._names)
494 496
495 497 start = self._rbcrevslen * _rbcrecsize
496 498 if start != len(self._rbcrevs):
497 499 step = ''
498 500 if wlock is None:
499 501 wlock = repo.wlock(wait=False)
500 502 revs = min(len(repo.changelog),
501 503 len(self._rbcrevs) // _rbcrecsize)
502 504 f = repo.vfs.open(_rbcrevs, 'ab')
503 505 if f.tell() != start:
504 506 repo.ui.debug("truncating %s to %s\n" % (_rbcrevs, start))
505 507 f.seek(start)
506 508 if f.tell() != start:
507 509 start = 0
508 510 f.seek(start)
509 511 f.truncate()
510 512 end = revs * _rbcrecsize
511 513 f.write(self._rbcrevs[start:end])
512 514 f.close()
513 515 self._rbcrevslen = revs
514 516 except (IOError, OSError, error.Abort, error.LockError) as inst:
515 517 repo.ui.debug("couldn't write revision branch cache%s: %s\n"
516 518 % (step, inst))
517 519 finally:
518 520 if wlock is not None:
519 521 wlock.release()
@@ -1,722 +1,727 b''
1 1 $ hg init a
2 2 $ cd a
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
7 Basic test
3 8 $ echo 'root' >root
4 9 $ hg add root
5 10 $ hg commit -d '0 0' -m "Adding root node"
6 11
7 12 $ echo 'a' >a
8 13 $ hg add a
9 14 $ hg branch a
10 15 marked working directory as branch a
11 16 (branches are permanent and global, did you want a bookmark?)
12 17 $ hg commit -d '1 0' -m "Adding a branch"
13 18
14 19 $ hg branch q
15 20 marked working directory as branch q
16 21 $ echo 'aa' >a
17 22 $ hg branch -C
18 23 reset working directory to branch a
19 24 $ hg commit -d '2 0' -m "Adding to a branch"
20 25
21 26 $ hg update -C 0
22 27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23 28 $ echo 'b' >b
24 29 $ hg add b
25 30 $ hg branch b
26 31 marked working directory as branch b
27 32 $ hg commit -d '2 0' -m "Adding b branch"
28 33
29 34 $ echo 'bh1' >bh1
30 35 $ hg add bh1
31 36 $ hg commit -d '3 0' -m "Adding b branch head 1"
32 37
33 38 $ hg update -C 2
34 39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 40 $ echo 'bh2' >bh2
36 41 $ hg add bh2
37 42 $ hg commit -d '4 0' -m "Adding b branch head 2"
38 43
39 44 $ echo 'c' >c
40 45 $ hg add c
41 46 $ hg branch c
42 47 marked working directory as branch c
43 48 $ hg commit -d '5 0' -m "Adding c branch"
44 49
45 50 reserved names
46 51
47 52 $ hg branch tip
48 53 abort: the name 'tip' is reserved
49 54 [255]
50 55 $ hg branch null
51 56 abort: the name 'null' is reserved
52 57 [255]
53 58 $ hg branch .
54 59 abort: the name '.' is reserved
55 60 [255]
56 61
57 62 invalid characters
58 63
59 64 $ hg branch 'foo:bar'
60 65 abort: ':' cannot be used in a name
61 66 [255]
62 67
63 68 $ hg branch 'foo
64 69 > bar'
65 70 abort: '\n' cannot be used in a name
66 71 [255]
67 72
68 73 trailing or leading spaces should be stripped before testing duplicates
69 74
70 75 $ hg branch 'b '
71 76 abort: a branch of the same name already exists
72 77 (use 'hg update' to switch to it)
73 78 [255]
74 79
75 80 $ hg branch ' b'
76 81 abort: a branch of the same name already exists
77 82 (use 'hg update' to switch to it)
78 83 [255]
79 84
80 85 verify update will accept invalid legacy branch names
81 86
82 87 $ hg init test-invalid-branch-name
83 88 $ cd test-invalid-branch-name
84 89 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
85 90 pulling from *test-invalid-branch-name.hg (glob)
86 91 requesting all changes
87 92 adding changesets
88 93 adding manifests
89 94 adding file changes
90 95 added 3 changesets with 3 changes to 2 files
91 96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 97
93 98 $ hg update '"colon:test"'
94 99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 100 $ cd ..
96 101
97 102 $ echo 'd' >d
98 103 $ hg add d
99 104 $ hg branch 'a branch name much longer than the default justification used by branches'
100 105 marked working directory as branch a branch name much longer than the default justification used by branches
101 106 $ hg commit -d '6 0' -m "Adding d branch"
102 107
103 108 $ hg branches
104 109 a branch name much longer than the default justification used by branches 7:10ff5895aa57
105 110 b 4:aee39cd168d0
106 111 c 6:589736a22561 (inactive)
107 112 a 5:d8cbc61dbaa6 (inactive)
108 113 default 0:19709c5a4e75 (inactive)
109 114
110 115 -------
111 116
112 117 $ hg branches -a
113 118 a branch name much longer than the default justification used by branches 7:10ff5895aa57
114 119 b 4:aee39cd168d0
115 120
116 121 --- Branch a
117 122
118 123 $ hg log -b a
119 124 changeset: 5:d8cbc61dbaa6
120 125 branch: a
121 126 parent: 2:881fe2b92ad0
122 127 user: test
123 128 date: Thu Jan 01 00:00:04 1970 +0000
124 129 summary: Adding b branch head 2
125 130
126 131 changeset: 2:881fe2b92ad0
127 132 branch: a
128 133 user: test
129 134 date: Thu Jan 01 00:00:02 1970 +0000
130 135 summary: Adding to a branch
131 136
132 137 changeset: 1:dd6b440dd85a
133 138 branch: a
134 139 user: test
135 140 date: Thu Jan 01 00:00:01 1970 +0000
136 141 summary: Adding a branch
137 142
138 143
139 144 ---- Branch b
140 145
141 146 $ hg log -b b
142 147 changeset: 4:aee39cd168d0
143 148 branch: b
144 149 user: test
145 150 date: Thu Jan 01 00:00:03 1970 +0000
146 151 summary: Adding b branch head 1
147 152
148 153 changeset: 3:ac22033332d1
149 154 branch: b
150 155 parent: 0:19709c5a4e75
151 156 user: test
152 157 date: Thu Jan 01 00:00:02 1970 +0000
153 158 summary: Adding b branch
154 159
155 160
156 161 ---- going to test branch closing
157 162
158 163 $ hg branches
159 164 a branch name much longer than the default justification used by branches 7:10ff5895aa57
160 165 b 4:aee39cd168d0
161 166 c 6:589736a22561 (inactive)
162 167 a 5:d8cbc61dbaa6 (inactive)
163 168 default 0:19709c5a4e75 (inactive)
164 169 $ hg up -C b
165 170 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
166 171 $ echo 'xxx1' >> b
167 172 $ hg commit -d '7 0' -m 'adding cset to branch b'
168 173 $ hg up -C aee39cd168d0
169 174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 175 $ echo 'xxx2' >> b
171 176 $ hg commit -d '8 0' -m 'adding head to branch b'
172 177 created new head
173 178 $ echo 'xxx3' >> b
174 179 $ hg commit -d '9 0' -m 'adding another cset to branch b'
175 180 $ hg branches
176 181 b 10:bfbe841b666e
177 182 a branch name much longer than the default justification used by branches 7:10ff5895aa57
178 183 c 6:589736a22561 (inactive)
179 184 a 5:d8cbc61dbaa6 (inactive)
180 185 default 0:19709c5a4e75 (inactive)
181 186 $ hg heads --closed
182 187 changeset: 10:bfbe841b666e
183 188 branch: b
184 189 tag: tip
185 190 user: test
186 191 date: Thu Jan 01 00:00:09 1970 +0000
187 192 summary: adding another cset to branch b
188 193
189 194 changeset: 8:eebb944467c9
190 195 branch: b
191 196 parent: 4:aee39cd168d0
192 197 user: test
193 198 date: Thu Jan 01 00:00:07 1970 +0000
194 199 summary: adding cset to branch b
195 200
196 201 changeset: 7:10ff5895aa57
197 202 branch: a branch name much longer than the default justification used by branches
198 203 user: test
199 204 date: Thu Jan 01 00:00:06 1970 +0000
200 205 summary: Adding d branch
201 206
202 207 changeset: 6:589736a22561
203 208 branch: c
204 209 user: test
205 210 date: Thu Jan 01 00:00:05 1970 +0000
206 211 summary: Adding c branch
207 212
208 213 changeset: 5:d8cbc61dbaa6
209 214 branch: a
210 215 parent: 2:881fe2b92ad0
211 216 user: test
212 217 date: Thu Jan 01 00:00:04 1970 +0000
213 218 summary: Adding b branch head 2
214 219
215 220 changeset: 0:19709c5a4e75
216 221 user: test
217 222 date: Thu Jan 01 00:00:00 1970 +0000
218 223 summary: Adding root node
219 224
220 225 $ hg heads
221 226 changeset: 10:bfbe841b666e
222 227 branch: b
223 228 tag: tip
224 229 user: test
225 230 date: Thu Jan 01 00:00:09 1970 +0000
226 231 summary: adding another cset to branch b
227 232
228 233 changeset: 8:eebb944467c9
229 234 branch: b
230 235 parent: 4:aee39cd168d0
231 236 user: test
232 237 date: Thu Jan 01 00:00:07 1970 +0000
233 238 summary: adding cset to branch b
234 239
235 240 changeset: 7:10ff5895aa57
236 241 branch: a branch name much longer than the default justification used by branches
237 242 user: test
238 243 date: Thu Jan 01 00:00:06 1970 +0000
239 244 summary: Adding d branch
240 245
241 246 changeset: 6:589736a22561
242 247 branch: c
243 248 user: test
244 249 date: Thu Jan 01 00:00:05 1970 +0000
245 250 summary: Adding c branch
246 251
247 252 changeset: 5:d8cbc61dbaa6
248 253 branch: a
249 254 parent: 2:881fe2b92ad0
250 255 user: test
251 256 date: Thu Jan 01 00:00:04 1970 +0000
252 257 summary: Adding b branch head 2
253 258
254 259 changeset: 0:19709c5a4e75
255 260 user: test
256 261 date: Thu Jan 01 00:00:00 1970 +0000
257 262 summary: Adding root node
258 263
259 264 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
260 265 $ hg branches -a
261 266 b 8:eebb944467c9
262 267 a branch name much longer than the default justification used by branches 7:10ff5895aa57
263 268 $ hg up -C b
264 269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 270 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
266 271 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
267 272 abort: can only close branch heads
268 273 [255]
269 274
270 275 $ hg log -r tip --debug
271 276 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
272 277 branch: b
273 278 tag: tip
274 279 phase: draft
275 280 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
276 281 parent: -1:0000000000000000000000000000000000000000
277 282 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
278 283 user: test
279 284 date: Thu Jan 01 00:00:09 1970 +0000
280 285 extra: branch=b
281 286 extra: close=1
282 287 description:
283 288 close this part branch too
284 289
285 290
286 291 --- b branch should be inactive
287 292
288 293 $ hg branches
289 294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
290 295 c 6:589736a22561 (inactive)
291 296 a 5:d8cbc61dbaa6 (inactive)
292 297 default 0:19709c5a4e75 (inactive)
293 298 $ hg branches -c
294 299 a branch name much longer than the default justification used by branches 7:10ff5895aa57
295 300 b 12:e3d49c0575d8 (closed)
296 301 c 6:589736a22561 (inactive)
297 302 a 5:d8cbc61dbaa6 (inactive)
298 303 default 0:19709c5a4e75 (inactive)
299 304 $ hg branches -a
300 305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
301 306 $ hg branches -q
302 307 a branch name much longer than the default justification used by branches
303 308 c
304 309 a
305 310 default
306 311 $ hg heads b
307 312 no open branch heads found on branches b
308 313 [1]
309 314 $ hg heads --closed b
310 315 changeset: 12:e3d49c0575d8
311 316 branch: b
312 317 tag: tip
313 318 parent: 8:eebb944467c9
314 319 user: test
315 320 date: Thu Jan 01 00:00:09 1970 +0000
316 321 summary: close this part branch too
317 322
318 323 changeset: 11:d3f163457ebf
319 324 branch: b
320 325 user: test
321 326 date: Thu Jan 01 00:00:09 1970 +0000
322 327 summary: prune bad branch
323 328
324 329 $ echo 'xxx4' >> b
325 330 $ hg commit -d '9 0' -m 'reopen branch with a change'
326 331 reopening closed branch head 12
327 332
328 333 --- branch b is back in action
329 334
330 335 $ hg branches -a
331 336 b 13:e23b5505d1ad
332 337 a branch name much longer than the default justification used by branches 7:10ff5895aa57
333 338
334 339 ---- test heads listings
335 340
336 341 $ hg heads
337 342 changeset: 13:e23b5505d1ad
338 343 branch: b
339 344 tag: tip
340 345 user: test
341 346 date: Thu Jan 01 00:00:09 1970 +0000
342 347 summary: reopen branch with a change
343 348
344 349 changeset: 7:10ff5895aa57
345 350 branch: a branch name much longer than the default justification used by branches
346 351 user: test
347 352 date: Thu Jan 01 00:00:06 1970 +0000
348 353 summary: Adding d branch
349 354
350 355 changeset: 6:589736a22561
351 356 branch: c
352 357 user: test
353 358 date: Thu Jan 01 00:00:05 1970 +0000
354 359 summary: Adding c branch
355 360
356 361 changeset: 5:d8cbc61dbaa6
357 362 branch: a
358 363 parent: 2:881fe2b92ad0
359 364 user: test
360 365 date: Thu Jan 01 00:00:04 1970 +0000
361 366 summary: Adding b branch head 2
362 367
363 368 changeset: 0:19709c5a4e75
364 369 user: test
365 370 date: Thu Jan 01 00:00:00 1970 +0000
366 371 summary: Adding root node
367 372
368 373
369 374 branch default
370 375
371 376 $ hg heads default
372 377 changeset: 0:19709c5a4e75
373 378 user: test
374 379 date: Thu Jan 01 00:00:00 1970 +0000
375 380 summary: Adding root node
376 381
377 382
378 383 branch a
379 384
380 385 $ hg heads a
381 386 changeset: 5:d8cbc61dbaa6
382 387 branch: a
383 388 parent: 2:881fe2b92ad0
384 389 user: test
385 390 date: Thu Jan 01 00:00:04 1970 +0000
386 391 summary: Adding b branch head 2
387 392
388 393 $ hg heads --active a
389 394 no open branch heads found on branches a
390 395 [1]
391 396
392 397 branch b
393 398
394 399 $ hg heads b
395 400 changeset: 13:e23b5505d1ad
396 401 branch: b
397 402 tag: tip
398 403 user: test
399 404 date: Thu Jan 01 00:00:09 1970 +0000
400 405 summary: reopen branch with a change
401 406
402 407 $ hg heads --closed b
403 408 changeset: 13:e23b5505d1ad
404 409 branch: b
405 410 tag: tip
406 411 user: test
407 412 date: Thu Jan 01 00:00:09 1970 +0000
408 413 summary: reopen branch with a change
409 414
410 415 changeset: 11:d3f163457ebf
411 416 branch: b
412 417 user: test
413 418 date: Thu Jan 01 00:00:09 1970 +0000
414 419 summary: prune bad branch
415 420
416 421 default branch colors:
417 422
418 423 $ cat <<EOF >> $HGRCPATH
419 424 > [extensions]
420 425 > color =
421 426 > [color]
422 427 > mode = ansi
423 428 > EOF
424 429
425 430 $ hg up -C c
426 431 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
427 432 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
428 433 $ hg up -C b
429 434 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
430 435 $ hg branches --color=always
431 436 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
432 437 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
433 438 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
434 439 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
435 440
436 441 default closed branch color:
437 442
438 443 $ hg branches --color=always --closed
439 444 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
440 445 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
441 446 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
442 447 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
443 448 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
444 449
445 450 $ cat <<EOF >> $HGRCPATH
446 451 > [extensions]
447 452 > color =
448 453 > [color]
449 454 > branches.active = green
450 455 > branches.closed = blue
451 456 > branches.current = red
452 457 > branches.inactive = magenta
453 458 > log.changeset = cyan
454 459 > EOF
455 460
456 461 custom branch colors:
457 462
458 463 $ hg branches --color=always
459 464 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
460 465 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
461 466 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
462 467 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
463 468
464 469 custom closed branch color:
465 470
466 471 $ hg branches --color=always --closed
467 472 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
468 473 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
469 474 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
470 475 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
471 476 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
472 477
473 478 template output:
474 479
475 480 $ hg branches -Tjson --closed
476 481 [
477 482 {
478 483 "active": true,
479 484 "branch": "b",
480 485 "closed": false,
481 486 "current": true,
482 487 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
483 488 "rev": 13
484 489 },
485 490 {
486 491 "active": true,
487 492 "branch": "a branch name much longer than the default justification used by branches",
488 493 "closed": false,
489 494 "current": false,
490 495 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
491 496 "rev": 7
492 497 },
493 498 {
494 499 "active": false,
495 500 "branch": "c",
496 501 "closed": true,
497 502 "current": false,
498 503 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
499 504 "rev": 14
500 505 },
501 506 {
502 507 "active": false,
503 508 "branch": "a",
504 509 "closed": false,
505 510 "current": false,
506 511 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
507 512 "rev": 5
508 513 },
509 514 {
510 515 "active": false,
511 516 "branch": "default",
512 517 "closed": false,
513 518 "current": false,
514 519 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
515 520 "rev": 0
516 521 }
517 522 ]
518 523
519 524 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
520 525 c
521 526
522 527 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
523 528 b: reopen branch with a change
524 529 a: Adding d branch
525 530 a: Adding b branch head 2
526 531 default: Adding root node
527 532
528 533 Tests of revision branch name caching
529 534
530 535 We rev branch cache is updated automatically. In these tests we use a trick to
531 536 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
532 537 rebuild that also will populate the rev branch cache.
533 538
534 539 revision branch cache is created when building the branch head cache
535 540 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
536 541 5
537 542 $ f --hexdump --size .hg/cache/rbc-*
538 543 .hg/cache/rbc-names-v1: size=87
539 544 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
540 545 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
541 546 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
542 547 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
543 548 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
544 549 0050: 72 61 6e 63 68 65 73 |ranches|
545 550 .hg/cache/rbc-revs-v1: size=120
546 551 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
547 552 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
548 553 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
549 554 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
550 555 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
551 556 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
552 557 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
553 558 0070: f8 94 c2 56 80 00 00 03 |...V....|
554 559
555 560 no errors when revbranchcache is not writable
556 561
557 562 $ echo >> .hg/cache/rbc-revs-v1
558 563 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
559 564 $ mkdir .hg/cache/rbc-revs-v1
560 565 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
561 566 5
562 567 $ rmdir .hg/cache/rbc-revs-v1
563 568 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
564 569
565 570 no errors when wlock cannot be acquired
566 571
567 572 #if unix-permissions
568 573 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
569 574 $ rm -f .hg/cache/branch*
570 575 $ chmod 555 .hg
571 576 $ hg head a -T '{rev}\n'
572 577 5
573 578 $ chmod 755 .hg
574 579 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
575 580 #endif
576 581
577 582 recovery from invalid cache revs file with trailing data
578 583 $ echo >> .hg/cache/rbc-revs-v1
579 584 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
580 585 5
581 586 truncating cache/rbc-revs-v1 to 120
582 587 $ f --size .hg/cache/rbc-revs*
583 588 .hg/cache/rbc-revs-v1: size=120
584 589 recovery from invalid cache file with partial last record
585 590 $ mv .hg/cache/rbc-revs-v1 .
586 591 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
587 592 $ f --size .hg/cache/rbc-revs*
588 593 .hg/cache/rbc-revs-v1: size=119
589 594 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
590 595 5
591 596 truncating cache/rbc-revs-v1 to 112
592 597 $ f --size .hg/cache/rbc-revs*
593 598 .hg/cache/rbc-revs-v1: size=120
594 599 recovery from invalid cache file with missing record - no truncation
595 600 $ mv .hg/cache/rbc-revs-v1 .
596 601 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
597 602 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
598 603 5
599 604 $ f --size .hg/cache/rbc-revs*
600 605 .hg/cache/rbc-revs-v1: size=120
601 606 recovery from invalid cache file with some bad records
602 607 $ mv .hg/cache/rbc-revs-v1 .
603 608 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
604 609 $ f --size .hg/cache/rbc-revs*
605 610 .hg/cache/rbc-revs-v1: size=8
606 611 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
607 612 $ f --size .hg/cache/rbc-revs*
608 613 .hg/cache/rbc-revs-v1: size=120
609 614 $ hg log -r 'branch(.)' -T '{rev} ' --debug
610 615 history modification detected - truncating revision branch cache to revision 13
611 616 history modification detected - truncating revision branch cache to revision 1
612 617 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
613 618 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
614 619 5
615 620 truncating cache/rbc-revs-v1 to 104
616 621 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
617 622 .hg/cache/rbc-revs-v1: size=120
618 623 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
619 624 cache is updated when committing
620 625 $ hg branch i-will-regret-this
621 626 marked working directory as branch i-will-regret-this
622 627 $ hg ci -m regrets
623 628 $ f --size .hg/cache/rbc-*
624 629 .hg/cache/rbc-names-v1: size=106
625 630 .hg/cache/rbc-revs-v1: size=128
626 631 update after rollback - the cache will be correct but rbc-names will will still
627 632 contain the branch name even though it no longer is used
628 633 $ hg up -qr '.^'
629 634 $ hg rollback -qf
630 635 $ f --size --hexdump .hg/cache/rbc-*
631 636 .hg/cache/rbc-names-v1: size=106
632 637 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
633 638 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
634 639 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
635 640 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
636 641 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
637 642 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
638 643 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
639 644 .hg/cache/rbc-revs-v1: size=120
640 645 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
641 646 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
642 647 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
643 648 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
644 649 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
645 650 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
646 651 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
647 652 0070: f8 94 c2 56 80 00 00 03 |...V....|
648 653 cache is updated/truncated when stripping - it is thus very hard to get in a
649 654 situation where the cache is out of sync and the hash check detects it
650 655 $ hg --config extensions.strip= strip -r tip --nob
651 656 $ f --size .hg/cache/rbc-revs*
652 657 .hg/cache/rbc-revs-v1: size=112
653 658
654 659 cache is rebuilt when corruption is detected
655 660 $ echo > .hg/cache/rbc-names-v1
656 661 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
657 662 referenced branch names not found - rebuilding revision branch cache from scratch
658 663 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
659 664 $ f --size --hexdump .hg/cache/rbc-*
660 665 .hg/cache/rbc-names-v1: size=79
661 666 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
662 667 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
663 668 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
664 669 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
665 670 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
666 671 .hg/cache/rbc-revs-v1: size=112
667 672 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
668 673 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
669 674 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
670 675 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
671 676 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
672 677 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
673 678 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
674 679
675 680 Test that cache files are created and grows correctly:
676 681
677 682 $ rm .hg/cache/rbc*
678 683 $ hg log -r "5 & branch(5)" -T "{rev}\n"
679 684 5
680 685 $ f --size --hexdump .hg/cache/rbc-*
681 686 .hg/cache/rbc-names-v1: size=1
682 687 0000: 61 |a|
683 688 .hg/cache/rbc-revs-v1: size=112
684 689 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
685 690 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
686 691 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
687 692 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
688 693 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
689 694 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
690 695 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
691 696
692 697 $ cd ..
693 698
694 699 Test for multiple incorrect branch cache entries:
695 700
696 701 $ hg init b
697 702 $ cd b
698 703 $ touch f
699 704 $ hg ci -Aqmf
700 705 $ echo >> f
701 706 $ hg ci -Amf
702 707 $ hg branch -q branch
703 708 $ hg ci -Amf
704 709
705 710 $ f --size --hexdump .hg/cache/rbc-*
706 711 .hg/cache/rbc-names-v1: size=14
707 712 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
708 713 .hg/cache/rbc-revs-v1: size=24
709 714 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
710 715 0010: 56 46 78 69 00 00 00 01 |VFxi....|
711 716 $ : > .hg/cache/rbc-revs-v1
712 717
713 718 No superfluous rebuilding of cache:
714 719 $ hg log -r "branch(null)&branch(branch)" --debug
715 720 $ f --size --hexdump .hg/cache/rbc-*
716 721 .hg/cache/rbc-names-v1: size=14
717 722 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
718 723 .hg/cache/rbc-revs-v1: size=24
719 724 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
720 725 0010: 56 46 78 69 00 00 00 01 |VFxi....|
721 726
722 727 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now