##// END OF EJS Templates
obsolete: fix ValueError when stored note contains ':' char (issue5783)...
Zharaskhan Aman -
r40117:a4d62ff9 default
parent child Browse files
Show More
@@ -1,1058 +1,1058 b''
1 1 # obsolete.py - obsolete markers handling
2 2 #
3 3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 4 # Logilab SA <contact@logilab.fr>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 """Obsolete marker handling
10 10
11 11 An obsolete marker maps an old changeset to a list of new
12 12 changesets. If the list of new changesets is empty, the old changeset
13 13 is said to be "killed". Otherwise, the old changeset is being
14 14 "replaced" by the new changesets.
15 15
16 16 Obsolete markers can be used to record and distribute changeset graph
17 17 transformations performed by history rewrite operations, and help
18 18 building new tools to reconcile conflicting rewrite actions. To
19 19 facilitate conflict resolution, markers include various annotations
20 20 besides old and news changeset identifiers, such as creation date or
21 21 author name.
22 22
23 23 The old obsoleted changeset is called a "predecessor" and possible
24 24 replacements are called "successors". Markers that used changeset X as
25 25 a predecessor are called "successor markers of X" because they hold
26 26 information about the successors of X. Markers that use changeset Y as
27 27 a successors are call "predecessor markers of Y" because they hold
28 28 information about the predecessors of Y.
29 29
30 30 Examples:
31 31
32 32 - When changeset A is replaced by changeset A', one marker is stored:
33 33
34 34 (A, (A',))
35 35
36 36 - When changesets A and B are folded into a new changeset C, two markers are
37 37 stored:
38 38
39 39 (A, (C,)) and (B, (C,))
40 40
41 41 - When changeset A is simply "pruned" from the graph, a marker is created:
42 42
43 43 (A, ())
44 44
45 45 - When changeset A is split into B and C, a single marker is used:
46 46
47 47 (A, (B, C))
48 48
49 49 We use a single marker to distinguish the "split" case from the "divergence"
50 50 case. If two independent operations rewrite the same changeset A in to A' and
51 51 A'', we have an error case: divergent rewriting. We can detect it because
52 52 two markers will be created independently:
53 53
54 54 (A, (B,)) and (A, (C,))
55 55
56 56 Format
57 57 ------
58 58
59 59 Markers are stored in an append-only file stored in
60 60 '.hg/store/obsstore'.
61 61
62 62 The file starts with a version header:
63 63
64 64 - 1 unsigned byte: version number, starting at zero.
65 65
66 66 The header is followed by the markers. Marker format depend of the version. See
67 67 comment associated with each format for details.
68 68
69 69 """
70 70 from __future__ import absolute_import
71 71
72 72 import errno
73 73 import hashlib
74 74 import struct
75 75
76 76 from .i18n import _
77 77 from . import (
78 78 encoding,
79 79 error,
80 80 node,
81 81 obsutil,
82 82 phases,
83 83 policy,
84 84 pycompat,
85 85 util,
86 86 )
87 87 from .utils import dateutil
88 88
89 89 parsers = policy.importmod(r'parsers')
90 90
91 91 _pack = struct.pack
92 92 _unpack = struct.unpack
93 93 _calcsize = struct.calcsize
94 94 propertycache = util.propertycache
95 95
96 96 # the obsolete feature is not mature enough to be enabled by default.
97 97 # you have to rely on third party extension extension to enable this.
98 98 _enabled = False
99 99
100 100 # Options for obsolescence
101 101 createmarkersopt = 'createmarkers'
102 102 allowunstableopt = 'allowunstable'
103 103 exchangeopt = 'exchange'
104 104
105 105 def _getoptionvalue(repo, option):
106 106 """Returns True if the given repository has the given obsolete option
107 107 enabled.
108 108 """
109 109 configkey = 'evolution.%s' % option
110 110 newconfig = repo.ui.configbool('experimental', configkey)
111 111
112 112 # Return the value only if defined
113 113 if newconfig is not None:
114 114 return newconfig
115 115
116 116 # Fallback on generic option
117 117 try:
118 118 return repo.ui.configbool('experimental', 'evolution')
119 119 except (error.ConfigError, AttributeError):
120 120 # Fallback on old-fashion config
121 121 # inconsistent config: experimental.evolution
122 122 result = set(repo.ui.configlist('experimental', 'evolution'))
123 123
124 124 if 'all' in result:
125 125 return True
126 126
127 127 # For migration purposes, temporarily return true if the config hasn't
128 128 # been set but _enabled is true.
129 129 if len(result) == 0 and _enabled:
130 130 return True
131 131
132 132 # Temporary hack for next check
133 133 newconfig = repo.ui.config('experimental', 'evolution.createmarkers')
134 134 if newconfig:
135 135 result.add('createmarkers')
136 136
137 137 return option in result
138 138
139 139 def getoptions(repo):
140 140 """Returns dicts showing state of obsolescence features."""
141 141
142 142 createmarkersvalue = _getoptionvalue(repo, createmarkersopt)
143 143 unstablevalue = _getoptionvalue(repo, allowunstableopt)
144 144 exchangevalue = _getoptionvalue(repo, exchangeopt)
145 145
146 146 # createmarkers must be enabled if other options are enabled
147 147 if ((unstablevalue or exchangevalue) and not createmarkersvalue):
148 148 raise error.Abort(_("'createmarkers' obsolete option must be enabled "
149 149 "if other obsolete options are enabled"))
150 150
151 151 return {
152 152 createmarkersopt: createmarkersvalue,
153 153 allowunstableopt: unstablevalue,
154 154 exchangeopt: exchangevalue,
155 155 }
156 156
157 157 def isenabled(repo, option):
158 158 """Returns True if the given repository has the given obsolete option
159 159 enabled.
160 160 """
161 161 return getoptions(repo)[option]
162 162
163 163 # Creating aliases for marker flags because evolve extension looks for
164 164 # bumpedfix in obsolete.py
165 165 bumpedfix = obsutil.bumpedfix
166 166 usingsha256 = obsutil.usingsha256
167 167
168 168 ## Parsing and writing of version "0"
169 169 #
170 170 # The header is followed by the markers. Each marker is made of:
171 171 #
172 172 # - 1 uint8 : number of new changesets "N", can be zero.
173 173 #
174 174 # - 1 uint32: metadata size "M" in bytes.
175 175 #
176 176 # - 1 byte: a bit field. It is reserved for flags used in common
177 177 # obsolete marker operations, to avoid repeated decoding of metadata
178 178 # entries.
179 179 #
180 180 # - 20 bytes: obsoleted changeset identifier.
181 181 #
182 182 # - N*20 bytes: new changesets identifiers.
183 183 #
184 184 # - M bytes: metadata as a sequence of nul-terminated strings. Each
185 185 # string contains a key and a value, separated by a colon ':', without
186 186 # additional encoding. Keys cannot contain '\0' or ':' and values
187 187 # cannot contain '\0'.
188 188 _fm0version = 0
189 189 _fm0fixed = '>BIB20s'
190 190 _fm0node = '20s'
191 191 _fm0fsize = _calcsize(_fm0fixed)
192 192 _fm0fnodesize = _calcsize(_fm0node)
193 193
194 194 def _fm0readmarkers(data, off, stop):
195 195 # Loop on markers
196 196 while off < stop:
197 197 # read fixed part
198 198 cur = data[off:off + _fm0fsize]
199 199 off += _fm0fsize
200 200 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
201 201 # read replacement
202 202 sucs = ()
203 203 if numsuc:
204 204 s = (_fm0fnodesize * numsuc)
205 205 cur = data[off:off + s]
206 206 sucs = _unpack(_fm0node * numsuc, cur)
207 207 off += s
208 208 # read metadata
209 209 # (metadata will be decoded on demand)
210 210 metadata = data[off:off + mdsize]
211 211 if len(metadata) != mdsize:
212 212 raise error.Abort(_('parsing obsolete marker: metadata is too '
213 213 'short, %d bytes expected, got %d')
214 214 % (mdsize, len(metadata)))
215 215 off += mdsize
216 216 metadata = _fm0decodemeta(metadata)
217 217 try:
218 218 when, offset = metadata.pop('date', '0 0').split(' ')
219 219 date = float(when), int(offset)
220 220 except ValueError:
221 221 date = (0., 0)
222 222 parents = None
223 223 if 'p2' in metadata:
224 224 parents = (metadata.pop('p1', None), metadata.pop('p2', None))
225 225 elif 'p1' in metadata:
226 226 parents = (metadata.pop('p1', None),)
227 227 elif 'p0' in metadata:
228 228 parents = ()
229 229 if parents is not None:
230 230 try:
231 231 parents = tuple(node.bin(p) for p in parents)
232 232 # if parent content is not a nodeid, drop the data
233 233 for p in parents:
234 234 if len(p) != 20:
235 235 parents = None
236 236 break
237 237 except TypeError:
238 238 # if content cannot be translated to nodeid drop the data.
239 239 parents = None
240 240
241 241 metadata = tuple(sorted(metadata.iteritems()))
242 242
243 243 yield (pre, sucs, flags, metadata, date, parents)
244 244
245 245 def _fm0encodeonemarker(marker):
246 246 pre, sucs, flags, metadata, date, parents = marker
247 247 if flags & usingsha256:
248 248 raise error.Abort(_('cannot handle sha256 with old obsstore format'))
249 249 metadata = dict(metadata)
250 250 time, tz = date
251 251 metadata['date'] = '%r %i' % (time, tz)
252 252 if parents is not None:
253 253 if not parents:
254 254 # mark that we explicitly recorded no parents
255 255 metadata['p0'] = ''
256 256 for i, p in enumerate(parents, 1):
257 257 metadata['p%i' % i] = node.hex(p)
258 258 metadata = _fm0encodemeta(metadata)
259 259 numsuc = len(sucs)
260 260 format = _fm0fixed + (_fm0node * numsuc)
261 261 data = [numsuc, len(metadata), flags, pre]
262 262 data.extend(sucs)
263 263 return _pack(format, *data) + metadata
264 264
265 265 def _fm0encodemeta(meta):
266 266 """Return encoded metadata string to string mapping.
267 267
268 268 Assume no ':' in key and no '\0' in both key and value."""
269 269 for key, value in meta.iteritems():
270 270 if ':' in key or '\0' in key:
271 271 raise ValueError("':' and '\0' are forbidden in metadata key'")
272 272 if '\0' in value:
273 273 raise ValueError("':' is forbidden in metadata value'")
274 274 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
275 275
276 276 def _fm0decodemeta(data):
277 277 """Return string to string dictionary from encoded version."""
278 278 d = {}
279 279 for l in data.split('\0'):
280 280 if l:
281 key, value = l.split(':')
281 key, value = l.split(':', 1)
282 282 d[key] = value
283 283 return d
284 284
285 285 ## Parsing and writing of version "1"
286 286 #
287 287 # The header is followed by the markers. Each marker is made of:
288 288 #
289 289 # - uint32: total size of the marker (including this field)
290 290 #
291 291 # - float64: date in seconds since epoch
292 292 #
293 293 # - int16: timezone offset in minutes
294 294 #
295 295 # - uint16: a bit field. It is reserved for flags used in common
296 296 # obsolete marker operations, to avoid repeated decoding of metadata
297 297 # entries.
298 298 #
299 299 # - uint8: number of successors "N", can be zero.
300 300 #
301 301 # - uint8: number of parents "P", can be zero.
302 302 #
303 303 # 0: parents data stored but no parent,
304 304 # 1: one parent stored,
305 305 # 2: two parents stored,
306 306 # 3: no parent data stored
307 307 #
308 308 # - uint8: number of metadata entries M
309 309 #
310 310 # - 20 or 32 bytes: predecessor changeset identifier.
311 311 #
312 312 # - N*(20 or 32) bytes: successors changesets identifiers.
313 313 #
314 314 # - P*(20 or 32) bytes: parents of the predecessors changesets.
315 315 #
316 316 # - M*(uint8, uint8): size of all metadata entries (key and value)
317 317 #
318 318 # - remaining bytes: the metadata, each (key, value) pair after the other.
319 319 _fm1version = 1
320 320 _fm1fixed = '>IdhHBBB20s'
321 321 _fm1nodesha1 = '20s'
322 322 _fm1nodesha256 = '32s'
323 323 _fm1nodesha1size = _calcsize(_fm1nodesha1)
324 324 _fm1nodesha256size = _calcsize(_fm1nodesha256)
325 325 _fm1fsize = _calcsize(_fm1fixed)
326 326 _fm1parentnone = 3
327 327 _fm1parentshift = 14
328 328 _fm1parentmask = (_fm1parentnone << _fm1parentshift)
329 329 _fm1metapair = 'BB'
330 330 _fm1metapairsize = _calcsize(_fm1metapair)
331 331
332 332 def _fm1purereadmarkers(data, off, stop):
333 333 # make some global constants local for performance
334 334 noneflag = _fm1parentnone
335 335 sha2flag = usingsha256
336 336 sha1size = _fm1nodesha1size
337 337 sha2size = _fm1nodesha256size
338 338 sha1fmt = _fm1nodesha1
339 339 sha2fmt = _fm1nodesha256
340 340 metasize = _fm1metapairsize
341 341 metafmt = _fm1metapair
342 342 fsize = _fm1fsize
343 343 unpack = _unpack
344 344
345 345 # Loop on markers
346 346 ufixed = struct.Struct(_fm1fixed).unpack
347 347
348 348 while off < stop:
349 349 # read fixed part
350 350 o1 = off + fsize
351 351 t, secs, tz, flags, numsuc, numpar, nummeta, prec = ufixed(data[off:o1])
352 352
353 353 if flags & sha2flag:
354 354 # FIXME: prec was read as a SHA1, needs to be amended
355 355
356 356 # read 0 or more successors
357 357 if numsuc == 1:
358 358 o2 = o1 + sha2size
359 359 sucs = (data[o1:o2],)
360 360 else:
361 361 o2 = o1 + sha2size * numsuc
362 362 sucs = unpack(sha2fmt * numsuc, data[o1:o2])
363 363
364 364 # read parents
365 365 if numpar == noneflag:
366 366 o3 = o2
367 367 parents = None
368 368 elif numpar == 1:
369 369 o3 = o2 + sha2size
370 370 parents = (data[o2:o3],)
371 371 else:
372 372 o3 = o2 + sha2size * numpar
373 373 parents = unpack(sha2fmt * numpar, data[o2:o3])
374 374 else:
375 375 # read 0 or more successors
376 376 if numsuc == 1:
377 377 o2 = o1 + sha1size
378 378 sucs = (data[o1:o2],)
379 379 else:
380 380 o2 = o1 + sha1size * numsuc
381 381 sucs = unpack(sha1fmt * numsuc, data[o1:o2])
382 382
383 383 # read parents
384 384 if numpar == noneflag:
385 385 o3 = o2
386 386 parents = None
387 387 elif numpar == 1:
388 388 o3 = o2 + sha1size
389 389 parents = (data[o2:o3],)
390 390 else:
391 391 o3 = o2 + sha1size * numpar
392 392 parents = unpack(sha1fmt * numpar, data[o2:o3])
393 393
394 394 # read metadata
395 395 off = o3 + metasize * nummeta
396 396 metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off])
397 397 metadata = []
398 398 for idx in pycompat.xrange(0, len(metapairsize), 2):
399 399 o1 = off + metapairsize[idx]
400 400 o2 = o1 + metapairsize[idx + 1]
401 401 metadata.append((data[off:o1], data[o1:o2]))
402 402 off = o2
403 403
404 404 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
405 405
406 406 def _fm1encodeonemarker(marker):
407 407 pre, sucs, flags, metadata, date, parents = marker
408 408 # determine node size
409 409 _fm1node = _fm1nodesha1
410 410 if flags & usingsha256:
411 411 _fm1node = _fm1nodesha256
412 412 numsuc = len(sucs)
413 413 numextranodes = numsuc
414 414 if parents is None:
415 415 numpar = _fm1parentnone
416 416 else:
417 417 numpar = len(parents)
418 418 numextranodes += numpar
419 419 formatnodes = _fm1node * numextranodes
420 420 formatmeta = _fm1metapair * len(metadata)
421 421 format = _fm1fixed + formatnodes + formatmeta
422 422 # tz is stored in minutes so we divide by 60
423 423 tz = date[1]//60
424 424 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
425 425 data.extend(sucs)
426 426 if parents is not None:
427 427 data.extend(parents)
428 428 totalsize = _calcsize(format)
429 429 for key, value in metadata:
430 430 lk = len(key)
431 431 lv = len(value)
432 432 if lk > 255:
433 433 msg = ('obsstore metadata key cannot be longer than 255 bytes'
434 434 ' (key "%s" is %u bytes)') % (key, lk)
435 435 raise error.ProgrammingError(msg)
436 436 if lv > 255:
437 437 msg = ('obsstore metadata value cannot be longer than 255 bytes'
438 438 ' (value "%s" for key "%s" is %u bytes)') % (value, key, lv)
439 439 raise error.ProgrammingError(msg)
440 440 data.append(lk)
441 441 data.append(lv)
442 442 totalsize += lk + lv
443 443 data[0] = totalsize
444 444 data = [_pack(format, *data)]
445 445 for key, value in metadata:
446 446 data.append(key)
447 447 data.append(value)
448 448 return ''.join(data)
449 449
450 450 def _fm1readmarkers(data, off, stop):
451 451 native = getattr(parsers, 'fm1readmarkers', None)
452 452 if not native:
453 453 return _fm1purereadmarkers(data, off, stop)
454 454 return native(data, off, stop)
455 455
456 456 # mapping to read/write various marker formats
457 457 # <version> -> (decoder, encoder)
458 458 formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
459 459 _fm1version: (_fm1readmarkers, _fm1encodeonemarker)}
460 460
461 461 def _readmarkerversion(data):
462 462 return _unpack('>B', data[0:1])[0]
463 463
464 464 @util.nogc
465 465 def _readmarkers(data, off=None, stop=None):
466 466 """Read and enumerate markers from raw data"""
467 467 diskversion = _readmarkerversion(data)
468 468 if not off:
469 469 off = 1 # skip 1 byte version number
470 470 if stop is None:
471 471 stop = len(data)
472 472 if diskversion not in formats:
473 473 msg = _('parsing obsolete marker: unknown version %r') % diskversion
474 474 raise error.UnknownVersion(msg, version=diskversion)
475 475 return diskversion, formats[diskversion][0](data, off, stop)
476 476
477 477 def encodeheader(version=_fm0version):
478 478 return _pack('>B', version)
479 479
480 480 def encodemarkers(markers, addheader=False, version=_fm0version):
481 481 # Kept separate from flushmarkers(), it will be reused for
482 482 # markers exchange.
483 483 encodeone = formats[version][1]
484 484 if addheader:
485 485 yield encodeheader(version)
486 486 for marker in markers:
487 487 yield encodeone(marker)
488 488
489 489 @util.nogc
490 490 def _addsuccessors(successors, markers):
491 491 for mark in markers:
492 492 successors.setdefault(mark[0], set()).add(mark)
493 493
494 494 @util.nogc
495 495 def _addpredecessors(predecessors, markers):
496 496 for mark in markers:
497 497 for suc in mark[1]:
498 498 predecessors.setdefault(suc, set()).add(mark)
499 499
500 500 @util.nogc
501 501 def _addchildren(children, markers):
502 502 for mark in markers:
503 503 parents = mark[5]
504 504 if parents is not None:
505 505 for p in parents:
506 506 children.setdefault(p, set()).add(mark)
507 507
508 508 def _checkinvalidmarkers(markers):
509 509 """search for marker with invalid data and raise error if needed
510 510
511 511 Exist as a separated function to allow the evolve extension for a more
512 512 subtle handling.
513 513 """
514 514 for mark in markers:
515 515 if node.nullid in mark[1]:
516 516 raise error.Abort(_('bad obsolescence marker detected: '
517 517 'invalid successors nullid'))
518 518
519 519 class obsstore(object):
520 520 """Store obsolete markers
521 521
522 522 Markers can be accessed with two mappings:
523 523 - predecessors[x] -> set(markers on predecessors edges of x)
524 524 - successors[x] -> set(markers on successors edges of x)
525 525 - children[x] -> set(markers on predecessors edges of children(x)
526 526 """
527 527
528 528 fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
529 529 # prec: nodeid, predecessors changesets
530 530 # succs: tuple of nodeid, successor changesets (0-N length)
531 531 # flag: integer, flag field carrying modifier for the markers (see doc)
532 532 # meta: binary blob in UTF-8, encoded metadata dictionary
533 533 # date: (float, int) tuple, date of marker creation
534 534 # parents: (tuple of nodeid) or None, parents of predecessors
535 535 # None is used when no data has been recorded
536 536
537 537 def __init__(self, svfs, defaultformat=_fm1version, readonly=False):
538 538 # caches for various obsolescence related cache
539 539 self.caches = {}
540 540 self.svfs = svfs
541 541 self._defaultformat = defaultformat
542 542 self._readonly = readonly
543 543
544 544 def __iter__(self):
545 545 return iter(self._all)
546 546
547 547 def __len__(self):
548 548 return len(self._all)
549 549
550 550 def __nonzero__(self):
551 551 if not self._cached(r'_all'):
552 552 try:
553 553 return self.svfs.stat('obsstore').st_size > 1
554 554 except OSError as inst:
555 555 if inst.errno != errno.ENOENT:
556 556 raise
557 557 # just build an empty _all list if no obsstore exists, which
558 558 # avoids further stat() syscalls
559 559 return bool(self._all)
560 560
561 561 __bool__ = __nonzero__
562 562
563 563 @property
564 564 def readonly(self):
565 565 """True if marker creation is disabled
566 566
567 567 Remove me in the future when obsolete marker is always on."""
568 568 return self._readonly
569 569
570 570 def create(self, transaction, prec, succs=(), flag=0, parents=None,
571 571 date=None, metadata=None, ui=None):
572 572 """obsolete: add a new obsolete marker
573 573
574 574 * ensuring it is hashable
575 575 * check mandatory metadata
576 576 * encode metadata
577 577
578 578 If you are a human writing code creating marker you want to use the
579 579 `createmarkers` function in this module instead.
580 580
581 581 return True if a new marker have been added, False if the markers
582 582 already existed (no op).
583 583 """
584 584 if metadata is None:
585 585 metadata = {}
586 586 if date is None:
587 587 if 'date' in metadata:
588 588 # as a courtesy for out-of-tree extensions
589 589 date = dateutil.parsedate(metadata.pop('date'))
590 590 elif ui is not None:
591 591 date = ui.configdate('devel', 'default-date')
592 592 if date is None:
593 593 date = dateutil.makedate()
594 594 else:
595 595 date = dateutil.makedate()
596 596 if len(prec) != 20:
597 597 raise ValueError(prec)
598 598 for succ in succs:
599 599 if len(succ) != 20:
600 600 raise ValueError(succ)
601 601 if prec in succs:
602 602 raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
603 603
604 604 metadata = tuple(sorted(metadata.iteritems()))
605 605 for k, v in metadata:
606 606 try:
607 607 # might be better to reject non-ASCII keys
608 608 k.decode('utf-8')
609 609 v.decode('utf-8')
610 610 except UnicodeDecodeError:
611 611 raise error.ProgrammingError(
612 612 'obsstore metadata must be valid UTF-8 sequence '
613 613 '(key = %r, value = %r)'
614 614 % (pycompat.bytestr(k), pycompat.bytestr(v)))
615 615
616 616 marker = (bytes(prec), tuple(succs), int(flag), metadata, date, parents)
617 617 return bool(self.add(transaction, [marker]))
618 618
619 619 def add(self, transaction, markers):
620 620 """Add new markers to the store
621 621
622 622 Take care of filtering duplicate.
623 623 Return the number of new marker."""
624 624 if self._readonly:
625 625 raise error.Abort(_('creating obsolete markers is not enabled on '
626 626 'this repo'))
627 627 known = set()
628 628 getsuccessors = self.successors.get
629 629 new = []
630 630 for m in markers:
631 631 if m not in getsuccessors(m[0], ()) and m not in known:
632 632 known.add(m)
633 633 new.append(m)
634 634 if new:
635 635 f = self.svfs('obsstore', 'ab')
636 636 try:
637 637 offset = f.tell()
638 638 transaction.add('obsstore', offset)
639 639 # offset == 0: new file - add the version header
640 640 data = b''.join(encodemarkers(new, offset == 0, self._version))
641 641 f.write(data)
642 642 finally:
643 643 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
644 644 # call 'filecacheentry.refresh()' here
645 645 f.close()
646 646 addedmarkers = transaction.changes.get('obsmarkers')
647 647 if addedmarkers is not None:
648 648 addedmarkers.update(new)
649 649 self._addmarkers(new, data)
650 650 # new marker *may* have changed several set. invalidate the cache.
651 651 self.caches.clear()
652 652 # records the number of new markers for the transaction hooks
653 653 previous = int(transaction.hookargs.get('new_obsmarkers', '0'))
654 654 transaction.hookargs['new_obsmarkers'] = '%d' % (previous + len(new))
655 655 return len(new)
656 656
657 657 def mergemarkers(self, transaction, data):
658 658 """merge a binary stream of markers inside the obsstore
659 659
660 660 Returns the number of new markers added."""
661 661 version, markers = _readmarkers(data)
662 662 return self.add(transaction, markers)
663 663
664 664 @propertycache
665 665 def _data(self):
666 666 return self.svfs.tryread('obsstore')
667 667
668 668 @propertycache
669 669 def _version(self):
670 670 if len(self._data) >= 1:
671 671 return _readmarkerversion(self._data)
672 672 else:
673 673 return self._defaultformat
674 674
675 675 @propertycache
676 676 def _all(self):
677 677 data = self._data
678 678 if not data:
679 679 return []
680 680 self._version, markers = _readmarkers(data)
681 681 markers = list(markers)
682 682 _checkinvalidmarkers(markers)
683 683 return markers
684 684
685 685 @propertycache
686 686 def successors(self):
687 687 successors = {}
688 688 _addsuccessors(successors, self._all)
689 689 return successors
690 690
691 691 @propertycache
692 692 def predecessors(self):
693 693 predecessors = {}
694 694 _addpredecessors(predecessors, self._all)
695 695 return predecessors
696 696
697 697 @propertycache
698 698 def children(self):
699 699 children = {}
700 700 _addchildren(children, self._all)
701 701 return children
702 702
703 703 def _cached(self, attr):
704 704 return attr in self.__dict__
705 705
706 706 def _addmarkers(self, markers, rawdata):
707 707 markers = list(markers) # to allow repeated iteration
708 708 self._data = self._data + rawdata
709 709 self._all.extend(markers)
710 710 if self._cached(r'successors'):
711 711 _addsuccessors(self.successors, markers)
712 712 if self._cached(r'predecessors'):
713 713 _addpredecessors(self.predecessors, markers)
714 714 if self._cached(r'children'):
715 715 _addchildren(self.children, markers)
716 716 _checkinvalidmarkers(markers)
717 717
718 718 def relevantmarkers(self, nodes):
719 719 """return a set of all obsolescence markers relevant to a set of nodes.
720 720
721 721 "relevant" to a set of nodes mean:
722 722
723 723 - marker that use this changeset as successor
724 724 - prune marker of direct children on this changeset
725 725 - recursive application of the two rules on predecessors of these
726 726 markers
727 727
728 728 It is a set so you cannot rely on order."""
729 729
730 730 pendingnodes = set(nodes)
731 731 seenmarkers = set()
732 732 seennodes = set(pendingnodes)
733 733 precursorsmarkers = self.predecessors
734 734 succsmarkers = self.successors
735 735 children = self.children
736 736 while pendingnodes:
737 737 direct = set()
738 738 for current in pendingnodes:
739 739 direct.update(precursorsmarkers.get(current, ()))
740 740 pruned = [m for m in children.get(current, ()) if not m[1]]
741 741 direct.update(pruned)
742 742 pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
743 743 direct.update(pruned)
744 744 direct -= seenmarkers
745 745 pendingnodes = set([m[0] for m in direct])
746 746 seenmarkers |= direct
747 747 pendingnodes -= seennodes
748 748 seennodes |= pendingnodes
749 749 return seenmarkers
750 750
751 751 def makestore(ui, repo):
752 752 """Create an obsstore instance from a repo."""
753 753 # read default format for new obsstore.
754 754 # developer config: format.obsstore-version
755 755 defaultformat = ui.configint('format', 'obsstore-version')
756 756 # rely on obsstore class default when possible.
757 757 kwargs = {}
758 758 if defaultformat is not None:
759 759 kwargs[r'defaultformat'] = defaultformat
760 760 readonly = not isenabled(repo, createmarkersopt)
761 761 store = obsstore(repo.svfs, readonly=readonly, **kwargs)
762 762 if store and readonly:
763 763 ui.warn(_('obsolete feature not enabled but %i markers found!\n')
764 764 % len(list(store)))
765 765 return store
766 766
767 767 def commonversion(versions):
768 768 """Return the newest version listed in both versions and our local formats.
769 769
770 770 Returns None if no common version exists.
771 771 """
772 772 versions.sort(reverse=True)
773 773 # search for highest version known on both side
774 774 for v in versions:
775 775 if v in formats:
776 776 return v
777 777 return None
778 778
779 779 # arbitrary picked to fit into 8K limit from HTTP server
780 780 # you have to take in account:
781 781 # - the version header
782 782 # - the base85 encoding
783 783 _maxpayload = 5300
784 784
785 785 def _pushkeyescape(markers):
786 786 """encode markers into a dict suitable for pushkey exchange
787 787
788 788 - binary data is base85 encoded
789 789 - split in chunks smaller than 5300 bytes"""
790 790 keys = {}
791 791 parts = []
792 792 currentlen = _maxpayload * 2 # ensure we create a new part
793 793 for marker in markers:
794 794 nextdata = _fm0encodeonemarker(marker)
795 795 if (len(nextdata) + currentlen > _maxpayload):
796 796 currentpart = []
797 797 currentlen = 0
798 798 parts.append(currentpart)
799 799 currentpart.append(nextdata)
800 800 currentlen += len(nextdata)
801 801 for idx, part in enumerate(reversed(parts)):
802 802 data = ''.join([_pack('>B', _fm0version)] + part)
803 803 keys['dump%i' % idx] = util.b85encode(data)
804 804 return keys
805 805
806 806 def listmarkers(repo):
807 807 """List markers over pushkey"""
808 808 if not repo.obsstore:
809 809 return {}
810 810 return _pushkeyescape(sorted(repo.obsstore))
811 811
812 812 def pushmarker(repo, key, old, new):
813 813 """Push markers over pushkey"""
814 814 if not key.startswith('dump'):
815 815 repo.ui.warn(_('unknown key: %r') % key)
816 816 return False
817 817 if old:
818 818 repo.ui.warn(_('unexpected old value for %r') % key)
819 819 return False
820 820 data = util.b85decode(new)
821 821 with repo.lock(), repo.transaction('pushkey: obsolete markers') as tr:
822 822 repo.obsstore.mergemarkers(tr, data)
823 823 repo.invalidatevolatilesets()
824 824 return True
825 825
826 826 # mapping of 'set-name' -> <function to compute this set>
827 827 cachefuncs = {}
828 828 def cachefor(name):
829 829 """Decorator to register a function as computing the cache for a set"""
830 830 def decorator(func):
831 831 if name in cachefuncs:
832 832 msg = "duplicated registration for volatileset '%s' (existing: %r)"
833 833 raise error.ProgrammingError(msg % (name, cachefuncs[name]))
834 834 cachefuncs[name] = func
835 835 return func
836 836 return decorator
837 837
838 838 def getrevs(repo, name):
839 839 """Return the set of revision that belong to the <name> set
840 840
841 841 Such access may compute the set and cache it for future use"""
842 842 repo = repo.unfiltered()
843 843 if not repo.obsstore:
844 844 return frozenset()
845 845 if name not in repo.obsstore.caches:
846 846 repo.obsstore.caches[name] = cachefuncs[name](repo)
847 847 return repo.obsstore.caches[name]
848 848
849 849 # To be simple we need to invalidate obsolescence cache when:
850 850 #
851 851 # - new changeset is added:
852 852 # - public phase is changed
853 853 # - obsolescence marker are added
854 854 # - strip is used a repo
855 855 def clearobscaches(repo):
856 856 """Remove all obsolescence related cache from a repo
857 857
858 858 This remove all cache in obsstore is the obsstore already exist on the
859 859 repo.
860 860
861 861 (We could be smarter here given the exact event that trigger the cache
862 862 clearing)"""
863 863 # only clear cache is there is obsstore data in this repo
864 864 if 'obsstore' in repo._filecache:
865 865 repo.obsstore.caches.clear()
866 866
867 867 def _mutablerevs(repo):
868 868 """the set of mutable revision in the repository"""
869 869 return repo._phasecache.getrevset(repo, phases.mutablephases)
870 870
871 871 @cachefor('obsolete')
872 872 def _computeobsoleteset(repo):
873 873 """the set of obsolete revisions"""
874 874 getnode = repo.changelog.node
875 875 notpublic = _mutablerevs(repo)
876 876 isobs = repo.obsstore.successors.__contains__
877 877 obs = set(r for r in notpublic if isobs(getnode(r)))
878 878 return obs
879 879
880 880 @cachefor('orphan')
881 881 def _computeorphanset(repo):
882 882 """the set of non obsolete revisions with obsolete parents"""
883 883 pfunc = repo.changelog.parentrevs
884 884 mutable = _mutablerevs(repo)
885 885 obsolete = getrevs(repo, 'obsolete')
886 886 others = mutable - obsolete
887 887 unstable = set()
888 888 for r in sorted(others):
889 889 # A rev is unstable if one of its parent is obsolete or unstable
890 890 # this works since we traverse following growing rev order
891 891 for p in pfunc(r):
892 892 if p in obsolete or p in unstable:
893 893 unstable.add(r)
894 894 break
895 895 return unstable
896 896
897 897 @cachefor('suspended')
898 898 def _computesuspendedset(repo):
899 899 """the set of obsolete parents with non obsolete descendants"""
900 900 suspended = repo.changelog.ancestors(getrevs(repo, 'orphan'))
901 901 return set(r for r in getrevs(repo, 'obsolete') if r in suspended)
902 902
903 903 @cachefor('extinct')
904 904 def _computeextinctset(repo):
905 905 """the set of obsolete parents without non obsolete descendants"""
906 906 return getrevs(repo, 'obsolete') - getrevs(repo, 'suspended')
907 907
908 908 @cachefor('phasedivergent')
909 909 def _computephasedivergentset(repo):
910 910 """the set of revs trying to obsolete public revisions"""
911 911 bumped = set()
912 912 # util function (avoid attribute lookup in the loop)
913 913 phase = repo._phasecache.phase # would be faster to grab the full list
914 914 public = phases.public
915 915 cl = repo.changelog
916 916 torev = cl.nodemap.get
917 917 tonode = cl.node
918 918 for rev in repo.revs('(not public()) and (not obsolete())'):
919 919 # We only evaluate mutable, non-obsolete revision
920 920 node = tonode(rev)
921 921 # (future) A cache of predecessors may worth if split is very common
922 922 for pnode in obsutil.allpredecessors(repo.obsstore, [node],
923 923 ignoreflags=bumpedfix):
924 924 prev = torev(pnode) # unfiltered! but so is phasecache
925 925 if (prev is not None) and (phase(repo, prev) <= public):
926 926 # we have a public predecessor
927 927 bumped.add(rev)
928 928 break # Next draft!
929 929 return bumped
930 930
931 931 @cachefor('contentdivergent')
932 932 def _computecontentdivergentset(repo):
933 933 """the set of rev that compete to be the final successors of some revision.
934 934 """
935 935 divergent = set()
936 936 obsstore = repo.obsstore
937 937 newermap = {}
938 938 tonode = repo.changelog.node
939 939 for rev in repo.revs('(not public()) - obsolete()'):
940 940 node = tonode(rev)
941 941 mark = obsstore.predecessors.get(node, ())
942 942 toprocess = set(mark)
943 943 seen = set()
944 944 while toprocess:
945 945 prec = toprocess.pop()[0]
946 946 if prec in seen:
947 947 continue # emergency cycle hanging prevention
948 948 seen.add(prec)
949 949 if prec not in newermap:
950 950 obsutil.successorssets(repo, prec, cache=newermap)
951 951 newer = [n for n in newermap[prec] if n]
952 952 if len(newer) > 1:
953 953 divergent.add(rev)
954 954 break
955 955 toprocess.update(obsstore.predecessors.get(prec, ()))
956 956 return divergent
957 957
958 958 def makefoldid(relation, user):
959 959
960 960 folddigest = hashlib.sha1(user)
961 961 for p in relation[0] + relation[1]:
962 962 folddigest.update('%d' % p.rev())
963 963 folddigest.update(p.node())
964 964 # Since fold only has to compete against fold for the same successors, it
965 965 # seems fine to use a small ID. Smaller ID save space.
966 966 return node.hex(folddigest.digest())[:8]
967 967
968 968 def createmarkers(repo, relations, flag=0, date=None, metadata=None,
969 969 operation=None):
970 970 """Add obsolete markers between changesets in a repo
971 971
972 972 <relations> must be an iterable of ((<old>,...), (<new>, ...)[,{metadata}])
973 973 tuple. `old` and `news` are changectx. metadata is an optional dictionary
974 974 containing metadata for this marker only. It is merged with the global
975 975 metadata specified through the `metadata` argument of this function.
976 976 Any string values in metadata must be UTF-8 bytes.
977 977
978 978 Trying to obsolete a public changeset will raise an exception.
979 979
980 980 Current user and date are used except if specified otherwise in the
981 981 metadata attribute.
982 982
983 983 This function operates within a transaction of its own, but does
984 984 not take any lock on the repo.
985 985 """
986 986 # prepare metadata
987 987 if metadata is None:
988 988 metadata = {}
989 989 if 'user' not in metadata:
990 990 luser = repo.ui.config('devel', 'user.obsmarker') or repo.ui.username()
991 991 metadata['user'] = encoding.fromlocal(luser)
992 992
993 993 # Operation metadata handling
994 994 useoperation = repo.ui.configbool('experimental',
995 995 'evolution.track-operation')
996 996 if useoperation and operation:
997 997 metadata['operation'] = operation
998 998
999 999 # Effect flag metadata handling
1000 1000 saveeffectflag = repo.ui.configbool('experimental',
1001 1001 'evolution.effect-flags')
1002 1002
1003 1003 with repo.transaction('add-obsolescence-marker') as tr:
1004 1004 markerargs = []
1005 1005 for rel in relations:
1006 1006 predecessors = rel[0]
1007 1007 if not isinstance(predecessors, tuple):
1008 1008 # preserve compat with old API until all caller are migrated
1009 1009 predecessors = (predecessors,)
1010 1010 if len(predecessors) > 1 and len(rel[1]) != 1:
1011 1011 msg = 'Fold markers can only have 1 successors, not %d'
1012 1012 raise error.ProgrammingError(msg % len(rel[1]))
1013 1013 foldid = None
1014 1014 foldsize = len(predecessors)
1015 1015 if 1 < foldsize:
1016 1016 foldid = makefoldid(rel, metadata['user'])
1017 1017 for foldidx, prec in enumerate(predecessors, 1):
1018 1018 sucs = rel[1]
1019 1019 localmetadata = metadata.copy()
1020 1020 if len(rel) > 2:
1021 1021 localmetadata.update(rel[2])
1022 1022 if foldid is not None:
1023 1023 localmetadata['fold-id'] = foldid
1024 1024 localmetadata['fold-idx'] = '%d' % foldidx
1025 1025 localmetadata['fold-size'] = '%d' % foldsize
1026 1026
1027 1027 if not prec.mutable():
1028 1028 raise error.Abort(_("cannot obsolete public changeset: %s")
1029 1029 % prec,
1030 1030 hint="see 'hg help phases' for details")
1031 1031 nprec = prec.node()
1032 1032 nsucs = tuple(s.node() for s in sucs)
1033 1033 npare = None
1034 1034 if not nsucs:
1035 1035 npare = tuple(p.node() for p in prec.parents())
1036 1036 if nprec in nsucs:
1037 1037 raise error.Abort(_("changeset %s cannot obsolete itself")
1038 1038 % prec)
1039 1039
1040 1040 # Effect flag can be different by relation
1041 1041 if saveeffectflag:
1042 1042 # The effect flag is saved in a versioned field name for
1043 1043 # future evolution
1044 1044 effectflag = obsutil.geteffectflag(prec, sucs)
1045 1045 localmetadata[obsutil.EFFECTFLAGFIELD] = "%d" % effectflag
1046 1046
1047 1047 # Creating the marker causes the hidden cache to become
1048 1048 # invalid, which causes recomputation when we ask for
1049 1049 # prec.parents() above. Resulting in n^2 behavior. So let's
1050 1050 # prepare all of the args first, then create the markers.
1051 1051 markerargs.append((nprec, nsucs, npare, localmetadata))
1052 1052
1053 1053 for args in markerargs:
1054 1054 nprec, nsucs, npare, localmetadata = args
1055 1055 repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
1056 1056 date=date, metadata=localmetadata,
1057 1057 ui=repo.ui)
1058 1058 repo.filteredrevcache.clear()
@@ -1,1622 +1,1641 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [phases]
3 3 > # public changeset are not obsolete
4 4 > publish=false
5 5 > [ui]
6 6 > logtemplate="{rev}:{node|short} ({phase}{if(obsolete, ' *{obsolete}*')}{if(instabilities, ' {instabilities}')}) [{tags} {bookmarks}] {desc|firstline}{if(obsfate, " [{join(obsfate, "; ")}]")}\n"
7 7 > EOF
8 8 $ mkcommit() {
9 9 > echo "$1" > "$1"
10 10 > hg add "$1"
11 11 > hg ci -m "add $1"
12 12 > }
13 13 $ getid() {
14 14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
15 15 > }
16 16
17 17 $ cat > debugkeys.py <<EOF
18 18 > def reposetup(ui, repo):
19 19 > class debugkeysrepo(repo.__class__):
20 20 > def listkeys(self, namespace):
21 21 > ui.write(b'listkeys %s\n' % (namespace,))
22 22 > return super(debugkeysrepo, self).listkeys(namespace)
23 23 >
24 24 > if repo.local():
25 25 > repo.__class__ = debugkeysrepo
26 26 > EOF
27 27
28 28 $ hg init tmpa
29 29 $ cd tmpa
30 30 $ mkcommit kill_me
31 31
32 32 Checking that the feature is properly disabled
33 33
34 34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 35 abort: creating obsolete markers is not enabled on this repo
36 36 [255]
37 37
38 38 Enabling it
39 39
40 40 $ cat >> $HGRCPATH << EOF
41 41 > [experimental]
42 42 > evolution=exchange
43 43 > evolution.createmarkers=True
44 44 > EOF
45 45
46 46 Killing a single changeset without replacement
47 47
48 48 $ hg debugobsolete 0
49 49 abort: changeset references must be full hexadecimal node identifiers
50 50 [255]
51 51 $ hg debugobsolete '00'
52 52 abort: changeset references must be full hexadecimal node identifiers
53 53 [255]
54 54 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 55 obsoleted 1 changesets
56 56 $ hg debugobsolete
57 57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
58 58
59 59 (test that mercurial is not confused)
60 60
61 61 $ hg up null --quiet # having 0 as parent prevents it to be hidden
62 62 $ hg tip
63 63 -1:000000000000 (public) [tip ]
64 64 $ hg up --hidden tip --quiet
65 65 updated to hidden changeset 97b7c2d76b18
66 66 (hidden revision '97b7c2d76b18' is pruned)
67 67
68 68 Killing a single changeset with itself should fail
69 69 (simple local safeguard)
70 70
71 71 $ hg debugobsolete `getid kill_me` `getid kill_me`
72 72 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
73 73 [255]
74 74
75 75 $ cd ..
76 76
77 77 Killing a single changeset with replacement
78 78 (and testing the format option)
79 79
80 80 $ hg init tmpb
81 81 $ cd tmpb
82 82 $ mkcommit a
83 83 $ mkcommit b
84 84 $ mkcommit original_c
85 85 $ hg up "desc('b')"
86 86 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
87 87 $ mkcommit new_c
88 88 created new head
89 89 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
90 90 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
91 91 obsoleted 1 changesets
92 92 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
93 93 2:245bde4270cd add original_c
94 94 $ hg debugrevlog -cd
95 95 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
96 96 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
97 97 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
98 98 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
99 99 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
100 100 $ hg debugobsolete
101 101 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
102 102
103 103 (check for version number of the obsstore)
104 104
105 105 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
106 106 \x00 (no-eol) (esc)
107 107
108 108 do it again (it read the obsstore before adding new changeset)
109 109
110 110 $ hg up '.^'
111 111 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
112 112 $ mkcommit new_2_c
113 113 created new head
114 114 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
115 115 obsoleted 1 changesets
116 116 $ hg debugobsolete
117 117 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
118 118 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
119 119
120 120 Register two markers with a missing node
121 121
122 122 $ hg up '.^'
123 123 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
124 124 $ mkcommit new_3_c
125 125 created new head
126 126 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
127 127 obsoleted 1 changesets
128 128 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
129 129 $ hg debugobsolete
130 130 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
131 131 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
132 132 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
133 133 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
134 134
135 135 Test the --index option of debugobsolete command
136 136 $ hg debugobsolete --index
137 137 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
138 138 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
139 139 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
140 140 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
141 141
142 142 Refuse pathological nullid successors
143 143 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
144 144 transaction abort!
145 145 rollback completed
146 146 abort: bad obsolescence marker detected: invalid successors nullid
147 147 [255]
148 148
149 149 Check that graphlog detect that a changeset is obsolete:
150 150
151 151 $ hg log -G
152 152 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
153 153 |
154 154 o 1:7c3bad9141dc (draft) [ ] add b
155 155 |
156 156 o 0:1f0dee641bb7 (draft) [ ] add a
157 157
158 158
159 159 check that heads does not report them
160 160
161 161 $ hg heads
162 162 5:5601fb93a350 (draft) [tip ] add new_3_c
163 163 $ hg heads --hidden
164 164 5:5601fb93a350 (draft) [tip ] add new_3_c
165 165 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
166 166 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
167 167 2:245bde4270cd (draft *obsolete*) [ ] add original_c [rewritten as 3:cdbce2fbb163]
168 168
169 169
170 170 check that summary does not report them
171 171
172 172 $ hg init ../sink
173 173 $ echo '[paths]' >> .hg/hgrc
174 174 $ echo 'default=../sink' >> .hg/hgrc
175 175 $ hg summary --remote
176 176 parent: 5:5601fb93a350 tip
177 177 add new_3_c
178 178 branch: default
179 179 commit: (clean)
180 180 update: (current)
181 181 phases: 3 draft
182 182 remote: 3 outgoing
183 183
184 184 $ hg summary --remote --hidden
185 185 parent: 5:5601fb93a350 tip
186 186 add new_3_c
187 187 branch: default
188 188 commit: (clean)
189 189 update: 3 new changesets, 4 branch heads (merge)
190 190 phases: 6 draft
191 191 remote: 3 outgoing
192 192
193 193 check that various commands work well with filtering
194 194
195 195 $ hg tip
196 196 5:5601fb93a350 (draft) [tip ] add new_3_c
197 197 $ hg log -r 6
198 198 abort: unknown revision '6'!
199 199 [255]
200 200 $ hg log -r 4
201 201 abort: hidden revision '4' was rewritten as: 5601fb93a350!
202 202 (use --hidden to access hidden revisions)
203 203 [255]
204 204 $ hg debugrevspec 'rev(6)'
205 205 $ hg debugrevspec 'rev(4)'
206 206 $ hg debugrevspec 'null'
207 207 -1
208 208
209 209 Check that public changeset are not accounted as obsolete:
210 210
211 211 $ hg --hidden phase --public 2
212 212 1 new phase-divergent changesets
213 213 $ hg log -G
214 214 @ 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
215 215 |
216 216 | o 2:245bde4270cd (public) [ ] add original_c
217 217 |/
218 218 o 1:7c3bad9141dc (public) [ ] add b
219 219 |
220 220 o 0:1f0dee641bb7 (public) [ ] add a
221 221
222 222
223 223 And that bumped changeset are detected
224 224 --------------------------------------
225 225
226 226 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
227 227 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
228 228 the public changeset
229 229
230 230 $ hg log --hidden -r 'phasedivergent()'
231 231 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
232 232
233 233 And that we can't push bumped changeset
234 234
235 235 $ hg push ../tmpa -r 0 --force #(make repo related)
236 236 pushing to ../tmpa
237 237 searching for changes
238 238 warning: repository is unrelated
239 239 adding changesets
240 240 adding manifests
241 241 adding file changes
242 242 added 1 changesets with 1 changes to 1 files (+1 heads)
243 243 $ hg push ../tmpa
244 244 pushing to ../tmpa
245 245 searching for changes
246 246 abort: push includes phase-divergent changeset: 5601fb93a350!
247 247 [255]
248 248
249 249 Fixing "bumped" situation
250 250 We need to create a clone of 5 and add a special marker with a flag
251 251
252 252 $ hg summary
253 253 parent: 5:5601fb93a350 tip (phase-divergent)
254 254 add new_3_c
255 255 branch: default
256 256 commit: (clean)
257 257 update: 1 new changesets, 2 branch heads (merge)
258 258 phases: 1 draft
259 259 phase-divergent: 1 changesets
260 260 $ hg up '5^'
261 261 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 262 $ hg revert -ar 5
263 263 adding new_3_c
264 264 $ hg ci -m 'add n3w_3_c'
265 265 created new head
266 266 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
267 267 obsoleted 1 changesets
268 268 $ hg log -r 'phasedivergent()'
269 269 $ hg log -G
270 270 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
271 271 |
272 272 | o 2:245bde4270cd (public) [ ] add original_c
273 273 |/
274 274 o 1:7c3bad9141dc (public) [ ] add b
275 275 |
276 276 o 0:1f0dee641bb7 (public) [ ] add a
277 277
278 278
279 279 Basic exclusive testing
280 280
281 281 $ hg log -G --hidden
282 282 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
283 283 |
284 284 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
285 285 |/
286 286 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
287 287 |/
288 288 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
289 289 |/
290 290 | o 2:245bde4270cd (public) [ ] add original_c
291 291 |/
292 292 o 1:7c3bad9141dc (public) [ ] add b
293 293 |
294 294 o 0:1f0dee641bb7 (public) [ ] add a
295 295
296 296 $ hg debugobsolete --rev 6f9641995072
297 297 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
298 298 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
299 299 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
300 300 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
301 301 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
302 302 $ hg debugobsolete --rev 6f9641995072 --exclusive
303 303 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
304 304 $ hg debugobsolete --rev 5601fb93a350 --hidden
305 305 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
306 306 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
307 307 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
308 308 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
309 309 $ hg debugobsolete --rev 5601fb93a350 --hidden --exclusive
310 310 $ hg debugobsolete --rev 5601fb93a350+6f9641995072 --hidden --exclusive
311 311 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
312 312 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
313 313 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
314 314
315 315 $ cd ..
316 316
317 317 Revision 0 is hidden
318 318 --------------------
319 319
320 320 $ hg init rev0hidden
321 321 $ cd rev0hidden
322 322
323 323 $ mkcommit kill0
324 324 $ hg up -q null
325 325 $ hg debugobsolete `getid kill0`
326 326 obsoleted 1 changesets
327 327 $ mkcommit a
328 328 $ mkcommit b
329 329
330 330 Should pick the first visible revision as "repo" node
331 331
332 332 $ hg archive ../archive-null
333 333 $ cat ../archive-null/.hg_archival.txt
334 334 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
335 335 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
336 336 branch: default
337 337 latesttag: null
338 338 latesttagdistance: 2
339 339 changessincelatesttag: 2
340 340
341 341
342 342 $ cd ..
343 343
344 344 Can disable transaction summary report
345 345
346 346 $ hg init transaction-summary
347 347 $ cd transaction-summary
348 348 $ mkcommit a
349 349 $ mkcommit b
350 350 $ hg up -q null
351 351 $ hg --config experimental.evolution.report-instabilities=false debugobsolete `getid a`
352 352 obsoleted 1 changesets
353 353 $ cd ..
354 354
355 355 Exchange Test
356 356 ============================
357 357
358 358 Destination repo does not have any data
359 359 ---------------------------------------
360 360
361 361 Simple incoming test
362 362
363 363 $ hg init tmpc
364 364 $ cd tmpc
365 365 $ hg incoming ../tmpb
366 366 comparing with ../tmpb
367 367 0:1f0dee641bb7 (public) [ ] add a
368 368 1:7c3bad9141dc (public) [ ] add b
369 369 2:245bde4270cd (public) [ ] add original_c
370 370 6:6f9641995072 (draft) [tip ] add n3w_3_c
371 371
372 372 Try to pull markers
373 373 (extinct changeset are excluded but marker are pushed)
374 374
375 375 $ hg pull ../tmpb
376 376 pulling from ../tmpb
377 377 requesting all changes
378 378 adding changesets
379 379 adding manifests
380 380 adding file changes
381 381 added 4 changesets with 4 changes to 4 files (+1 heads)
382 382 5 new obsolescence markers
383 383 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
384 384 (run 'hg heads' to see heads, 'hg merge' to merge)
385 385 $ hg debugobsolete
386 386 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
387 387 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
388 388 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
389 389 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
390 390 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
391 391
392 392 Rollback//Transaction support
393 393
394 394 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
395 395 $ hg debugobsolete
396 396 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
397 397 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
398 398 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
399 399 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
400 400 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
401 401 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
402 402 $ hg rollback -n
403 403 repository tip rolled back to revision 3 (undo debugobsolete)
404 404 $ hg rollback
405 405 repository tip rolled back to revision 3 (undo debugobsolete)
406 406 $ hg debugobsolete
407 407 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
408 408 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
409 409 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
410 410 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
411 411 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
412 412
413 413 $ cd ..
414 414
415 415 Try to push markers
416 416
417 417 $ hg init tmpd
418 418 $ hg -R tmpb push tmpd
419 419 pushing to tmpd
420 420 searching for changes
421 421 adding changesets
422 422 adding manifests
423 423 adding file changes
424 424 added 4 changesets with 4 changes to 4 files (+1 heads)
425 425 5 new obsolescence markers
426 426 $ hg -R tmpd debugobsolete | sort
427 427 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
428 428 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
429 429 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
430 430 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
431 431 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
432 432
433 433 Check obsolete keys are exchanged only if source has an obsolete store
434 434
435 435 $ hg init empty
436 436 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
437 437 pushing to tmpd
438 438 listkeys phases
439 439 listkeys bookmarks
440 440 no changes found
441 441 listkeys phases
442 442 [1]
443 443
444 444 clone support
445 445 (markers are copied and extinct changesets are included to allow hardlinks)
446 446
447 447 $ hg clone tmpb clone-dest
448 448 updating to branch default
449 449 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 450 $ hg -R clone-dest log -G --hidden
451 451 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
452 452 |
453 453 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
454 454 |/
455 455 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
456 456 |/
457 457 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
458 458 |/
459 459 | o 2:245bde4270cd (public) [ ] add original_c
460 460 |/
461 461 o 1:7c3bad9141dc (public) [ ] add b
462 462 |
463 463 o 0:1f0dee641bb7 (public) [ ] add a
464 464
465 465 $ hg -R clone-dest debugobsolete
466 466 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
467 467 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
468 468 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
469 469 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
470 470 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
471 471
472 472
473 473 Destination repo have existing data
474 474 ---------------------------------------
475 475
476 476 On pull
477 477
478 478 $ hg init tmpe
479 479 $ cd tmpe
480 480 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
481 481 $ hg pull ../tmpb
482 482 pulling from ../tmpb
483 483 requesting all changes
484 484 adding changesets
485 485 adding manifests
486 486 adding file changes
487 487 added 4 changesets with 4 changes to 4 files (+1 heads)
488 488 5 new obsolescence markers
489 489 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
490 490 (run 'hg heads' to see heads, 'hg merge' to merge)
491 491 $ hg debugobsolete
492 492 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
493 493 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
494 494 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
495 495 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
496 496 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
497 497 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
498 498
499 499
500 500 On push
501 501
502 502 $ hg push ../tmpc
503 503 pushing to ../tmpc
504 504 searching for changes
505 505 no changes found
506 506 1 new obsolescence markers
507 507 [1]
508 508 $ hg -R ../tmpc debugobsolete
509 509 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
510 510 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
511 511 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
512 512 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
513 513 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
514 514 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
515 515
516 516 detect outgoing obsolete and unstable
517 517 ---------------------------------------
518 518
519 519
520 520 $ hg log -G
521 521 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
522 522 |
523 523 | o 2:245bde4270cd (public) [ ] add original_c
524 524 |/
525 525 o 1:7c3bad9141dc (public) [ ] add b
526 526 |
527 527 o 0:1f0dee641bb7 (public) [ ] add a
528 528
529 529 $ hg up 'desc("n3w_3_c")'
530 530 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 531 $ mkcommit original_d
532 532 $ mkcommit original_e
533 533 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
534 534 obsoleted 1 changesets
535 535 1 new orphan changesets
536 536 $ hg debugobsolete | grep `getid original_d`
537 537 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
538 538 $ hg log -r 'obsolete()'
539 539 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
540 540 $ hg summary
541 541 parent: 5:cda648ca50f5 tip (orphan)
542 542 add original_e
543 543 branch: default
544 544 commit: (clean)
545 545 update: 1 new changesets, 2 branch heads (merge)
546 546 phases: 3 draft
547 547 orphan: 1 changesets
548 548 $ hg log -G -r '::orphan()'
549 549 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
550 550 |
551 551 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
552 552 |
553 553 o 3:6f9641995072 (draft) [ ] add n3w_3_c
554 554 |
555 555 o 1:7c3bad9141dc (public) [ ] add b
556 556 |
557 557 o 0:1f0dee641bb7 (public) [ ] add a
558 558
559 559
560 560 refuse to push obsolete changeset
561 561
562 562 $ hg push ../tmpc/ -r 'desc("original_d")'
563 563 pushing to ../tmpc/
564 564 searching for changes
565 565 abort: push includes obsolete changeset: 94b33453f93b!
566 566 [255]
567 567
568 568 refuse to push unstable changeset
569 569
570 570 $ hg push ../tmpc/
571 571 pushing to ../tmpc/
572 572 searching for changes
573 573 abort: push includes orphan changeset: cda648ca50f5!
574 574 [255]
575 575
576 576 Test that extinct changeset are properly detected
577 577
578 578 $ hg log -r 'extinct()'
579 579
580 580 Don't try to push extinct changeset
581 581
582 582 $ hg init ../tmpf
583 583 $ hg out ../tmpf
584 584 comparing with ../tmpf
585 585 searching for changes
586 586 0:1f0dee641bb7 (public) [ ] add a
587 587 1:7c3bad9141dc (public) [ ] add b
588 588 2:245bde4270cd (public) [ ] add original_c
589 589 3:6f9641995072 (draft) [ ] add n3w_3_c
590 590 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
591 591 5:cda648ca50f5 (draft orphan) [tip ] add original_e
592 592 $ hg push ../tmpf -f # -f because be push unstable too
593 593 pushing to ../tmpf
594 594 searching for changes
595 595 adding changesets
596 596 adding manifests
597 597 adding file changes
598 598 added 6 changesets with 6 changes to 6 files (+1 heads)
599 599 7 new obsolescence markers
600 600 1 new orphan changesets
601 601
602 602 no warning displayed
603 603
604 604 $ hg push ../tmpf
605 605 pushing to ../tmpf
606 606 searching for changes
607 607 no changes found
608 608 [1]
609 609
610 610 Do not warn about new head when the new head is a successors of a remote one
611 611
612 612 $ hg log -G
613 613 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
614 614 |
615 615 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
616 616 |
617 617 o 3:6f9641995072 (draft) [ ] add n3w_3_c
618 618 |
619 619 | o 2:245bde4270cd (public) [ ] add original_c
620 620 |/
621 621 o 1:7c3bad9141dc (public) [ ] add b
622 622 |
623 623 o 0:1f0dee641bb7 (public) [ ] add a
624 624
625 625 $ hg up -q 'desc(n3w_3_c)'
626 626 $ mkcommit obsolete_e
627 627 created new head
628 628 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'` \
629 629 > -u 'test <test@example.net>'
630 630 obsoleted 1 changesets
631 631 $ hg outgoing ../tmpf # parasite hg outgoing testin
632 632 comparing with ../tmpf
633 633 searching for changes
634 634 6:3de5eca88c00 (draft) [tip ] add obsolete_e
635 635 $ hg push ../tmpf
636 636 pushing to ../tmpf
637 637 searching for changes
638 638 adding changesets
639 639 adding manifests
640 640 adding file changes
641 641 added 1 changesets with 1 changes to 1 files (+1 heads)
642 642 1 new obsolescence markers
643 643 obsoleted 1 changesets
644 644
645 645 test relevance computation
646 646 ---------------------------------------
647 647
648 648 Checking simple case of "marker relevance".
649 649
650 650
651 651 Reminder of the repo situation
652 652
653 653 $ hg log --hidden --graph
654 654 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
655 655 |
656 656 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e [rewritten as 6:3de5eca88c00 by test <test@example.net>]
657 657 | |
658 658 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
659 659 |/
660 660 o 3:6f9641995072 (draft) [ ] add n3w_3_c
661 661 |
662 662 | o 2:245bde4270cd (public) [ ] add original_c
663 663 |/
664 664 o 1:7c3bad9141dc (public) [ ] add b
665 665 |
666 666 o 0:1f0dee641bb7 (public) [ ] add a
667 667
668 668
669 669 List of all markers
670 670
671 671 $ hg debugobsolete
672 672 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
673 673 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
674 674 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
675 675 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
676 676 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
677 677 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
678 678 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
679 679 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
680 680
681 681 List of changesets with no chain
682 682
683 683 $ hg debugobsolete --hidden --rev ::2
684 684
685 685 List of changesets that are included on marker chain
686 686
687 687 $ hg debugobsolete --hidden --rev 6
688 688 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
689 689
690 690 List of changesets with a longer chain, (including a pruned children)
691 691
692 692 $ hg debugobsolete --hidden --rev 3
693 693 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
694 694 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
695 695 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
696 696 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
697 697 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
698 698 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
699 699 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
700 700
701 701 List of both
702 702
703 703 $ hg debugobsolete --hidden --rev 3::6
704 704 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
705 705 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
706 706 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
707 707 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
708 708 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
709 709 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
710 710 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
711 711 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
712 712
713 713 List of all markers in JSON
714 714
715 715 $ hg debugobsolete -Tjson
716 716 [
717 717 {
718 718 "date": [1339, 0],
719 719 "flag": 0,
720 720 "metadata": {"user": "test"},
721 721 "prednode": "1339133913391339133913391339133913391339",
722 722 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
723 723 },
724 724 {
725 725 "date": [1339, 0],
726 726 "flag": 0,
727 727 "metadata": {"user": "test"},
728 728 "prednode": "1337133713371337133713371337133713371337",
729 729 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
730 730 },
731 731 {
732 732 "date": [121, 120],
733 733 "flag": 12,
734 734 "metadata": {"user": "test"},
735 735 "prednode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
736 736 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
737 737 },
738 738 {
739 739 "date": [1338, 0],
740 740 "flag": 1,
741 741 "metadata": {"user": "test"},
742 742 "prednode": "5601fb93a350734d935195fee37f4054c529ff39",
743 743 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
744 744 },
745 745 {
746 746 "date": [1338, 0],
747 747 "flag": 0,
748 748 "metadata": {"user": "test"},
749 749 "prednode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
750 750 "succnodes": ["1337133713371337133713371337133713371337"]
751 751 },
752 752 {
753 753 "date": [1337, 0],
754 754 "flag": 0,
755 755 "metadata": {"user": "test"},
756 756 "prednode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
757 757 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
758 758 },
759 759 {
760 760 "date": [0, 0],
761 761 "flag": 0,
762 762 "metadata": {"user": "test"},
763 763 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
764 764 "prednode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
765 765 "succnodes": []
766 766 },
767 767 {
768 768 "date": *, (glob)
769 769 "flag": 0,
770 770 "metadata": {"user": "test <test@example.net>"},
771 771 "prednode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
772 772 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
773 773 }
774 774 ]
775 775
776 776 Template keywords
777 777
778 778 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
779 779 3de5eca88c00 ????-??-?? (glob)
780 780 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
781 781 user=test <test@example.net>
782 782 $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n'
783 783 'user': 'test <test@example.net>'
784 784 'user': 'test <test@example.net>'
785 785 $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n'
786 786 3de5eca88c00aa039da7399a220f4a5221faa585
787 787 3de5eca88c00aa039da7399a220f4a5221faa585
788 788 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
789 789 0 test <test@example.net>
790 790
791 791 Test the debug output for exchange
792 792 ----------------------------------
793 793
794 794 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
795 795 pulling from ../tmpb
796 796 searching for changes
797 797 no changes found
798 798 obsmarker-exchange: 346 bytes received
799 799
800 800 check hgweb does not explode
801 801 ====================================
802 802
803 803 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
804 804 adding changesets
805 805 adding manifests
806 806 adding file changes
807 807 added 62 changesets with 63 changes to 9 files (+60 heads)
808 808 new changesets 50c51b361e60:c15e9edfca13 (62 drafts)
809 809 (2 other changesets obsolete on arrival)
810 810 (run 'hg heads .' to see heads, 'hg merge' to merge)
811 811 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
812 812 > do
813 813 > hg debugobsolete $node
814 814 > done
815 815 obsoleted 1 changesets
816 816 obsoleted 1 changesets
817 817 obsoleted 1 changesets
818 818 obsoleted 1 changesets
819 819 obsoleted 1 changesets
820 820 obsoleted 1 changesets
821 821 obsoleted 1 changesets
822 822 obsoleted 1 changesets
823 823 obsoleted 1 changesets
824 824 obsoleted 1 changesets
825 825 obsoleted 1 changesets
826 826 obsoleted 1 changesets
827 827 obsoleted 1 changesets
828 828 obsoleted 1 changesets
829 829 obsoleted 1 changesets
830 830 obsoleted 1 changesets
831 831 obsoleted 1 changesets
832 832 obsoleted 1 changesets
833 833 obsoleted 1 changesets
834 834 obsoleted 1 changesets
835 835 obsoleted 1 changesets
836 836 obsoleted 1 changesets
837 837 obsoleted 1 changesets
838 838 obsoleted 1 changesets
839 839 obsoleted 1 changesets
840 840 obsoleted 1 changesets
841 841 obsoleted 1 changesets
842 842 obsoleted 1 changesets
843 843 obsoleted 1 changesets
844 844 obsoleted 1 changesets
845 845 obsoleted 1 changesets
846 846 obsoleted 1 changesets
847 847 obsoleted 1 changesets
848 848 obsoleted 1 changesets
849 849 obsoleted 1 changesets
850 850 obsoleted 1 changesets
851 851 obsoleted 1 changesets
852 852 obsoleted 1 changesets
853 853 obsoleted 1 changesets
854 854 obsoleted 1 changesets
855 855 obsoleted 1 changesets
856 856 obsoleted 1 changesets
857 857 obsoleted 1 changesets
858 858 obsoleted 1 changesets
859 859 obsoleted 1 changesets
860 860 obsoleted 1 changesets
861 861 obsoleted 1 changesets
862 862 obsoleted 1 changesets
863 863 obsoleted 1 changesets
864 864 obsoleted 1 changesets
865 865 obsoleted 1 changesets
866 866 obsoleted 1 changesets
867 867 obsoleted 1 changesets
868 868 obsoleted 1 changesets
869 869 obsoleted 1 changesets
870 870 obsoleted 1 changesets
871 871 obsoleted 1 changesets
872 872 obsoleted 1 changesets
873 873 obsoleted 1 changesets
874 874 obsoleted 1 changesets
875 875 $ hg up tip
876 876 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
877 877
878 878 #if serve
879 879
880 880 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
881 881 $ cat hg.pid >> $DAEMON_PIDS
882 882
883 883 check changelog view
884 884
885 885 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
886 886 200 Script output follows
887 887
888 888 check graph view
889 889
890 890 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
891 891 200 Script output follows
892 892
893 893 check filelog view
894 894
895 895 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
896 896 200 Script output follows
897 897
898 898 check filelog view for hidden commits (obsolete ones are hidden here)
899 899
900 900 $ get-with-headers.py localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar' | grep obsolete
901 901 [1]
902 902
903 903 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
904 904 200 Script output follows
905 905 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
906 906 404 Not Found
907 907 [1]
908 908
909 909 check that web.view config option:
910 910
911 911 $ killdaemons.py hg.pid
912 912 $ cat >> .hg/hgrc << EOF
913 913 > [web]
914 914 > view=all
915 915 > EOF
916 916 $ wait
917 917 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
918 918 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
919 919 200 Script output follows
920 920 $ killdaemons.py hg.pid
921 921
922 922 Checking _enable=False warning if obsolete marker exists
923 923
924 924 $ echo '[experimental]' >> $HGRCPATH
925 925 $ echo "evolution=" >> $HGRCPATH
926 926 $ hg log -r tip
927 927 68:c15e9edfca13 (draft) [tip ] add celestine
928 928
929 929 reenable for later test
930 930
931 931 $ echo '[experimental]' >> $HGRCPATH
932 932 $ echo "evolution.exchange=True" >> $HGRCPATH
933 933 $ echo "evolution.createmarkers=True" >> $HGRCPATH
934 934
935 935 $ rm access.log errors.log
936 936 #endif
937 937
938 938 Several troubles on the same changeset (create an unstable and bumped changeset)
939 939
940 940 $ hg debugobsolete `getid obsolete_e`
941 941 obsoleted 1 changesets
942 942 2 new orphan changesets
943 943 $ hg debugobsolete `getid original_c` `getid babar`
944 944 1 new phase-divergent changesets
945 945 $ hg log --config ui.logtemplate= -r 'phasedivergent() and orphan()'
946 946 changeset: 7:50c51b361e60
947 947 user: test
948 948 date: Thu Jan 01 00:00:00 1970 +0000
949 949 instability: orphan, phase-divergent
950 950 summary: add babar
951 951
952 952
953 953 test the "obsolete" templatekw
954 954
955 955 $ hg log -r 'obsolete()'
956 956 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e [pruned]
957 957
958 958 test the "troubles" templatekw
959 959
960 960 $ hg log -r 'phasedivergent() and orphan()'
961 961 7:50c51b361e60 (draft orphan phase-divergent) [ ] add babar
962 962
963 963 test the default cmdline template
964 964
965 965 $ hg log -T default -r 'phasedivergent()'
966 966 changeset: 7:50c51b361e60
967 967 user: test
968 968 date: Thu Jan 01 00:00:00 1970 +0000
969 969 instability: orphan, phase-divergent
970 970 summary: add babar
971 971
972 972 $ hg log -T default -r 'obsolete()'
973 973 changeset: 6:3de5eca88c00
974 974 parent: 3:6f9641995072
975 975 user: test
976 976 date: Thu Jan 01 00:00:00 1970 +0000
977 977 obsolete: pruned
978 978 summary: add obsolete_e
979 979
980 980
981 981 test the obsolete labels
982 982
983 983 $ hg log --config ui.logtemplate= --color=debug -r 'phasedivergent()'
984 984 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
985 985 [log.user|user: test]
986 986 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
987 987 [log.instability|instability: orphan, phase-divergent]
988 988 [log.summary|summary: add babar]
989 989
990 990
991 991 $ hg log -T default -r 'phasedivergent()' --color=debug
992 992 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent|changeset: 7:50c51b361e60]
993 993 [log.user|user: test]
994 994 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
995 995 [log.instability|instability: orphan, phase-divergent]
996 996 [log.summary|summary: add babar]
997 997
998 998
999 999 $ hg log --config ui.logtemplate= --color=debug -r "obsolete()"
1000 1000 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1001 1001 [log.parent changeset.draft|parent: 3:6f9641995072]
1002 1002 [log.user|user: test]
1003 1003 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1004 1004 [log.obsfate|obsolete: pruned]
1005 1005 [log.summary|summary: add obsolete_e]
1006 1006
1007 1007
1008 1008 $ hg log -T default -r 'obsolete()' --color=debug
1009 1009 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1010 1010 [log.parent changeset.draft|parent: 3:6f9641995072]
1011 1011 [log.user|user: test]
1012 1012 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1013 1013 [log.obsfate|obsolete: pruned]
1014 1014 [log.summary|summary: add obsolete_e]
1015 1015
1016 1016
1017 1017 test summary output
1018 1018
1019 1019 $ hg up -r 'phasedivergent() and orphan()'
1020 1020 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1021 1021 $ hg summary
1022 1022 parent: 7:50c51b361e60 (orphan, phase-divergent)
1023 1023 add babar
1024 1024 branch: default
1025 1025 commit: (clean)
1026 1026 update: 2 new changesets (update)
1027 1027 phases: 4 draft
1028 1028 orphan: 2 changesets
1029 1029 phase-divergent: 1 changesets
1030 1030 $ hg up -r 'obsolete()'
1031 1031 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1032 1032 $ hg summary
1033 1033 parent: 6:3de5eca88c00 (obsolete)
1034 1034 add obsolete_e
1035 1035 branch: default
1036 1036 commit: (clean)
1037 1037 update: 3 new changesets (update)
1038 1038 phases: 4 draft
1039 1039 orphan: 2 changesets
1040 1040 phase-divergent: 1 changesets
1041 1041
1042 1042 test debugwhyunstable output
1043 1043
1044 1044 $ hg debugwhyunstable 50c51b361e60
1045 1045 orphan: obsolete parent 3de5eca88c00aa039da7399a220f4a5221faa585
1046 1046 phase-divergent: immutable predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca
1047 1047
1048 1048 test whyunstable template keyword
1049 1049
1050 1050 $ hg log -r 50c51b361e60 -T '{whyunstable}\n'
1051 1051 orphan: obsolete parent 3de5eca88c00
1052 1052 phase-divergent: immutable predecessor 245bde4270cd
1053 1053 $ hg log -r 50c51b361e60 -T '{whyunstable % "{instability}: {reason} {node|shortest}\n"}'
1054 1054 orphan: obsolete parent 3de5
1055 1055 phase-divergent: immutable predecessor 245b
1056 1056
1057 1057 #if serve
1058 1058
1059 1059 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1060 1060 $ cat hg.pid >> $DAEMON_PIDS
1061 1061
1062 1062 check obsolete changeset
1063 1063
1064 1064 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=paper' | grep '<span class="obsolete">'
1065 1065 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1066 1066 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=coal' | grep '<span class="obsolete">'
1067 1067 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1068 1068 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=gitweb' | grep '<span class="logtags">'
1069 1069 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1070 1070 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=monoblue' | grep '<span class="logtags">'
1071 1071 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1072 1072 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
1073 1073 <th class="obsolete">obsolete:</th>
1074 1074 <td class="obsolete">pruned by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
1075 1075
1076 1076 check changeset with instabilities
1077 1077
1078 1078 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=paper' | grep '<span class="instability">'
1079 1079 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1080 1080 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=coal' | grep '<span class="instability">'
1081 1081 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span>
1082 1082 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=gitweb' | grep '<span class="logtags">'
1083 1083 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1084 1084 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=monoblue' | grep '<span class="logtags">'
1085 1085 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> </span>
1086 1086 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=spartan' | grep 'class="unstable"'
1087 1087 <th class="unstable">unstable:</th>
1088 1088 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1089 1089 <th class="unstable">unstable:</th>
1090 1090 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1091 1091
1092 1092 check explanation for an orphan and phase-divergent changeset
1093 1093
1094 1094 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=paper' | egrep '(orphan|phase-divergent):'
1095 1095 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=paper">3de5eca88c00</a><br>
1096 1096 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=paper">245bde4270cd</a></td>
1097 1097 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=coal' | egrep '(orphan|phase-divergent):'
1098 1098 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=coal">3de5eca88c00</a><br>
1099 1099 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=coal">245bde4270cd</a></td>
1100 1100 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=gitweb' | egrep '(orphan|phase-divergent):'
1101 1101 <td>orphan: obsolete parent <a class="list" href="/rev/3de5eca88c00?style=gitweb">3de5eca88c00</a></td>
1102 1102 <td>phase-divergent: immutable predecessor <a class="list" href="/rev/245bde4270cd?style=gitweb">245bde4270cd</a></td>
1103 1103 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=monoblue' | egrep '(orphan|phase-divergent):'
1104 1104 <dd>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=monoblue">3de5eca88c00</a></dd>
1105 1105 <dd>phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=monoblue">245bde4270cd</a></dd>
1106 1106 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=spartan' | egrep '(orphan|phase-divergent):'
1107 1107 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1108 1108 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1109 1109
1110 1110 $ killdaemons.py
1111 1111
1112 1112 $ rm hg.pid access.log errors.log
1113 1113
1114 1114 #endif
1115 1115
1116 1116 Test incoming/outcoming with changesets obsoleted remotely, known locally
1117 1117 ===============================================================================
1118 1118
1119 1119 This test issue 3805
1120 1120
1121 1121 $ hg init repo-issue3805
1122 1122 $ cd repo-issue3805
1123 1123 $ echo "base" > base
1124 1124 $ hg ci -Am "base"
1125 1125 adding base
1126 1126 $ echo "foo" > foo
1127 1127 $ hg ci -Am "A"
1128 1128 adding foo
1129 1129 $ hg clone . ../other-issue3805
1130 1130 updating to branch default
1131 1131 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1132 1132 $ echo "bar" >> foo
1133 1133 $ hg ci --amend
1134 1134 $ cd ../other-issue3805
1135 1135 $ hg log -G
1136 1136 @ 1:29f0c6921ddd (draft) [tip ] A
1137 1137 |
1138 1138 o 0:d20a80d4def3 (draft) [ ] base
1139 1139
1140 1140 $ hg log -G -R ../repo-issue3805
1141 1141 @ 2:323a9c3ddd91 (draft) [tip ] A
1142 1142 |
1143 1143 o 0:d20a80d4def3 (draft) [ ] base
1144 1144
1145 1145 $ hg incoming
1146 1146 comparing with $TESTTMP/tmpe/repo-issue3805
1147 1147 searching for changes
1148 1148 2:323a9c3ddd91 (draft) [tip ] A
1149 1149 $ hg incoming --bundle ../issue3805.hg
1150 1150 comparing with $TESTTMP/tmpe/repo-issue3805
1151 1151 searching for changes
1152 1152 2:323a9c3ddd91 (draft) [tip ] A
1153 1153 $ hg outgoing
1154 1154 comparing with $TESTTMP/tmpe/repo-issue3805
1155 1155 searching for changes
1156 1156 1:29f0c6921ddd (draft) [tip ] A
1157 1157
1158 1158 #if serve
1159 1159
1160 1160 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1161 1161 $ cat hg.pid >> $DAEMON_PIDS
1162 1162
1163 1163 $ hg incoming http://localhost:$HGPORT
1164 1164 comparing with http://localhost:$HGPORT/
1165 1165 searching for changes
1166 1166 2:323a9c3ddd91 (draft) [tip ] A
1167 1167 $ hg outgoing http://localhost:$HGPORT
1168 1168 comparing with http://localhost:$HGPORT/
1169 1169 searching for changes
1170 1170 1:29f0c6921ddd (draft) [tip ] A
1171 1171
1172 1172 $ killdaemons.py
1173 1173
1174 1174 #endif
1175 1175
1176 1176 This test issue 3814
1177 1177
1178 1178 (nothing to push but locally hidden changeset)
1179 1179
1180 1180 $ cd ..
1181 1181 $ hg init repo-issue3814
1182 1182 $ cd repo-issue3805
1183 1183 $ hg push -r 323a9c3ddd91 ../repo-issue3814
1184 1184 pushing to ../repo-issue3814
1185 1185 searching for changes
1186 1186 adding changesets
1187 1187 adding manifests
1188 1188 adding file changes
1189 1189 added 2 changesets with 2 changes to 2 files
1190 1190 1 new obsolescence markers
1191 1191 $ hg out ../repo-issue3814
1192 1192 comparing with ../repo-issue3814
1193 1193 searching for changes
1194 1194 no changes found
1195 1195 [1]
1196 1196
1197 1197 Test that a local tag blocks a changeset from being hidden
1198 1198
1199 1199 $ hg tag -l visible -r 1 --hidden
1200 1200 $ hg log -G
1201 1201 @ 2:323a9c3ddd91 (draft) [tip ] A
1202 1202 |
1203 1203 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A [rewritten using amend as 2:323a9c3ddd91]
1204 1204 |/
1205 1205 o 0:d20a80d4def3 (draft) [ ] base
1206 1206
1207 1207 Test that removing a local tag does not cause some commands to fail
1208 1208
1209 1209 $ hg tag -l -r tip tiptag
1210 1210 $ hg tags
1211 1211 tiptag 2:323a9c3ddd91
1212 1212 tip 2:323a9c3ddd91
1213 1213 visible 1:29f0c6921ddd
1214 1214 $ hg --config extensions.strip= strip -r tip --no-backup
1215 1215 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1216 1216 $ hg tags
1217 1217 visible 1:29f0c6921ddd
1218 1218 tip 1:29f0c6921ddd
1219 1219
1220 1220 Test bundle overlay onto hidden revision
1221 1221
1222 1222 $ cd ..
1223 1223 $ hg init repo-bundleoverlay
1224 1224 $ cd repo-bundleoverlay
1225 1225 $ echo "A" > foo
1226 1226 $ hg ci -Am "A"
1227 1227 adding foo
1228 1228 $ echo "B" >> foo
1229 1229 $ hg ci -m "B"
1230 1230 $ hg up 0
1231 1231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1232 1232 $ echo "C" >> foo
1233 1233 $ hg ci -m "C"
1234 1234 created new head
1235 1235 $ hg log -G
1236 1236 @ 2:c186d7714947 (draft) [tip ] C
1237 1237 |
1238 1238 | o 1:44526ebb0f98 (draft) [ ] B
1239 1239 |/
1240 1240 o 0:4b34ecfb0d56 (draft) [ ] A
1241 1241
1242 1242
1243 1243 $ hg clone -r1 . ../other-bundleoverlay
1244 1244 adding changesets
1245 1245 adding manifests
1246 1246 adding file changes
1247 1247 added 2 changesets with 2 changes to 1 files
1248 1248 new changesets 4b34ecfb0d56:44526ebb0f98 (2 drafts)
1249 1249 updating to branch default
1250 1250 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1251 1251 $ cd ../other-bundleoverlay
1252 1252 $ echo "B+" >> foo
1253 1253 $ hg ci --amend -m "B+"
1254 1254 $ hg log -G --hidden
1255 1255 @ 2:b7d587542d40 (draft) [tip ] B+
1256 1256 |
1257 1257 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B [rewritten using amend as 2:b7d587542d40]
1258 1258 |/
1259 1259 o 0:4b34ecfb0d56 (draft) [ ] A
1260 1260
1261 1261
1262 1262 #if repobundlerepo
1263 1263 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1264 1264 comparing with ../repo-bundleoverlay
1265 1265 searching for changes
1266 1266 1:44526ebb0f98 (draft) [ ] B
1267 1267 2:c186d7714947 (draft) [tip ] C
1268 1268 $ hg log -G -R ../bundleoverlay.hg
1269 1269 o 3:c186d7714947 (draft) [tip ] C
1270 1270 |
1271 1271 | @ 2:b7d587542d40 (draft) [ ] B+
1272 1272 |/
1273 1273 o 0:4b34ecfb0d56 (draft) [ ] A
1274 1274
1275 1275 #endif
1276 1276
1277 1277 #if serve
1278 1278
1279 1279 Test issue 4506
1280 1280
1281 1281 $ cd ..
1282 1282 $ hg init repo-issue4506
1283 1283 $ cd repo-issue4506
1284 1284 $ echo "0" > foo
1285 1285 $ hg add foo
1286 1286 $ hg ci -m "content-0"
1287 1287
1288 1288 $ hg up null
1289 1289 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1290 1290 $ echo "1" > bar
1291 1291 $ hg add bar
1292 1292 $ hg ci -m "content-1"
1293 1293 created new head
1294 1294 $ hg up 0
1295 1295 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1296 1296 $ hg graft 1
1297 1297 grafting 1:1c9eddb02162 "content-1" (tip)
1298 1298
1299 1299 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1300 1300 obsoleted 1 changesets
1301 1301
1302 1302 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1303 1303 $ cat hg.pid >> $DAEMON_PIDS
1304 1304
1305 1305 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1306 1306 404 Not Found
1307 1307 [1]
1308 1308 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1309 1309 200 Script output follows
1310 1310 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1311 1311 200 Script output follows
1312 1312
1313 1313 $ killdaemons.py
1314 1314
1315 1315 #endif
1316 1316
1317 1317 Test heads computation on pending index changes with obsolescence markers
1318 1318 $ cd ..
1319 1319 $ cat >$TESTTMP/test_extension.py << EOF
1320 1320 > from __future__ import absolute_import
1321 1321 > from mercurial.i18n import _
1322 1322 > from mercurial import cmdutil, pycompat, registrar
1323 1323 > from mercurial.utils import stringutil
1324 1324 >
1325 1325 > cmdtable = {}
1326 1326 > command = registrar.command(cmdtable)
1327 1327 > @command(b"amendtransient",[], _(b'hg amendtransient [rev]'))
1328 1328 > def amend(ui, repo, *pats, **opts):
1329 1329 > opts = pycompat.byteskwargs(opts)
1330 1330 > opts[b'message'] = b'Test'
1331 1331 > opts[b'logfile'] = None
1332 1332 > cmdutil.amend(ui, repo, repo[b'.'], {}, pats, opts)
1333 1333 > ui.write(b'%s\n' % stringutil.pprint(repo.changelog.headrevs()))
1334 1334 > EOF
1335 1335 $ cat >> $HGRCPATH << EOF
1336 1336 > [extensions]
1337 1337 > testextension=$TESTTMP/test_extension.py
1338 1338 > EOF
1339 1339 $ hg init repo-issue-nativerevs-pending-changes
1340 1340 $ cd repo-issue-nativerevs-pending-changes
1341 1341 $ mkcommit a
1342 1342 $ mkcommit b
1343 1343 $ hg up ".^"
1344 1344 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1345 1345 $ echo aa > a
1346 1346 $ hg amendtransient
1347 1347 1 new orphan changesets
1348 1348 [1, 2]
1349 1349
1350 1350 Test cache consistency for the visible filter
1351 1351 1) We want to make sure that the cached filtered revs are invalidated when
1352 1352 bookmarks change
1353 1353 $ cd ..
1354 1354 $ cat >$TESTTMP/test_extension.py << EOF
1355 1355 > from __future__ import absolute_import, print_function
1356 1356 > import weakref
1357 1357 > from mercurial import (
1358 1358 > bookmarks,
1359 1359 > cmdutil,
1360 1360 > extensions,
1361 1361 > repoview,
1362 1362 > )
1363 1363 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1364 1364 > reporef = weakref.ref(bkmstoreinst._repo)
1365 1365 > def trhook(tr):
1366 1366 > repo = reporef()
1367 1367 > hidden1 = repoview.computehidden(repo)
1368 1368 > hidden = repoview.filterrevs(repo, b'visible')
1369 1369 > if sorted(hidden1) != sorted(hidden):
1370 1370 > print("cache inconsistency")
1371 1371 > bkmstoreinst._repo.currenttransaction().addpostclose(b'test_extension', trhook)
1372 1372 > orig(bkmstoreinst, *args, **kwargs)
1373 1373 > def extsetup(ui):
1374 1374 > extensions.wrapfunction(bookmarks.bmstore, '_recordchange',
1375 1375 > _bookmarkchanged)
1376 1376 > EOF
1377 1377
1378 1378 $ hg init repo-cache-inconsistency
1379 1379 $ cd repo-issue-nativerevs-pending-changes
1380 1380 $ mkcommit a
1381 1381 a already tracked!
1382 1382 $ mkcommit b
1383 1383 $ hg id
1384 1384 13bedc178fce tip
1385 1385 $ echo "hello" > b
1386 1386 $ hg commit --amend -m "message"
1387 1387 $ hg book bookb -r 13bedc178fce --hidden
1388 1388 bookmarking hidden changeset 13bedc178fce
1389 1389 (hidden revision '13bedc178fce' was rewritten as: a9b1f8652753)
1390 1390 $ hg log -r 13bedc178fce
1391 1391 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753]
1392 1392 $ hg book -d bookb
1393 1393 $ hg log -r 13bedc178fce
1394 1394 abort: hidden revision '13bedc178fce' was rewritten as: a9b1f8652753!
1395 1395 (use --hidden to access hidden revisions)
1396 1396 [255]
1397 1397
1398 1398 Empty out the test extension, as it isn't compatible with later parts
1399 1399 of the test.
1400 1400 $ echo > $TESTTMP/test_extension.py
1401 1401
1402 1402 Test ability to pull changeset with locally applying obsolescence markers
1403 1403 (issue4945)
1404 1404
1405 1405 $ cd ..
1406 1406 $ hg init issue4845
1407 1407 $ cd issue4845
1408 1408
1409 1409 $ echo foo > f0
1410 1410 $ hg add f0
1411 1411 $ hg ci -m '0'
1412 1412 $ echo foo > f1
1413 1413 $ hg add f1
1414 1414 $ hg ci -m '1'
1415 1415 $ echo foo > f2
1416 1416 $ hg add f2
1417 1417 $ hg ci -m '2'
1418 1418
1419 1419 $ echo bar > f2
1420 1420 $ hg commit --amend --config experimental.evolution.createmarkers=True
1421 1421 $ hg log -G
1422 1422 @ 3:b0551702f918 (draft) [tip ] 2
1423 1423 |
1424 1424 o 1:e016b03fd86f (draft) [ ] 1
1425 1425 |
1426 1426 o 0:a78f55e5508c (draft) [ ] 0
1427 1427
1428 1428 $ hg log -G --hidden
1429 1429 @ 3:b0551702f918 (draft) [tip ] 2
1430 1430 |
1431 1431 | x 2:e008cf283490 (draft *obsolete*) [ ] 2 [rewritten using amend as 3:b0551702f918]
1432 1432 |/
1433 1433 o 1:e016b03fd86f (draft) [ ] 1
1434 1434 |
1435 1435 o 0:a78f55e5508c (draft) [ ] 0
1436 1436
1437 1437
1438 1438 $ hg strip --hidden -r 2 --config extensions.strip= --config devel.strip-obsmarkers=no
1439 1439 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e008cf283490-ede36964-backup.hg
1440 1440 $ hg debugobsolete
1441 1441 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1442 1442 $ hg log -G
1443 1443 @ 2:b0551702f918 (draft) [tip ] 2
1444 1444 |
1445 1445 o 1:e016b03fd86f (draft) [ ] 1
1446 1446 |
1447 1447 o 0:a78f55e5508c (draft) [ ] 0
1448 1448
1449 1449 $ hg log -G --hidden
1450 1450 @ 2:b0551702f918 (draft) [tip ] 2
1451 1451 |
1452 1452 o 1:e016b03fd86f (draft) [ ] 1
1453 1453 |
1454 1454 o 0:a78f55e5508c (draft) [ ] 0
1455 1455
1456 1456 $ hg debugbundle .hg/strip-backup/e008cf283490-*-backup.hg
1457 1457 Stream params: {Compression: BZ}
1458 1458 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
1459 1459 e008cf2834908e5d6b0f792a9d4b0e2272260fb8
1460 1460 cache:rev-branch-cache -- {} (mandatory: False)
1461 1461 phase-heads -- {} (mandatory: True)
1462 1462 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 draft
1463 1463
1464 1464 #if repobundlerepo
1465 1465 $ hg pull .hg/strip-backup/e008cf283490-*-backup.hg
1466 1466 pulling from .hg/strip-backup/e008cf283490-ede36964-backup.hg
1467 1467 searching for changes
1468 1468 no changes found
1469 1469 #endif
1470 1470 $ hg debugobsolete
1471 1471 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1472 1472 $ hg log -G
1473 1473 @ 2:b0551702f918 (draft) [tip ] 2
1474 1474 |
1475 1475 o 1:e016b03fd86f (draft) [ ] 1
1476 1476 |
1477 1477 o 0:a78f55e5508c (draft) [ ] 0
1478 1478
1479 1479 $ hg log -G --hidden
1480 1480 @ 2:b0551702f918 (draft) [tip ] 2
1481 1481 |
1482 1482 o 1:e016b03fd86f (draft) [ ] 1
1483 1483 |
1484 1484 o 0:a78f55e5508c (draft) [ ] 0
1485 1485
1486 1486
1487 1487 Testing that strip remove markers:
1488 1488
1489 1489 $ hg strip -r 1 --config extensions.strip=
1490 1490 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1491 1491 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-65ede734-backup.hg
1492 1492 $ hg debugobsolete
1493 1493 $ hg log -G
1494 1494 @ 0:a78f55e5508c (draft) [tip ] 0
1495 1495
1496 1496 $ hg log -G --hidden
1497 1497 @ 0:a78f55e5508c (draft) [tip ] 0
1498 1498
1499 1499 $ hg debugbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1500 1500 Stream params: {Compression: BZ}
1501 1501 changegroup -- {nbchanges: 2, version: 02} (mandatory: True)
1502 1502 e016b03fd86fcccc54817d120b90b751aaf367d6
1503 1503 b0551702f918510f01ae838ab03a463054c67b46
1504 1504 cache:rev-branch-cache -- {} (mandatory: False)
1505 1505 obsmarkers -- {} (mandatory: True)
1506 1506 version: 1 (92 bytes)
1507 1507 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1508 1508 phase-heads -- {} (mandatory: True)
1509 1509 b0551702f918510f01ae838ab03a463054c67b46 draft
1510 1510
1511 1511 $ hg unbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1512 1512 adding changesets
1513 1513 adding manifests
1514 1514 adding file changes
1515 1515 added 2 changesets with 2 changes to 2 files
1516 1516 1 new obsolescence markers
1517 1517 new changesets e016b03fd86f:b0551702f918 (2 drafts)
1518 1518 (run 'hg update' to get a working copy)
1519 1519 $ hg debugobsolete | sort
1520 1520 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1521 1521 $ hg log -G
1522 1522 o 2:b0551702f918 (draft) [tip ] 2
1523 1523 |
1524 1524 o 1:e016b03fd86f (draft) [ ] 1
1525 1525 |
1526 1526 @ 0:a78f55e5508c (draft) [ ] 0
1527 1527
1528 1528 $ hg log -G --hidden
1529 1529 o 2:b0551702f918 (draft) [tip ] 2
1530 1530 |
1531 1531 o 1:e016b03fd86f (draft) [ ] 1
1532 1532 |
1533 1533 @ 0:a78f55e5508c (draft) [ ] 0
1534 1534
1535 1535 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1536 1536 only a subset of those are displayed (because of --rev option)
1537 1537 $ hg init doindexrev
1538 1538 $ cd doindexrev
1539 1539 $ echo a > a
1540 1540 $ hg ci -Am a
1541 1541 adding a
1542 1542 $ hg ci --amend -m aa
1543 1543 $ echo b > b
1544 1544 $ hg ci -Am b
1545 1545 adding b
1546 1546 $ hg ci --amend -m bb
1547 1547 $ echo c > c
1548 1548 $ hg ci -Am c
1549 1549 adding c
1550 1550 $ hg ci --amend -m cc
1551 1551 $ echo d > d
1552 1552 $ hg ci -Am d
1553 1553 adding d
1554 1554 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1555 1555 $ hg debugobsolete --index --rev "3+7"
1556 1556 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1557 1557 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1558 1558 $ hg debugobsolete --index --rev "3+7" -Tjson
1559 1559 [
1560 1560 {
1561 1561 "date": [0, 0],
1562 1562 "flag": 0,
1563 1563 "index": 1,
1564 1564 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1565 1565 "prednode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1566 1566 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1567 1567 },
1568 1568 {
1569 1569 "date": [0, 0],
1570 1570 "flag": 0,
1571 1571 "index": 3,
1572 1572 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1573 1573 "prednode": "4715cf767440ed891755448016c2b8cf70760c30",
1574 1574 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1575 1575 }
1576 1576 ]
1577 1577
1578 1578 Test the --delete option of debugobsolete command
1579 1579 $ hg debugobsolete --index
1580 1580 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1581 1581 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1582 1582 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1583 1583 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1584 1584 $ hg debugobsolete --delete 1 --delete 3
1585 1585 deleted 2 obsolescence markers
1586 1586 $ hg debugobsolete
1587 1587 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1588 1588 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1589 1589
1590 1590 Test adding changeset after obsmarkers affecting it
1591 1591 (eg: during pull, or unbundle)
1592 1592
1593 1593 $ mkcommit e
1594 1594 $ hg bundle -r . --base .~1 ../bundle-2.hg
1595 1595 1 changesets found
1596 1596 $ getid .
1597 1597 $ hg --config extensions.strip= strip -r .
1598 1598 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1599 1599 saved backup bundle to $TESTTMP/tmpe/issue4845/doindexrev/.hg/strip-backup/9bc153528424-ee80edd4-backup.hg
1600 1600 $ hg debugobsolete 9bc153528424ea266d13e57f9ff0d799dfe61e4b
1601 1601 $ hg unbundle ../bundle-2.hg
1602 1602 adding changesets
1603 1603 adding manifests
1604 1604 adding file changes
1605 1605 added 1 changesets with 1 changes to 1 files
1606 1606 (1 other changesets obsolete on arrival)
1607 1607 (run 'hg update' to get a working copy)
1608 1608 $ hg log -G
1609 1609 @ 7:7ae79c5d60f0 (draft) [tip ] dd
1610 1610 |
1611 1611 | o 6:4715cf767440 (draft) [ ] d
1612 1612 |/
1613 1613 o 5:29346082e4a9 (draft) [ ] cc
1614 1614 |
1615 1615 o 3:d27fb9b06607 (draft) [ ] bb
1616 1616 |
1617 1617 | o 2:6fdef60fcbab (draft) [ ] b
1618 1618 |/
1619 1619 o 1:f9bd49731b0b (draft) [ ] aa
1620 1620
1621 1621
1622 1622 $ cd ..
1623
1624 Test issue 5783
1625
1626 $ hg init issue-5783 --config format.obsstore-version=0
1627 $ cd issue-5783
1628 $ touch a.cpp
1629 $ hg add a.cpp
1630 $ hg commit -m 'Add a.cpp'
1631 $ echo 'Hello' > a.cpp
1632 $ hg amend -n 'Testing::Obsstore' --config format.obsstore-version=0 --config extensions.amend=
1633 $ touch b.cpp
1634 $ hg add b.cpp
1635 $ hg commit -m 'Add b.cpp'
1636 $ echo 'Hello' > b.cpp
1637 $ hg amend -n 'Testing::Obsstore2' --config extensions.amend=
1638 $ hg debugobsolete
1639 d1b09fe3ad2b2a03e23a72f0c582e29a49570145 1a1a11184d2588af24e767e5335d5d9d07e8c550 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore', 'operation': 'amend', 'user': 'test'}
1640 1bfd8e3868f641e048b6667cd672c68932f26d00 79959ca316d5b27ac6be1dd0cfd0843a5b5412eb 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore2', 'operation': 'amend', 'user': 'test'}
1641 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now