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