##// END OF EJS Templates
obsmarker: add an experimental flag controlling "operation" recording...
marmoute -
r32354:f432897a default
parent child Browse files
Show More
@@ -1,1287 +1,1290 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 "precursor" and possible
24 24 replacements are called "successors". Markers that used changeset X as
25 25 a precursor 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 "precursor markers of Y" because they hold
28 28 information about the precursors 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 struct
74 74
75 75 from .i18n import _
76 76 from . import (
77 77 error,
78 78 node,
79 79 parsers,
80 80 phases,
81 81 util,
82 82 )
83 83
84 84 _pack = struct.pack
85 85 _unpack = struct.unpack
86 86 _calcsize = struct.calcsize
87 87 propertycache = util.propertycache
88 88
89 89 # the obsolete feature is not mature enough to be enabled by default.
90 90 # you have to rely on third party extension extension to enable this.
91 91 _enabled = False
92 92
93 93 # Options for obsolescence
94 94 createmarkersopt = 'createmarkers'
95 95 allowunstableopt = 'allowunstable'
96 96 exchangeopt = 'exchange'
97 97
98 98 def isenabled(repo, option):
99 99 """Returns True if the given repository has the given obsolete option
100 100 enabled.
101 101 """
102 102 result = set(repo.ui.configlist('experimental', 'evolution'))
103 103 if 'all' in result:
104 104 return True
105 105
106 106 # For migration purposes, temporarily return true if the config hasn't been
107 107 # set but _enabled is true.
108 108 if len(result) == 0 and _enabled:
109 109 return True
110 110
111 111 # createmarkers must be enabled if other options are enabled
112 112 if ((allowunstableopt in result or exchangeopt in result) and
113 113 not createmarkersopt in result):
114 114 raise error.Abort(_("'createmarkers' obsolete option must be enabled "
115 115 "if other obsolete options are enabled"))
116 116
117 117 return option in result
118 118
119 119 ### obsolescence marker flag
120 120
121 121 ## bumpedfix flag
122 122 #
123 123 # When a changeset A' succeed to a changeset A which became public, we call A'
124 124 # "bumped" because it's a successors of a public changesets
125 125 #
126 126 # o A' (bumped)
127 127 # |`:
128 128 # | o A
129 129 # |/
130 130 # o Z
131 131 #
132 132 # The way to solve this situation is to create a new changeset Ad as children
133 133 # of A. This changeset have the same content than A'. So the diff from A to A'
134 134 # is the same than the diff from A to Ad. Ad is marked as a successors of A'
135 135 #
136 136 # o Ad
137 137 # |`:
138 138 # | x A'
139 139 # |'|
140 140 # o | A
141 141 # |/
142 142 # o Z
143 143 #
144 144 # But by transitivity Ad is also a successors of A. To avoid having Ad marked
145 145 # as bumped too, we add the `bumpedfix` flag to the marker. <A', (Ad,)>.
146 146 # This flag mean that the successors express the changes between the public and
147 147 # bumped version and fix the situation, breaking the transitivity of
148 148 # "bumped" here.
149 149 bumpedfix = 1
150 150 usingsha256 = 2
151 151
152 152 ## Parsing and writing of version "0"
153 153 #
154 154 # The header is followed by the markers. Each marker is made of:
155 155 #
156 156 # - 1 uint8 : number of new changesets "N", can be zero.
157 157 #
158 158 # - 1 uint32: metadata size "M" in bytes.
159 159 #
160 160 # - 1 byte: a bit field. It is reserved for flags used in common
161 161 # obsolete marker operations, to avoid repeated decoding of metadata
162 162 # entries.
163 163 #
164 164 # - 20 bytes: obsoleted changeset identifier.
165 165 #
166 166 # - N*20 bytes: new changesets identifiers.
167 167 #
168 168 # - M bytes: metadata as a sequence of nul-terminated strings. Each
169 169 # string contains a key and a value, separated by a colon ':', without
170 170 # additional encoding. Keys cannot contain '\0' or ':' and values
171 171 # cannot contain '\0'.
172 172 _fm0version = 0
173 173 _fm0fixed = '>BIB20s'
174 174 _fm0node = '20s'
175 175 _fm0fsize = _calcsize(_fm0fixed)
176 176 _fm0fnodesize = _calcsize(_fm0node)
177 177
178 178 def _fm0readmarkers(data, off):
179 179 # Loop on markers
180 180 l = len(data)
181 181 while off + _fm0fsize <= l:
182 182 # read fixed part
183 183 cur = data[off:off + _fm0fsize]
184 184 off += _fm0fsize
185 185 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
186 186 # read replacement
187 187 sucs = ()
188 188 if numsuc:
189 189 s = (_fm0fnodesize * numsuc)
190 190 cur = data[off:off + s]
191 191 sucs = _unpack(_fm0node * numsuc, cur)
192 192 off += s
193 193 # read metadata
194 194 # (metadata will be decoded on demand)
195 195 metadata = data[off:off + mdsize]
196 196 if len(metadata) != mdsize:
197 197 raise error.Abort(_('parsing obsolete marker: metadata is too '
198 198 'short, %d bytes expected, got %d')
199 199 % (mdsize, len(metadata)))
200 200 off += mdsize
201 201 metadata = _fm0decodemeta(metadata)
202 202 try:
203 203 when, offset = metadata.pop('date', '0 0').split(' ')
204 204 date = float(when), int(offset)
205 205 except ValueError:
206 206 date = (0., 0)
207 207 parents = None
208 208 if 'p2' in metadata:
209 209 parents = (metadata.pop('p1', None), metadata.pop('p2', None))
210 210 elif 'p1' in metadata:
211 211 parents = (metadata.pop('p1', None),)
212 212 elif 'p0' in metadata:
213 213 parents = ()
214 214 if parents is not None:
215 215 try:
216 216 parents = tuple(node.bin(p) for p in parents)
217 217 # if parent content is not a nodeid, drop the data
218 218 for p in parents:
219 219 if len(p) != 20:
220 220 parents = None
221 221 break
222 222 except TypeError:
223 223 # if content cannot be translated to nodeid drop the data.
224 224 parents = None
225 225
226 226 metadata = tuple(sorted(metadata.iteritems()))
227 227
228 228 yield (pre, sucs, flags, metadata, date, parents)
229 229
230 230 def _fm0encodeonemarker(marker):
231 231 pre, sucs, flags, metadata, date, parents = marker
232 232 if flags & usingsha256:
233 233 raise error.Abort(_('cannot handle sha256 with old obsstore format'))
234 234 metadata = dict(metadata)
235 235 time, tz = date
236 236 metadata['date'] = '%r %i' % (time, tz)
237 237 if parents is not None:
238 238 if not parents:
239 239 # mark that we explicitly recorded no parents
240 240 metadata['p0'] = ''
241 241 for i, p in enumerate(parents, 1):
242 242 metadata['p%i' % i] = node.hex(p)
243 243 metadata = _fm0encodemeta(metadata)
244 244 numsuc = len(sucs)
245 245 format = _fm0fixed + (_fm0node * numsuc)
246 246 data = [numsuc, len(metadata), flags, pre]
247 247 data.extend(sucs)
248 248 return _pack(format, *data) + metadata
249 249
250 250 def _fm0encodemeta(meta):
251 251 """Return encoded metadata string to string mapping.
252 252
253 253 Assume no ':' in key and no '\0' in both key and value."""
254 254 for key, value in meta.iteritems():
255 255 if ':' in key or '\0' in key:
256 256 raise ValueError("':' and '\0' are forbidden in metadata key'")
257 257 if '\0' in value:
258 258 raise ValueError("':' is forbidden in metadata value'")
259 259 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
260 260
261 261 def _fm0decodemeta(data):
262 262 """Return string to string dictionary from encoded version."""
263 263 d = {}
264 264 for l in data.split('\0'):
265 265 if l:
266 266 key, value = l.split(':')
267 267 d[key] = value
268 268 return d
269 269
270 270 ## Parsing and writing of version "1"
271 271 #
272 272 # The header is followed by the markers. Each marker is made of:
273 273 #
274 274 # - uint32: total size of the marker (including this field)
275 275 #
276 276 # - float64: date in seconds since epoch
277 277 #
278 278 # - int16: timezone offset in minutes
279 279 #
280 280 # - uint16: a bit field. It is reserved for flags used in common
281 281 # obsolete marker operations, to avoid repeated decoding of metadata
282 282 # entries.
283 283 #
284 284 # - uint8: number of successors "N", can be zero.
285 285 #
286 286 # - uint8: number of parents "P", can be zero.
287 287 #
288 288 # 0: parents data stored but no parent,
289 289 # 1: one parent stored,
290 290 # 2: two parents stored,
291 291 # 3: no parent data stored
292 292 #
293 293 # - uint8: number of metadata entries M
294 294 #
295 295 # - 20 or 32 bytes: precursor changeset identifier.
296 296 #
297 297 # - N*(20 or 32) bytes: successors changesets identifiers.
298 298 #
299 299 # - P*(20 or 32) bytes: parents of the precursors changesets.
300 300 #
301 301 # - M*(uint8, uint8): size of all metadata entries (key and value)
302 302 #
303 303 # - remaining bytes: the metadata, each (key, value) pair after the other.
304 304 _fm1version = 1
305 305 _fm1fixed = '>IdhHBBB20s'
306 306 _fm1nodesha1 = '20s'
307 307 _fm1nodesha256 = '32s'
308 308 _fm1nodesha1size = _calcsize(_fm1nodesha1)
309 309 _fm1nodesha256size = _calcsize(_fm1nodesha256)
310 310 _fm1fsize = _calcsize(_fm1fixed)
311 311 _fm1parentnone = 3
312 312 _fm1parentshift = 14
313 313 _fm1parentmask = (_fm1parentnone << _fm1parentshift)
314 314 _fm1metapair = 'BB'
315 315 _fm1metapairsize = _calcsize('BB')
316 316
317 317 def _fm1purereadmarkers(data, off):
318 318 # make some global constants local for performance
319 319 noneflag = _fm1parentnone
320 320 sha2flag = usingsha256
321 321 sha1size = _fm1nodesha1size
322 322 sha2size = _fm1nodesha256size
323 323 sha1fmt = _fm1nodesha1
324 324 sha2fmt = _fm1nodesha256
325 325 metasize = _fm1metapairsize
326 326 metafmt = _fm1metapair
327 327 fsize = _fm1fsize
328 328 unpack = _unpack
329 329
330 330 # Loop on markers
331 331 stop = len(data) - _fm1fsize
332 332 ufixed = struct.Struct(_fm1fixed).unpack
333 333
334 334 while off <= stop:
335 335 # read fixed part
336 336 o1 = off + fsize
337 337 t, secs, tz, flags, numsuc, numpar, nummeta, prec = ufixed(data[off:o1])
338 338
339 339 if flags & sha2flag:
340 340 # FIXME: prec was read as a SHA1, needs to be amended
341 341
342 342 # read 0 or more successors
343 343 if numsuc == 1:
344 344 o2 = o1 + sha2size
345 345 sucs = (data[o1:o2],)
346 346 else:
347 347 o2 = o1 + sha2size * numsuc
348 348 sucs = unpack(sha2fmt * numsuc, data[o1:o2])
349 349
350 350 # read parents
351 351 if numpar == noneflag:
352 352 o3 = o2
353 353 parents = None
354 354 elif numpar == 1:
355 355 o3 = o2 + sha2size
356 356 parents = (data[o2:o3],)
357 357 else:
358 358 o3 = o2 + sha2size * numpar
359 359 parents = unpack(sha2fmt * numpar, data[o2:o3])
360 360 else:
361 361 # read 0 or more successors
362 362 if numsuc == 1:
363 363 o2 = o1 + sha1size
364 364 sucs = (data[o1:o2],)
365 365 else:
366 366 o2 = o1 + sha1size * numsuc
367 367 sucs = unpack(sha1fmt * numsuc, data[o1:o2])
368 368
369 369 # read parents
370 370 if numpar == noneflag:
371 371 o3 = o2
372 372 parents = None
373 373 elif numpar == 1:
374 374 o3 = o2 + sha1size
375 375 parents = (data[o2:o3],)
376 376 else:
377 377 o3 = o2 + sha1size * numpar
378 378 parents = unpack(sha1fmt * numpar, data[o2:o3])
379 379
380 380 # read metadata
381 381 off = o3 + metasize * nummeta
382 382 metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off])
383 383 metadata = []
384 384 for idx in xrange(0, len(metapairsize), 2):
385 385 o1 = off + metapairsize[idx]
386 386 o2 = o1 + metapairsize[idx + 1]
387 387 metadata.append((data[off:o1], data[o1:o2]))
388 388 off = o2
389 389
390 390 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
391 391
392 392 def _fm1encodeonemarker(marker):
393 393 pre, sucs, flags, metadata, date, parents = marker
394 394 # determine node size
395 395 _fm1node = _fm1nodesha1
396 396 if flags & usingsha256:
397 397 _fm1node = _fm1nodesha256
398 398 numsuc = len(sucs)
399 399 numextranodes = numsuc
400 400 if parents is None:
401 401 numpar = _fm1parentnone
402 402 else:
403 403 numpar = len(parents)
404 404 numextranodes += numpar
405 405 formatnodes = _fm1node * numextranodes
406 406 formatmeta = _fm1metapair * len(metadata)
407 407 format = _fm1fixed + formatnodes + formatmeta
408 408 # tz is stored in minutes so we divide by 60
409 409 tz = date[1]//60
410 410 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
411 411 data.extend(sucs)
412 412 if parents is not None:
413 413 data.extend(parents)
414 414 totalsize = _calcsize(format)
415 415 for key, value in metadata:
416 416 lk = len(key)
417 417 lv = len(value)
418 418 data.append(lk)
419 419 data.append(lv)
420 420 totalsize += lk + lv
421 421 data[0] = totalsize
422 422 data = [_pack(format, *data)]
423 423 for key, value in metadata:
424 424 data.append(key)
425 425 data.append(value)
426 426 return ''.join(data)
427 427
428 428 def _fm1readmarkers(data, off):
429 429 native = getattr(parsers, 'fm1readmarkers', None)
430 430 if not native:
431 431 return _fm1purereadmarkers(data, off)
432 432 stop = len(data) - _fm1fsize
433 433 return native(data, off, stop)
434 434
435 435 # mapping to read/write various marker formats
436 436 # <version> -> (decoder, encoder)
437 437 formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
438 438 _fm1version: (_fm1readmarkers, _fm1encodeonemarker)}
439 439
440 440 @util.nogc
441 441 def _readmarkers(data):
442 442 """Read and enumerate markers from raw data"""
443 443 off = 0
444 444 diskversion = _unpack('>B', data[off:off + 1])[0]
445 445 off += 1
446 446 if diskversion not in formats:
447 447 raise error.Abort(_('parsing obsolete marker: unknown version %r')
448 448 % diskversion)
449 449 return diskversion, formats[diskversion][0](data, off)
450 450
451 451 def encodemarkers(markers, addheader=False, version=_fm0version):
452 452 # Kept separate from flushmarkers(), it will be reused for
453 453 # markers exchange.
454 454 encodeone = formats[version][1]
455 455 if addheader:
456 456 yield _pack('>B', version)
457 457 for marker in markers:
458 458 yield encodeone(marker)
459 459
460 460
461 461 class marker(object):
462 462 """Wrap obsolete marker raw data"""
463 463
464 464 def __init__(self, repo, data):
465 465 # the repo argument will be used to create changectx in later version
466 466 self._repo = repo
467 467 self._data = data
468 468 self._decodedmeta = None
469 469
470 470 def __hash__(self):
471 471 return hash(self._data)
472 472
473 473 def __eq__(self, other):
474 474 if type(other) != type(self):
475 475 return False
476 476 return self._data == other._data
477 477
478 478 def precnode(self):
479 479 """Precursor changeset node identifier"""
480 480 return self._data[0]
481 481
482 482 def succnodes(self):
483 483 """List of successor changesets node identifiers"""
484 484 return self._data[1]
485 485
486 486 def parentnodes(self):
487 487 """Parents of the precursors (None if not recorded)"""
488 488 return self._data[5]
489 489
490 490 def metadata(self):
491 491 """Decoded metadata dictionary"""
492 492 return dict(self._data[3])
493 493
494 494 def date(self):
495 495 """Creation date as (unixtime, offset)"""
496 496 return self._data[4]
497 497
498 498 def flags(self):
499 499 """The flags field of the marker"""
500 500 return self._data[2]
501 501
502 502 @util.nogc
503 503 def _addsuccessors(successors, markers):
504 504 for mark in markers:
505 505 successors.setdefault(mark[0], set()).add(mark)
506 506
507 507 @util.nogc
508 508 def _addprecursors(precursors, markers):
509 509 for mark in markers:
510 510 for suc in mark[1]:
511 511 precursors.setdefault(suc, set()).add(mark)
512 512
513 513 @util.nogc
514 514 def _addchildren(children, markers):
515 515 for mark in markers:
516 516 parents = mark[5]
517 517 if parents is not None:
518 518 for p in parents:
519 519 children.setdefault(p, set()).add(mark)
520 520
521 521 def _checkinvalidmarkers(markers):
522 522 """search for marker with invalid data and raise error if needed
523 523
524 524 Exist as a separated function to allow the evolve extension for a more
525 525 subtle handling.
526 526 """
527 527 for mark in markers:
528 528 if node.nullid in mark[1]:
529 529 raise error.Abort(_('bad obsolescence marker detected: '
530 530 'invalid successors nullid'))
531 531
532 532 class obsstore(object):
533 533 """Store obsolete markers
534 534
535 535 Markers can be accessed with two mappings:
536 536 - precursors[x] -> set(markers on precursors edges of x)
537 537 - successors[x] -> set(markers on successors edges of x)
538 538 - children[x] -> set(markers on precursors edges of children(x)
539 539 """
540 540
541 541 fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
542 542 # prec: nodeid, precursor changesets
543 543 # succs: tuple of nodeid, successor changesets (0-N length)
544 544 # flag: integer, flag field carrying modifier for the markers (see doc)
545 545 # meta: binary blob, encoded metadata dictionary
546 546 # date: (float, int) tuple, date of marker creation
547 547 # parents: (tuple of nodeid) or None, parents of precursors
548 548 # None is used when no data has been recorded
549 549
550 550 def __init__(self, svfs, defaultformat=_fm1version, readonly=False):
551 551 # caches for various obsolescence related cache
552 552 self.caches = {}
553 553 self.svfs = svfs
554 554 self._version = defaultformat
555 555 self._readonly = readonly
556 556
557 557 def __iter__(self):
558 558 return iter(self._all)
559 559
560 560 def __len__(self):
561 561 return len(self._all)
562 562
563 563 def __nonzero__(self):
564 564 if not self._cached('_all'):
565 565 try:
566 566 return self.svfs.stat('obsstore').st_size > 1
567 567 except OSError as inst:
568 568 if inst.errno != errno.ENOENT:
569 569 raise
570 570 # just build an empty _all list if no obsstore exists, which
571 571 # avoids further stat() syscalls
572 572 pass
573 573 return bool(self._all)
574 574
575 575 __bool__ = __nonzero__
576 576
577 577 @property
578 578 def readonly(self):
579 579 """True if marker creation is disabled
580 580
581 581 Remove me in the future when obsolete marker is always on."""
582 582 return self._readonly
583 583
584 584 def create(self, transaction, prec, succs=(), flag=0, parents=None,
585 585 date=None, metadata=None):
586 586 """obsolete: add a new obsolete marker
587 587
588 588 * ensuring it is hashable
589 589 * check mandatory metadata
590 590 * encode metadata
591 591
592 592 If you are a human writing code creating marker you want to use the
593 593 `createmarkers` function in this module instead.
594 594
595 595 return True if a new marker have been added, False if the markers
596 596 already existed (no op).
597 597 """
598 598 if metadata is None:
599 599 metadata = {}
600 600 if date is None:
601 601 if 'date' in metadata:
602 602 # as a courtesy for out-of-tree extensions
603 603 date = util.parsedate(metadata.pop('date'))
604 604 else:
605 605 date = util.makedate()
606 606 if len(prec) != 20:
607 607 raise ValueError(prec)
608 608 for succ in succs:
609 609 if len(succ) != 20:
610 610 raise ValueError(succ)
611 611 if prec in succs:
612 612 raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
613 613
614 614 metadata = tuple(sorted(metadata.iteritems()))
615 615
616 616 marker = (str(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(self._all)
628 628 new = []
629 629 for m in markers:
630 630 if m not in known:
631 631 known.add(m)
632 632 new.append(m)
633 633 if new:
634 634 f = self.svfs('obsstore', 'ab')
635 635 try:
636 636 offset = f.tell()
637 637 transaction.add('obsstore', offset)
638 638 # offset == 0: new file - add the version header
639 639 for bytes in encodemarkers(new, offset == 0, self._version):
640 640 f.write(bytes)
641 641 finally:
642 642 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
643 643 # call 'filecacheentry.refresh()' here
644 644 f.close()
645 645 self._addmarkers(new)
646 646 # new marker *may* have changed several set. invalidate the cache.
647 647 self.caches.clear()
648 648 # records the number of new markers for the transaction hooks
649 649 previous = int(transaction.hookargs.get('new_obsmarkers', '0'))
650 650 transaction.hookargs['new_obsmarkers'] = str(previous + len(new))
651 651 return len(new)
652 652
653 653 def mergemarkers(self, transaction, data):
654 654 """merge a binary stream of markers inside the obsstore
655 655
656 656 Returns the number of new markers added."""
657 657 version, markers = _readmarkers(data)
658 658 return self.add(transaction, markers)
659 659
660 660 @propertycache
661 661 def _all(self):
662 662 data = self.svfs.tryread('obsstore')
663 663 if not data:
664 664 return []
665 665 self._version, markers = _readmarkers(data)
666 666 markers = list(markers)
667 667 _checkinvalidmarkers(markers)
668 668 return markers
669 669
670 670 @propertycache
671 671 def successors(self):
672 672 successors = {}
673 673 _addsuccessors(successors, self._all)
674 674 return successors
675 675
676 676 @propertycache
677 677 def precursors(self):
678 678 precursors = {}
679 679 _addprecursors(precursors, self._all)
680 680 return precursors
681 681
682 682 @propertycache
683 683 def children(self):
684 684 children = {}
685 685 _addchildren(children, self._all)
686 686 return children
687 687
688 688 def _cached(self, attr):
689 689 return attr in self.__dict__
690 690
691 691 def _addmarkers(self, markers):
692 692 markers = list(markers) # to allow repeated iteration
693 693 self._all.extend(markers)
694 694 if self._cached('successors'):
695 695 _addsuccessors(self.successors, markers)
696 696 if self._cached('precursors'):
697 697 _addprecursors(self.precursors, markers)
698 698 if self._cached('children'):
699 699 _addchildren(self.children, markers)
700 700 _checkinvalidmarkers(markers)
701 701
702 702 def relevantmarkers(self, nodes):
703 703 """return a set of all obsolescence markers relevant to a set of nodes.
704 704
705 705 "relevant" to a set of nodes mean:
706 706
707 707 - marker that use this changeset as successor
708 708 - prune marker of direct children on this changeset
709 709 - recursive application of the two rules on precursors of these markers
710 710
711 711 It is a set so you cannot rely on order."""
712 712
713 713 pendingnodes = set(nodes)
714 714 seenmarkers = set()
715 715 seennodes = set(pendingnodes)
716 716 precursorsmarkers = self.precursors
717 717 children = self.children
718 718 while pendingnodes:
719 719 direct = set()
720 720 for current in pendingnodes:
721 721 direct.update(precursorsmarkers.get(current, ()))
722 722 pruned = [m for m in children.get(current, ()) if not m[1]]
723 723 direct.update(pruned)
724 724 direct -= seenmarkers
725 725 pendingnodes = set([m[0] for m in direct])
726 726 seenmarkers |= direct
727 727 pendingnodes -= seennodes
728 728 seennodes |= pendingnodes
729 729 return seenmarkers
730 730
731 731 def commonversion(versions):
732 732 """Return the newest version listed in both versions and our local formats.
733 733
734 734 Returns None if no common version exists.
735 735 """
736 736 versions.sort(reverse=True)
737 737 # search for highest version known on both side
738 738 for v in versions:
739 739 if v in formats:
740 740 return v
741 741 return None
742 742
743 743 # arbitrary picked to fit into 8K limit from HTTP server
744 744 # you have to take in account:
745 745 # - the version header
746 746 # - the base85 encoding
747 747 _maxpayload = 5300
748 748
749 749 def _pushkeyescape(markers):
750 750 """encode markers into a dict suitable for pushkey exchange
751 751
752 752 - binary data is base85 encoded
753 753 - split in chunks smaller than 5300 bytes"""
754 754 keys = {}
755 755 parts = []
756 756 currentlen = _maxpayload * 2 # ensure we create a new part
757 757 for marker in markers:
758 758 nextdata = _fm0encodeonemarker(marker)
759 759 if (len(nextdata) + currentlen > _maxpayload):
760 760 currentpart = []
761 761 currentlen = 0
762 762 parts.append(currentpart)
763 763 currentpart.append(nextdata)
764 764 currentlen += len(nextdata)
765 765 for idx, part in enumerate(reversed(parts)):
766 766 data = ''.join([_pack('>B', _fm0version)] + part)
767 767 keys['dump%i' % idx] = util.b85encode(data)
768 768 return keys
769 769
770 770 def listmarkers(repo):
771 771 """List markers over pushkey"""
772 772 if not repo.obsstore:
773 773 return {}
774 774 return _pushkeyescape(sorted(repo.obsstore))
775 775
776 776 def pushmarker(repo, key, old, new):
777 777 """Push markers over pushkey"""
778 778 if not key.startswith('dump'):
779 779 repo.ui.warn(_('unknown key: %r') % key)
780 780 return 0
781 781 if old:
782 782 repo.ui.warn(_('unexpected old value for %r') % key)
783 783 return 0
784 784 data = util.b85decode(new)
785 785 lock = repo.lock()
786 786 try:
787 787 tr = repo.transaction('pushkey: obsolete markers')
788 788 try:
789 789 repo.obsstore.mergemarkers(tr, data)
790 790 tr.close()
791 791 return 1
792 792 finally:
793 793 tr.release()
794 794 finally:
795 795 lock.release()
796 796
797 797 def getmarkers(repo, nodes=None):
798 798 """returns markers known in a repository
799 799
800 800 If <nodes> is specified, only markers "relevant" to those nodes are are
801 801 returned"""
802 802 if nodes is None:
803 803 rawmarkers = repo.obsstore
804 804 else:
805 805 rawmarkers = repo.obsstore.relevantmarkers(nodes)
806 806
807 807 for markerdata in rawmarkers:
808 808 yield marker(repo, markerdata)
809 809
810 810 def relevantmarkers(repo, node):
811 811 """all obsolete markers relevant to some revision"""
812 812 for markerdata in repo.obsstore.relevantmarkers(node):
813 813 yield marker(repo, markerdata)
814 814
815 815
816 816 def precursormarkers(ctx):
817 817 """obsolete marker marking this changeset as a successors"""
818 818 for data in ctx.repo().obsstore.precursors.get(ctx.node(), ()):
819 819 yield marker(ctx.repo(), data)
820 820
821 821 def successormarkers(ctx):
822 822 """obsolete marker making this changeset obsolete"""
823 823 for data in ctx.repo().obsstore.successors.get(ctx.node(), ()):
824 824 yield marker(ctx.repo(), data)
825 825
826 826 def allsuccessors(obsstore, nodes, ignoreflags=0):
827 827 """Yield node for every successor of <nodes>.
828 828
829 829 Some successors may be unknown locally.
830 830
831 831 This is a linear yield unsuited to detecting split changesets. It includes
832 832 initial nodes too."""
833 833 remaining = set(nodes)
834 834 seen = set(remaining)
835 835 while remaining:
836 836 current = remaining.pop()
837 837 yield current
838 838 for mark in obsstore.successors.get(current, ()):
839 839 # ignore marker flagged with specified flag
840 840 if mark[2] & ignoreflags:
841 841 continue
842 842 for suc in mark[1]:
843 843 if suc not in seen:
844 844 seen.add(suc)
845 845 remaining.add(suc)
846 846
847 847 def allprecursors(obsstore, nodes, ignoreflags=0):
848 848 """Yield node for every precursors of <nodes>.
849 849
850 850 Some precursors may be unknown locally.
851 851
852 852 This is a linear yield unsuited to detecting folded changesets. It includes
853 853 initial nodes too."""
854 854
855 855 remaining = set(nodes)
856 856 seen = set(remaining)
857 857 while remaining:
858 858 current = remaining.pop()
859 859 yield current
860 860 for mark in obsstore.precursors.get(current, ()):
861 861 # ignore marker flagged with specified flag
862 862 if mark[2] & ignoreflags:
863 863 continue
864 864 suc = mark[0]
865 865 if suc not in seen:
866 866 seen.add(suc)
867 867 remaining.add(suc)
868 868
869 869 def foreground(repo, nodes):
870 870 """return all nodes in the "foreground" of other node
871 871
872 872 The foreground of a revision is anything reachable using parent -> children
873 873 or precursor -> successor relation. It is very similar to "descendant" but
874 874 augmented with obsolescence information.
875 875
876 876 Beware that possible obsolescence cycle may result if complex situation.
877 877 """
878 878 repo = repo.unfiltered()
879 879 foreground = set(repo.set('%ln::', nodes))
880 880 if repo.obsstore:
881 881 # We only need this complicated logic if there is obsolescence
882 882 # XXX will probably deserve an optimised revset.
883 883 nm = repo.changelog.nodemap
884 884 plen = -1
885 885 # compute the whole set of successors or descendants
886 886 while len(foreground) != plen:
887 887 plen = len(foreground)
888 888 succs = set(c.node() for c in foreground)
889 889 mutable = [c.node() for c in foreground if c.mutable()]
890 890 succs.update(allsuccessors(repo.obsstore, mutable))
891 891 known = (n for n in succs if n in nm)
892 892 foreground = set(repo.set('%ln::', known))
893 893 return set(c.node() for c in foreground)
894 894
895 895
896 896 def successorssets(repo, initialnode, cache=None):
897 897 """Return set of all latest successors of initial nodes
898 898
899 899 The successors set of a changeset A are the group of revisions that succeed
900 900 A. It succeeds A as a consistent whole, each revision being only a partial
901 901 replacement. The successors set contains non-obsolete changesets only.
902 902
903 903 This function returns the full list of successor sets which is why it
904 904 returns a list of tuples and not just a single tuple. Each tuple is a valid
905 905 successors set. Note that (A,) may be a valid successors set for changeset A
906 906 (see below).
907 907
908 908 In most cases, a changeset A will have a single element (e.g. the changeset
909 909 A is replaced by A') in its successors set. Though, it is also common for a
910 910 changeset A to have no elements in its successor set (e.g. the changeset
911 911 has been pruned). Therefore, the returned list of successors sets will be
912 912 [(A',)] or [], respectively.
913 913
914 914 When a changeset A is split into A' and B', however, it will result in a
915 915 successors set containing more than a single element, i.e. [(A',B')].
916 916 Divergent changesets will result in multiple successors sets, i.e. [(A',),
917 917 (A'')].
918 918
919 919 If a changeset A is not obsolete, then it will conceptually have no
920 920 successors set. To distinguish this from a pruned changeset, the successor
921 921 set will contain itself only, i.e. [(A,)].
922 922
923 923 Finally, successors unknown locally are considered to be pruned (obsoleted
924 924 without any successors).
925 925
926 926 The optional `cache` parameter is a dictionary that may contain precomputed
927 927 successors sets. It is meant to reuse the computation of a previous call to
928 928 `successorssets` when multiple calls are made at the same time. The cache
929 929 dictionary is updated in place. The caller is responsible for its life
930 930 span. Code that makes multiple calls to `successorssets` *must* use this
931 931 cache mechanism or suffer terrible performance.
932 932 """
933 933
934 934 succmarkers = repo.obsstore.successors
935 935
936 936 # Stack of nodes we search successors sets for
937 937 toproceed = [initialnode]
938 938 # set version of above list for fast loop detection
939 939 # element added to "toproceed" must be added here
940 940 stackedset = set(toproceed)
941 941 if cache is None:
942 942 cache = {}
943 943
944 944 # This while loop is the flattened version of a recursive search for
945 945 # successors sets
946 946 #
947 947 # def successorssets(x):
948 948 # successors = directsuccessors(x)
949 949 # ss = [[]]
950 950 # for succ in directsuccessors(x):
951 951 # # product as in itertools cartesian product
952 952 # ss = product(ss, successorssets(succ))
953 953 # return ss
954 954 #
955 955 # But we can not use plain recursive calls here:
956 956 # - that would blow the python call stack
957 957 # - obsolescence markers may have cycles, we need to handle them.
958 958 #
959 959 # The `toproceed` list act as our call stack. Every node we search
960 960 # successors set for are stacked there.
961 961 #
962 962 # The `stackedset` is set version of this stack used to check if a node is
963 963 # already stacked. This check is used to detect cycles and prevent infinite
964 964 # loop.
965 965 #
966 966 # successors set of all nodes are stored in the `cache` dictionary.
967 967 #
968 968 # After this while loop ends we use the cache to return the successors sets
969 969 # for the node requested by the caller.
970 970 while toproceed:
971 971 # Every iteration tries to compute the successors sets of the topmost
972 972 # node of the stack: CURRENT.
973 973 #
974 974 # There are four possible outcomes:
975 975 #
976 976 # 1) We already know the successors sets of CURRENT:
977 977 # -> mission accomplished, pop it from the stack.
978 978 # 2) Node is not obsolete:
979 979 # -> the node is its own successors sets. Add it to the cache.
980 980 # 3) We do not know successors set of direct successors of CURRENT:
981 981 # -> We add those successors to the stack.
982 982 # 4) We know successors sets of all direct successors of CURRENT:
983 983 # -> We can compute CURRENT successors set and add it to the
984 984 # cache.
985 985 #
986 986 current = toproceed[-1]
987 987 if current in cache:
988 988 # case (1): We already know the successors sets
989 989 stackedset.remove(toproceed.pop())
990 990 elif current not in succmarkers:
991 991 # case (2): The node is not obsolete.
992 992 if current in repo:
993 993 # We have a valid last successors.
994 994 cache[current] = [(current,)]
995 995 else:
996 996 # Final obsolete version is unknown locally.
997 997 # Do not count that as a valid successors
998 998 cache[current] = []
999 999 else:
1000 1000 # cases (3) and (4)
1001 1001 #
1002 1002 # We proceed in two phases. Phase 1 aims to distinguish case (3)
1003 1003 # from case (4):
1004 1004 #
1005 1005 # For each direct successors of CURRENT, we check whether its
1006 1006 # successors sets are known. If they are not, we stack the
1007 1007 # unknown node and proceed to the next iteration of the while
1008 1008 # loop. (case 3)
1009 1009 #
1010 1010 # During this step, we may detect obsolescence cycles: a node
1011 1011 # with unknown successors sets but already in the call stack.
1012 1012 # In such a situation, we arbitrary set the successors sets of
1013 1013 # the node to nothing (node pruned) to break the cycle.
1014 1014 #
1015 1015 # If no break was encountered we proceed to phase 2.
1016 1016 #
1017 1017 # Phase 2 computes successors sets of CURRENT (case 4); see details
1018 1018 # in phase 2 itself.
1019 1019 #
1020 1020 # Note the two levels of iteration in each phase.
1021 1021 # - The first one handles obsolescence markers using CURRENT as
1022 1022 # precursor (successors markers of CURRENT).
1023 1023 #
1024 1024 # Having multiple entry here means divergence.
1025 1025 #
1026 1026 # - The second one handles successors defined in each marker.
1027 1027 #
1028 1028 # Having none means pruned node, multiple successors means split,
1029 1029 # single successors are standard replacement.
1030 1030 #
1031 1031 for mark in sorted(succmarkers[current]):
1032 1032 for suc in mark[1]:
1033 1033 if suc not in cache:
1034 1034 if suc in stackedset:
1035 1035 # cycle breaking
1036 1036 cache[suc] = []
1037 1037 else:
1038 1038 # case (3) If we have not computed successors sets
1039 1039 # of one of those successors we add it to the
1040 1040 # `toproceed` stack and stop all work for this
1041 1041 # iteration.
1042 1042 toproceed.append(suc)
1043 1043 stackedset.add(suc)
1044 1044 break
1045 1045 else:
1046 1046 continue
1047 1047 break
1048 1048 else:
1049 1049 # case (4): we know all successors sets of all direct
1050 1050 # successors
1051 1051 #
1052 1052 # Successors set contributed by each marker depends on the
1053 1053 # successors sets of all its "successors" node.
1054 1054 #
1055 1055 # Each different marker is a divergence in the obsolescence
1056 1056 # history. It contributes successors sets distinct from other
1057 1057 # markers.
1058 1058 #
1059 1059 # Within a marker, a successor may have divergent successors
1060 1060 # sets. In such a case, the marker will contribute multiple
1061 1061 # divergent successors sets. If multiple successors have
1062 1062 # divergent successors sets, a Cartesian product is used.
1063 1063 #
1064 1064 # At the end we post-process successors sets to remove
1065 1065 # duplicated entry and successors set that are strict subset of
1066 1066 # another one.
1067 1067 succssets = []
1068 1068 for mark in sorted(succmarkers[current]):
1069 1069 # successors sets contributed by this marker
1070 1070 markss = [[]]
1071 1071 for suc in mark[1]:
1072 1072 # cardinal product with previous successors
1073 1073 productresult = []
1074 1074 for prefix in markss:
1075 1075 for suffix in cache[suc]:
1076 1076 newss = list(prefix)
1077 1077 for part in suffix:
1078 1078 # do not duplicated entry in successors set
1079 1079 # first entry wins.
1080 1080 if part not in newss:
1081 1081 newss.append(part)
1082 1082 productresult.append(newss)
1083 1083 markss = productresult
1084 1084 succssets.extend(markss)
1085 1085 # remove duplicated and subset
1086 1086 seen = []
1087 1087 final = []
1088 1088 candidate = sorted(((set(s), s) for s in succssets if s),
1089 1089 key=lambda x: len(x[1]), reverse=True)
1090 1090 for setversion, listversion in candidate:
1091 1091 for seenset in seen:
1092 1092 if setversion.issubset(seenset):
1093 1093 break
1094 1094 else:
1095 1095 final.append(listversion)
1096 1096 seen.append(setversion)
1097 1097 final.reverse() # put small successors set first
1098 1098 cache[current] = final
1099 1099 return cache[initialnode]
1100 1100
1101 1101 # mapping of 'set-name' -> <function to compute this set>
1102 1102 cachefuncs = {}
1103 1103 def cachefor(name):
1104 1104 """Decorator to register a function as computing the cache for a set"""
1105 1105 def decorator(func):
1106 1106 assert name not in cachefuncs
1107 1107 cachefuncs[name] = func
1108 1108 return func
1109 1109 return decorator
1110 1110
1111 1111 def getrevs(repo, name):
1112 1112 """Return the set of revision that belong to the <name> set
1113 1113
1114 1114 Such access may compute the set and cache it for future use"""
1115 1115 repo = repo.unfiltered()
1116 1116 if not repo.obsstore:
1117 1117 return frozenset()
1118 1118 if name not in repo.obsstore.caches:
1119 1119 repo.obsstore.caches[name] = cachefuncs[name](repo)
1120 1120 return repo.obsstore.caches[name]
1121 1121
1122 1122 # To be simple we need to invalidate obsolescence cache when:
1123 1123 #
1124 1124 # - new changeset is added:
1125 1125 # - public phase is changed
1126 1126 # - obsolescence marker are added
1127 1127 # - strip is used a repo
1128 1128 def clearobscaches(repo):
1129 1129 """Remove all obsolescence related cache from a repo
1130 1130
1131 1131 This remove all cache in obsstore is the obsstore already exist on the
1132 1132 repo.
1133 1133
1134 1134 (We could be smarter here given the exact event that trigger the cache
1135 1135 clearing)"""
1136 1136 # only clear cache is there is obsstore data in this repo
1137 1137 if 'obsstore' in repo._filecache:
1138 1138 repo.obsstore.caches.clear()
1139 1139
1140 1140 @cachefor('obsolete')
1141 1141 def _computeobsoleteset(repo):
1142 1142 """the set of obsolete revisions"""
1143 1143 obs = set()
1144 1144 getnode = repo.changelog.node
1145 1145 notpublic = repo._phasecache.getrevset(repo, (phases.draft, phases.secret))
1146 1146 for r in notpublic:
1147 1147 if getnode(r) in repo.obsstore.successors:
1148 1148 obs.add(r)
1149 1149 return obs
1150 1150
1151 1151 @cachefor('unstable')
1152 1152 def _computeunstableset(repo):
1153 1153 """the set of non obsolete revisions with obsolete parents"""
1154 1154 revs = [(ctx.rev(), ctx) for ctx in
1155 1155 repo.set('(not public()) and (not obsolete())')]
1156 1156 revs.sort(key=lambda x:x[0])
1157 1157 unstable = set()
1158 1158 for rev, ctx in revs:
1159 1159 # A rev is unstable if one of its parent is obsolete or unstable
1160 1160 # this works since we traverse following growing rev order
1161 1161 if any((x.obsolete() or (x.rev() in unstable))
1162 1162 for x in ctx.parents()):
1163 1163 unstable.add(rev)
1164 1164 return unstable
1165 1165
1166 1166 @cachefor('suspended')
1167 1167 def _computesuspendedset(repo):
1168 1168 """the set of obsolete parents with non obsolete descendants"""
1169 1169 suspended = repo.changelog.ancestors(getrevs(repo, 'unstable'))
1170 1170 return set(r for r in getrevs(repo, 'obsolete') if r in suspended)
1171 1171
1172 1172 @cachefor('extinct')
1173 1173 def _computeextinctset(repo):
1174 1174 """the set of obsolete parents without non obsolete descendants"""
1175 1175 return getrevs(repo, 'obsolete') - getrevs(repo, 'suspended')
1176 1176
1177 1177
1178 1178 @cachefor('bumped')
1179 1179 def _computebumpedset(repo):
1180 1180 """the set of revs trying to obsolete public revisions"""
1181 1181 bumped = set()
1182 1182 # util function (avoid attribute lookup in the loop)
1183 1183 phase = repo._phasecache.phase # would be faster to grab the full list
1184 1184 public = phases.public
1185 1185 cl = repo.changelog
1186 1186 torev = cl.nodemap.get
1187 1187 for ctx in repo.set('(not public()) and (not obsolete())'):
1188 1188 rev = ctx.rev()
1189 1189 # We only evaluate mutable, non-obsolete revision
1190 1190 node = ctx.node()
1191 1191 # (future) A cache of precursors may worth if split is very common
1192 1192 for pnode in allprecursors(repo.obsstore, [node],
1193 1193 ignoreflags=bumpedfix):
1194 1194 prev = torev(pnode) # unfiltered! but so is phasecache
1195 1195 if (prev is not None) and (phase(repo, prev) <= public):
1196 1196 # we have a public precursor
1197 1197 bumped.add(rev)
1198 1198 break # Next draft!
1199 1199 return bumped
1200 1200
1201 1201 @cachefor('divergent')
1202 1202 def _computedivergentset(repo):
1203 1203 """the set of rev that compete to be the final successors of some revision.
1204 1204 """
1205 1205 divergent = set()
1206 1206 obsstore = repo.obsstore
1207 1207 newermap = {}
1208 1208 for ctx in repo.set('(not public()) - obsolete()'):
1209 1209 mark = obsstore.precursors.get(ctx.node(), ())
1210 1210 toprocess = set(mark)
1211 1211 seen = set()
1212 1212 while toprocess:
1213 1213 prec = toprocess.pop()[0]
1214 1214 if prec in seen:
1215 1215 continue # emergency cycle hanging prevention
1216 1216 seen.add(prec)
1217 1217 if prec not in newermap:
1218 1218 successorssets(repo, prec, newermap)
1219 1219 newer = [n for n in newermap[prec] if n]
1220 1220 if len(newer) > 1:
1221 1221 divergent.add(ctx.rev())
1222 1222 break
1223 1223 toprocess.update(obsstore.precursors.get(prec, ()))
1224 1224 return divergent
1225 1225
1226 1226
1227 1227 def createmarkers(repo, relations, flag=0, date=None, metadata=None,
1228 1228 operation=None):
1229 1229 """Add obsolete markers between changesets in a repo
1230 1230
1231 1231 <relations> must be an iterable of (<old>, (<new>, ...)[,{metadata}])
1232 1232 tuple. `old` and `news` are changectx. metadata is an optional dictionary
1233 1233 containing metadata for this marker only. It is merged with the global
1234 1234 metadata specified through the `metadata` argument of this function,
1235 1235
1236 1236 Trying to obsolete a public changeset will raise an exception.
1237 1237
1238 1238 Current user and date are used except if specified otherwise in the
1239 1239 metadata attribute.
1240 1240
1241 1241 This function operates within a transaction of its own, but does
1242 1242 not take any lock on the repo.
1243 1243 """
1244 1244 # prepare metadata
1245 1245 if metadata is None:
1246 1246 metadata = {}
1247 1247 if 'user' not in metadata:
1248 1248 metadata['user'] = repo.ui.username()
1249 if operation:
1249 useoperation = repo.ui.configbool('experimental',
1250 'evolution.track-operation',
1251 False)
1252 if useoperation and operation:
1250 1253 metadata['operation'] = operation
1251 1254 tr = repo.transaction('add-obsolescence-marker')
1252 1255 try:
1253 1256 markerargs = []
1254 1257 for rel in relations:
1255 1258 prec = rel[0]
1256 1259 sucs = rel[1]
1257 1260 localmetadata = metadata.copy()
1258 1261 if 2 < len(rel):
1259 1262 localmetadata.update(rel[2])
1260 1263
1261 1264 if not prec.mutable():
1262 1265 raise error.Abort(_("cannot obsolete public changeset: %s")
1263 1266 % prec,
1264 1267 hint="see 'hg help phases' for details")
1265 1268 nprec = prec.node()
1266 1269 nsucs = tuple(s.node() for s in sucs)
1267 1270 npare = None
1268 1271 if not nsucs:
1269 1272 npare = tuple(p.node() for p in prec.parents())
1270 1273 if nprec in nsucs:
1271 1274 raise error.Abort(_("changeset %s cannot obsolete itself")
1272 1275 % prec)
1273 1276
1274 1277 # Creating the marker causes the hidden cache to become invalid,
1275 1278 # which causes recomputation when we ask for prec.parents() above.
1276 1279 # Resulting in n^2 behavior. So let's prepare all of the args
1277 1280 # first, then create the markers.
1278 1281 markerargs.append((nprec, nsucs, npare, localmetadata))
1279 1282
1280 1283 for args in markerargs:
1281 1284 nprec, nsucs, npare, localmetadata = args
1282 1285 repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
1283 1286 date=date, metadata=localmetadata)
1284 1287 repo.filteredrevcache.clear()
1285 1288 tr.close()
1286 1289 finally:
1287 1290 tr.release()
@@ -1,576 +1,578 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 Enable obsolete
4 4
5 5 $ cat >> $HGRCPATH << EOF
6 6 > [ui]
7 7 > logtemplate= {rev}:{node|short} {desc|firstline}
8 8 > [phases]
9 9 > publish=False
10 10 > [experimental]
11 11 > evolution=createmarkers,allowunstable
12 12 > [extensions]
13 13 > histedit=
14 14 > rebase=
15 15 > EOF
16 16
17 17 Test that histedit learns about obsolescence not stored in histedit state
18 18 $ hg init boo
19 19 $ cd boo
20 20 $ echo a > a
21 21 $ hg ci -Am a
22 22 adding a
23 23 $ echo a > b
24 24 $ echo a > c
25 25 $ echo a > c
26 26 $ hg ci -Am b
27 27 adding b
28 28 adding c
29 29 $ echo a > d
30 30 $ hg ci -Am c
31 31 adding d
32 32 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
33 33 $ echo "pick `hg log -r 2 -T '{node|short}'`" >> plan
34 34 $ echo "edit `hg log -r 1 -T '{node|short}'`" >> plan
35 35 $ hg histedit -r 'all()' --commands plan
36 36 Editing (1b2d564fad96), you may commit or record as needed now.
37 37 (hg histedit --continue to resume)
38 38 [1]
39 39 $ hg st
40 40 A b
41 41 A c
42 42 ? plan
43 43 $ hg commit --amend b
44 44 $ hg histedit --continue
45 45 $ hg log -G
46 46 @ 6:46abc7c4d873 b
47 47 |
48 48 o 5:49d44ab2be1b c
49 49 |
50 50 o 0:cb9a9f314b8b a
51 51
52 52 $ hg debugobsolete
53 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'operation': 'amend', 'user': 'test'} (glob)
54 3e30a45cf2f719e96ab3922dfe039cfd047956ce 0 {e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf} (*) {'operation': 'amend', 'user': 'test'} (glob)
55 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
56 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
53 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'user': 'test'} (glob)
54 3e30a45cf2f719e96ab3922dfe039cfd047956ce 0 {e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf} (*) {'user': 'test'} (glob)
55 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (*) {'user': 'test'} (glob)
56 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'user': 'test'} (glob)
57 57
58 58 With some node gone missing during the edit.
59 59
60 60 $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
61 61 $ echo "pick `hg log -r 6 -T '{node|short}'`" >> plan
62 62 $ echo "edit `hg log -r 5 -T '{node|short}'`" >> plan
63 63 $ hg histedit -r 'all()' --commands plan
64 64 Editing (49d44ab2be1b), you may commit or record as needed now.
65 65 (hg histedit --continue to resume)
66 66 [1]
67 67 $ hg st
68 68 A b
69 69 A d
70 70 ? plan
71 71 $ hg commit --amend -X . -m XXXXXX
72 72 $ hg commit --amend -X . -m b2
73 73 $ hg --hidden --config extensions.strip= strip 'desc(XXXXXX)' --no-backup
74 74 $ hg histedit --continue
75 75 $ hg log -G
76 76 @ 9:273c1f3b8626 c
77 77 |
78 78 o 8:aba7da937030 b2
79 79 |
80 80 o 0:cb9a9f314b8b a
81 81
82 82 $ hg debugobsolete
83 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'operation': 'amend', 'user': 'test'} (glob)
84 3e30a45cf2f719e96ab3922dfe039cfd047956ce 0 {e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf} (*) {'operation': 'amend', 'user': 'test'} (glob)
85 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
86 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
87 76f72745eac0643d16530e56e2f86e36e40631f1 2ca853e48edbd6453a0674dc0fe28a0974c51b9c 0 (*) {'operation': 'amend', 'user': 'test'} (glob)
88 2ca853e48edbd6453a0674dc0fe28a0974c51b9c aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (*) {'operation': 'amend', 'user': 'test'} (glob)
89 49d44ab2be1b67a79127568a67c9c99430633b48 273c1f3b86267ed3ec684bb13af1fa4d6ba56e02 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
90 46abc7c4d8738e8563e577f7889e1b6db3da4199 aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
83 e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'user': 'test'} (glob)
84 3e30a45cf2f719e96ab3922dfe039cfd047956ce 0 {e72d22b19f8ecf4150ab4f91d0973fd9955d3ddf} (*) {'user': 'test'} (glob)
85 1b2d564fad96311b45362f17c2aa855150efb35f 46abc7c4d8738e8563e577f7889e1b6db3da4199 0 (*) {'user': 'test'} (glob)
86 114f4176969ef342759a8a57e6bccefc4234829b 49d44ab2be1b67a79127568a67c9c99430633b48 0 (*) {'user': 'test'} (glob)
87 76f72745eac0643d16530e56e2f86e36e40631f1 2ca853e48edbd6453a0674dc0fe28a0974c51b9c 0 (*) {'user': 'test'} (glob)
88 2ca853e48edbd6453a0674dc0fe28a0974c51b9c aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (*) {'user': 'test'} (glob)
89 49d44ab2be1b67a79127568a67c9c99430633b48 273c1f3b86267ed3ec684bb13af1fa4d6ba56e02 0 (*) {'user': 'test'} (glob)
90 46abc7c4d8738e8563e577f7889e1b6db3da4199 aba7da93703075eec9fb1dbaf143ff2bc1c49d46 0 (*) {'user': 'test'} (glob)
91 91 $ cd ..
92 92
93 93 Base setup for the rest of the testing
94 94 ======================================
95 95
96 96 $ hg init base
97 97 $ cd base
98 98
99 99 $ for x in a b c d e f ; do
100 100 > echo $x > $x
101 101 > hg add $x
102 102 > hg ci -m $x
103 103 > done
104 104
105 105 $ hg log --graph
106 106 @ 5:652413bf663e f
107 107 |
108 108 o 4:e860deea161a e
109 109 |
110 110 o 3:055a42cdd887 d
111 111 |
112 112 o 2:177f92b77385 c
113 113 |
114 114 o 1:d2ae7f538514 b
115 115 |
116 116 o 0:cb9a9f314b8b a
117 117
118 118
119 119 $ HGEDITOR=cat hg histedit 1
120 120 pick d2ae7f538514 1 b
121 121 pick 177f92b77385 2 c
122 122 pick 055a42cdd887 3 d
123 123 pick e860deea161a 4 e
124 124 pick 652413bf663e 5 f
125 125
126 126 # Edit history between d2ae7f538514 and 652413bf663e
127 127 #
128 128 # Commits are listed from least to most recent
129 129 #
130 130 # You can reorder changesets by reordering the lines
131 131 #
132 132 # Commands:
133 133 #
134 134 # e, edit = use commit, but stop for amending
135 135 # m, mess = edit commit message without changing commit content
136 136 # p, pick = use commit
137 137 # d, drop = remove commit from history
138 138 # f, fold = use commit, but combine it with the one above
139 139 # r, roll = like fold, but discard this commit's description and date
140 140 #
141 141 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
142 142 > pick 177f92b77385 2 c
143 143 > drop d2ae7f538514 1 b
144 144 > pick 055a42cdd887 3 d
145 145 > fold e860deea161a 4 e
146 146 > pick 652413bf663e 5 f
147 147 > EOF
148 148 [1]
149 149 $ hg log --graph --hidden
150 150 @ 10:cacdfd884a93 f
151 151 |
152 152 o 9:59d9f330561f d
153 153 |
154 154 | x 8:b558abc46d09 fold-temp-revision e860deea161a
155 155 | |
156 156 | x 7:96e494a2d553 d
157 157 |/
158 158 o 6:b346ab9a313d c
159 159 |
160 160 | x 5:652413bf663e f
161 161 | |
162 162 | x 4:e860deea161a e
163 163 | |
164 164 | x 3:055a42cdd887 d
165 165 | |
166 166 | x 2:177f92b77385 c
167 167 | |
168 168 | x 1:d2ae7f538514 b
169 169 |/
170 170 o 0:cb9a9f314b8b a
171 171
172 172 $ hg debugobsolete
173 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (*) {'operation': 'histedit', 'user': 'test'} (glob)
174 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (*) {'operation': 'histedit', 'user': 'test'} (glob)
175 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'operation': 'histedit', 'user': 'test'} (glob)
176 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
177 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
178 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
179 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
173 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (*) {'user': 'test'} (glob)
174 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (*) {'user': 'test'} (glob)
175 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
176 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
177 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
178 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
179 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
180 180
181 181
182 182 Ensure hidden revision does not prevent histedit
183 183 -------------------------------------------------
184 184
185 185 create an hidden revision
186 186
187 187 $ hg histedit 6 --commands - << EOF
188 188 > pick b346ab9a313d 6 c
189 189 > drop 59d9f330561f 7 d
190 190 > pick cacdfd884a93 8 f
191 191 > EOF
192 192 $ hg log --graph
193 193 @ 11:c13eb81022ca f
194 194 |
195 195 o 6:b346ab9a313d c
196 196 |
197 197 o 0:cb9a9f314b8b a
198 198
199 199 check hidden revision are ignored (6 have hidden children 7 and 8)
200 200
201 201 $ hg histedit 6 --commands - << EOF
202 202 > pick b346ab9a313d 6 c
203 203 > pick c13eb81022ca 8 f
204 204 > EOF
205 205
206 206
207 207
208 208 Test that rewriting leaving instability behind is allowed
209 209 ---------------------------------------------------------------------
210 210
211 211 $ hg up '.^'
212 212 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
213 213 $ hg log -r 'children(.)'
214 214 11:c13eb81022ca f (no-eol)
215 215 $ hg histedit -r '.' --commands - <<EOF
216 216 > edit b346ab9a313d 6 c
217 217 > EOF
218 218 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
219 219 adding c
220 220 Editing (b346ab9a313d), you may commit or record as needed now.
221 221 (hg histedit --continue to resume)
222 222 [1]
223 223 $ echo c >> c
224 224 $ hg histedit --continue
225 225
226 226 $ hg log -r 'unstable()'
227 227 11:c13eb81022ca f (no-eol)
228 228
229 229 stabilise
230 230
231 231 $ hg rebase -r 'unstable()' -d .
232 232 rebasing 11:c13eb81022ca "f"
233 233 $ hg up tip -q
234 234
235 235 Test dropping of changeset on the top of the stack
236 236 -------------------------------------------------------
237 237
238 238 Nothing is rewritten below, the working directory parent must be change for the
239 239 dropped changeset to be hidden.
240 240
241 241 $ cd ..
242 242 $ hg clone base droplast
243 243 updating to branch default
244 244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 245 $ cd droplast
246 246 $ hg histedit -r '40db8afa467b' --commands - << EOF
247 247 > pick 40db8afa467b 10 c
248 248 > drop b449568bf7fc 11 f
249 249 > EOF
250 250 $ hg log -G
251 251 @ 12:40db8afa467b c
252 252 |
253 253 o 0:cb9a9f314b8b a
254 254
255 255
256 256 With rewritten ancestors
257 257
258 258 $ echo e > e
259 259 $ hg add e
260 260 $ hg commit -m g
261 261 $ echo f > f
262 262 $ hg add f
263 263 $ hg commit -m h
264 264 $ hg histedit -r '40db8afa467b' --commands - << EOF
265 265 > pick 47a8561c0449 12 g
266 266 > pick 40db8afa467b 10 c
267 267 > drop 1b3b05f35ff0 13 h
268 268 > EOF
269 269 $ hg log -G
270 270 @ 17:ee6544123ab8 c
271 271 |
272 272 o 16:269e713e9eae g
273 273 |
274 274 o 0:cb9a9f314b8b a
275 275
276 276 $ cd ../base
277 277
278 278
279 279
280 280 Test phases support
281 281 ===========================================
282 282
283 283 Check that histedit respect immutability
284 284 -------------------------------------------
285 285
286 286 $ cat >> $HGRCPATH << EOF
287 287 > [ui]
288 288 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
289 289 > EOF
290 290
291 291 $ hg ph -pv '.^'
292 292 phase changed for 2 changesets
293 293 $ hg log -G
294 294 @ 13:b449568bf7fc (draft) f
295 295 |
296 296 o 12:40db8afa467b (public) c
297 297 |
298 298 o 0:cb9a9f314b8b (public) a
299 299
300 300 $ hg histedit -r '.~2'
301 301 abort: cannot edit public changeset: cb9a9f314b8b
302 302 (see 'hg help phases' for details)
303 303 [255]
304 304
305 305
306 306 Prepare further testing
307 307 -------------------------------------------
308 308
309 309 $ for x in g h i j k ; do
310 310 > echo $x > $x
311 311 > hg add $x
312 312 > hg ci -m $x
313 313 > done
314 314 $ hg phase --force --secret .~2
315 315 $ hg log -G
316 316 @ 18:ee118ab9fa44 (secret) k
317 317 |
318 318 o 17:3a6c53ee7f3d (secret) j
319 319 |
320 320 o 16:b605fb7503f2 (secret) i
321 321 |
322 322 o 15:7395e1ff83bd (draft) h
323 323 |
324 324 o 14:6b70183d2492 (draft) g
325 325 |
326 326 o 13:b449568bf7fc (draft) f
327 327 |
328 328 o 12:40db8afa467b (public) c
329 329 |
330 330 o 0:cb9a9f314b8b (public) a
331 331
332 332 $ cd ..
333 333
334 334 simple phase conservation
335 335 -------------------------------------------
336 336
337 337 Resulting changeset should conserve the phase of the original one whatever the
338 338 phases.new-commit option is.
339 339
340 340 New-commit as draft (default)
341 341
342 342 $ cp -R base simple-draft
343 343 $ cd simple-draft
344 344 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
345 345 > edit b449568bf7fc 11 f
346 346 > pick 6b70183d2492 12 g
347 347 > pick 7395e1ff83bd 13 h
348 348 > pick b605fb7503f2 14 i
349 349 > pick 3a6c53ee7f3d 15 j
350 350 > pick ee118ab9fa44 16 k
351 351 > EOF
352 352 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
353 353 adding f
354 354 Editing (b449568bf7fc), you may commit or record as needed now.
355 355 (hg histedit --continue to resume)
356 356 [1]
357 357 $ echo f >> f
358 358 $ hg histedit --continue
359 359 $ hg log -G
360 360 @ 24:12e89af74238 (secret) k
361 361 |
362 362 o 23:636a8687b22e (secret) j
363 363 |
364 364 o 22:ccaf0a38653f (secret) i
365 365 |
366 366 o 21:11a89d1c2613 (draft) h
367 367 |
368 368 o 20:c1dec7ca82ea (draft) g
369 369 |
370 370 o 19:087281e68428 (draft) f
371 371 |
372 372 o 12:40db8afa467b (public) c
373 373 |
374 374 o 0:cb9a9f314b8b (public) a
375 375
376 376 $ cd ..
377 377
378 378
379 379 New-commit as secret (config)
380 380
381 381 $ cp -R base simple-secret
382 382 $ cd simple-secret
383 383 $ cat >> .hg/hgrc << EOF
384 384 > [phases]
385 385 > new-commit=secret
386 386 > EOF
387 387 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
388 388 > edit b449568bf7fc 11 f
389 389 > pick 6b70183d2492 12 g
390 390 > pick 7395e1ff83bd 13 h
391 391 > pick b605fb7503f2 14 i
392 392 > pick 3a6c53ee7f3d 15 j
393 393 > pick ee118ab9fa44 16 k
394 394 > EOF
395 395 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
396 396 adding f
397 397 Editing (b449568bf7fc), you may commit or record as needed now.
398 398 (hg histedit --continue to resume)
399 399 [1]
400 400 $ echo f >> f
401 401 $ hg histedit --continue
402 402 $ hg log -G
403 403 @ 24:12e89af74238 (secret) k
404 404 |
405 405 o 23:636a8687b22e (secret) j
406 406 |
407 407 o 22:ccaf0a38653f (secret) i
408 408 |
409 409 o 21:11a89d1c2613 (draft) h
410 410 |
411 411 o 20:c1dec7ca82ea (draft) g
412 412 |
413 413 o 19:087281e68428 (draft) f
414 414 |
415 415 o 12:40db8afa467b (public) c
416 416 |
417 417 o 0:cb9a9f314b8b (public) a
418 418
419 419 $ cd ..
420 420
421 421
422 422 Changeset reordering
423 423 -------------------------------------------
424 424
425 425 If a secret changeset is put before a draft one, all descendant should be secret.
426 426 It seems more important to present the secret phase.
427 427
428 428 $ cp -R base reorder
429 429 $ cd reorder
430 430 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
431 431 > pick b449568bf7fc 11 f
432 432 > pick 3a6c53ee7f3d 15 j
433 433 > pick 6b70183d2492 12 g
434 434 > pick b605fb7503f2 14 i
435 435 > pick 7395e1ff83bd 13 h
436 436 > pick ee118ab9fa44 16 k
437 437 > EOF
438 438 $ hg log -G
439 439 @ 23:558246857888 (secret) k
440 440 |
441 441 o 22:28bd44768535 (secret) h
442 442 |
443 443 o 21:d5395202aeb9 (secret) i
444 444 |
445 445 o 20:21edda8e341b (secret) g
446 446 |
447 447 o 19:5ab64f3a4832 (secret) j
448 448 |
449 449 o 13:b449568bf7fc (draft) f
450 450 |
451 451 o 12:40db8afa467b (public) c
452 452 |
453 453 o 0:cb9a9f314b8b (public) a
454 454
455 455 $ cd ..
456 456
457 457 Changeset folding
458 458 -------------------------------------------
459 459
460 460 Folding a secret changeset with a draft one turn the result secret (again,
461 461 better safe than sorry). Folding between same phase changeset still works
462 462
463 463 Note that there is a few reordering in this series for more extensive test
464 464
465 465 $ cp -R base folding
466 466 $ cd folding
467 467 $ cat >> .hg/hgrc << EOF
468 468 > [phases]
469 469 > new-commit=secret
470 470 > EOF
471 471 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
472 472 > pick 7395e1ff83bd 13 h
473 473 > fold b449568bf7fc 11 f
474 474 > pick 6b70183d2492 12 g
475 475 > fold 3a6c53ee7f3d 15 j
476 476 > pick b605fb7503f2 14 i
477 477 > fold ee118ab9fa44 16 k
478 478 > EOF
479 479 $ hg log -G
480 480 @ 27:f9daec13fb98 (secret) i
481 481 |
482 482 o 24:49807617f46a (secret) g
483 483 |
484 484 o 21:050280826e04 (draft) h
485 485 |
486 486 o 12:40db8afa467b (public) c
487 487 |
488 488 o 0:cb9a9f314b8b (public) a
489 489
490 490 $ hg co 49807617f46a
491 491 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
492 492 $ echo wat >> wat
493 493 $ hg add wat
494 494 $ hg ci -m 'add wat'
495 495 created new head
496 496 $ hg merge f9daec13fb98
497 497 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 498 (branch merge, don't forget to commit)
499 499 $ hg ci -m 'merge'
500 500 $ echo not wat > wat
501 501 $ hg ci -m 'modify wat'
502 502 $ hg histedit 050280826e04
503 503 abort: cannot edit history that contains merges
504 504 [255]
505 505 $ cd ..
506 506
507 507 Check abort behavior
508 508 -------------------------------------------
509 509
510 510 We checks that abort properly clean the repository so the same histedit can be
511 511 attempted later.
512 512
513 513 $ cp -R base abort
514 514 $ cd abort
515 515 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
516 516 > pick b449568bf7fc 13 f
517 517 > pick 7395e1ff83bd 15 h
518 518 > pick 6b70183d2492 14 g
519 519 > pick b605fb7503f2 16 i
520 520 > roll 3a6c53ee7f3d 17 j
521 521 > edit ee118ab9fa44 18 k
522 522 > EOF
523 523 Editing (ee118ab9fa44), you may commit or record as needed now.
524 524 (hg histedit --continue to resume)
525 525 [1]
526 526
527 527 $ hg histedit --abort
528 528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
529 529 saved backup bundle to $TESTTMP/abort/.hg/strip-backup/4dc06258baa6-dff4ef05-backup.hg (glob)
530 530
531 531 $ hg log -G
532 532 @ 18:ee118ab9fa44 (secret) k
533 533 |
534 534 o 17:3a6c53ee7f3d (secret) j
535 535 |
536 536 o 16:b605fb7503f2 (secret) i
537 537 |
538 538 o 15:7395e1ff83bd (draft) h
539 539 |
540 540 o 14:6b70183d2492 (draft) g
541 541 |
542 542 o 13:b449568bf7fc (draft) f
543 543 |
544 544 o 12:40db8afa467b (public) c
545 545 |
546 546 o 0:cb9a9f314b8b (public) a
547 547
548 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
548 $ hg histedit -r 'b449568bf7fc' --commands - << EOF --config experimental.evolution.track-operation=1
549 549 > pick b449568bf7fc 13 f
550 550 > pick 7395e1ff83bd 15 h
551 551 > pick 6b70183d2492 14 g
552 552 > pick b605fb7503f2 16 i
553 553 > pick 3a6c53ee7f3d 17 j
554 554 > edit ee118ab9fa44 18 k
555 555 > EOF
556 556 Editing (ee118ab9fa44), you may commit or record as needed now.
557 557 (hg histedit --continue to resume)
558 558 [1]
559 $ hg histedit --continue
559 $ hg histedit --continue --config experimental.evolution.track-operation=1
560 560 $ hg log -G
561 561 @ 23:175d6b286a22 (secret) k
562 562 |
563 563 o 22:44ca09d59ae4 (secret) j
564 564 |
565 565 o 21:31747692a644 (secret) i
566 566 |
567 567 o 20:9985cd4f21fa (draft) g
568 568 |
569 569 o 19:4dc06258baa6 (draft) h
570 570 |
571 571 o 13:b449568bf7fc (draft) f
572 572 |
573 573 o 12:40db8afa467b (public) c
574 574 |
575 575 o 0:cb9a9f314b8b (public) a
576 576
577 $ hg debugobsolete --rev .
578 ee118ab9fa44ebb86be85996548b5517a39e5093 175d6b286a224c23f192e79a581ce83131a53fa2 0 (*) {'operation': 'histedit', 'user': 'test'} (glob)
@@ -1,1284 +1,1284 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(troubles, ' {troubles}')}) [{tags} {bookmarks}] {desc|firstline}\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('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=createmarkers,exchange
43 43 > EOF
44 44
45 45 Killing a single changeset without replacement
46 46
47 47 $ hg debugobsolete 0
48 48 abort: changeset references must be full hexadecimal node identifiers
49 49 [255]
50 50 $ hg debugobsolete '00'
51 51 abort: changeset references must be full hexadecimal node identifiers
52 52 [255]
53 53 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
54 54 $ hg debugobsolete
55 55 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
56 56
57 57 (test that mercurial is not confused)
58 58
59 59 $ hg up null --quiet # having 0 as parent prevents it to be hidden
60 60 $ hg tip
61 61 -1:000000000000 (public) [tip ]
62 62 $ hg up --hidden tip --quiet
63 63
64 64 Killing a single changeset with itself should fail
65 65 (simple local safeguard)
66 66
67 67 $ hg debugobsolete `getid kill_me` `getid kill_me`
68 68 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
69 69 [255]
70 70
71 71 $ cd ..
72 72
73 73 Killing a single changeset with replacement
74 74 (and testing the format option)
75 75
76 76 $ hg init tmpb
77 77 $ cd tmpb
78 78 $ mkcommit a
79 79 $ mkcommit b
80 80 $ mkcommit original_c
81 81 $ hg up "desc('b')"
82 82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 83 $ mkcommit new_c
84 84 created new head
85 85 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
86 86 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
87 87 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
88 88 2:245bde4270cd add original_c
89 89 $ hg debugrevlog -cd
90 90 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
91 91 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
92 92 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
93 93 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
94 94 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
95 95 $ hg debugobsolete
96 96 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
97 97
98 98 (check for version number of the obsstore)
99 99
100 100 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
101 101 \x00 (no-eol) (esc)
102 102
103 103 do it again (it read the obsstore before adding new changeset)
104 104
105 105 $ hg up '.^'
106 106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 107 $ mkcommit new_2_c
108 108 created new head
109 109 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
110 110 $ hg debugobsolete
111 111 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
112 112 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
113 113
114 114 Register two markers with a missing node
115 115
116 116 $ hg up '.^'
117 117 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
118 118 $ mkcommit new_3_c
119 119 created new head
120 120 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
121 121 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
122 122 $ hg debugobsolete
123 123 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
124 124 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
125 125 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
126 126 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
127 127
128 128 Test the --index option of debugobsolete command
129 129 $ hg debugobsolete --index
130 130 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
131 131 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
132 132 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
133 133 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
134 134
135 135 Refuse pathological nullid successors
136 136 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
137 137 transaction abort!
138 138 rollback completed
139 139 abort: bad obsolescence marker detected: invalid successors nullid
140 140 [255]
141 141
142 142 Check that graphlog detect that a changeset is obsolete:
143 143
144 144 $ hg log -G
145 145 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
146 146 |
147 147 o 1:7c3bad9141dc (draft) [ ] add b
148 148 |
149 149 o 0:1f0dee641bb7 (draft) [ ] add a
150 150
151 151
152 152 check that heads does not report them
153 153
154 154 $ hg heads
155 155 5:5601fb93a350 (draft) [tip ] add new_3_c
156 156 $ hg heads --hidden
157 157 5:5601fb93a350 (draft) [tip ] add new_3_c
158 158 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c
159 159 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c
160 160 2:245bde4270cd (draft *obsolete*) [ ] add original_c
161 161
162 162
163 163 check that summary does not report them
164 164
165 165 $ hg init ../sink
166 166 $ echo '[paths]' >> .hg/hgrc
167 167 $ echo 'default=../sink' >> .hg/hgrc
168 168 $ hg summary --remote
169 169 parent: 5:5601fb93a350 tip
170 170 add new_3_c
171 171 branch: default
172 172 commit: (clean)
173 173 update: (current)
174 174 phases: 3 draft
175 175 remote: 3 outgoing
176 176
177 177 $ hg summary --remote --hidden
178 178 parent: 5:5601fb93a350 tip
179 179 add new_3_c
180 180 branch: default
181 181 commit: (clean)
182 182 update: 3 new changesets, 4 branch heads (merge)
183 183 phases: 6 draft
184 184 remote: 3 outgoing
185 185
186 186 check that various commands work well with filtering
187 187
188 188 $ hg tip
189 189 5:5601fb93a350 (draft) [tip ] add new_3_c
190 190 $ hg log -r 6
191 191 abort: unknown revision '6'!
192 192 [255]
193 193 $ hg log -r 4
194 194 abort: hidden revision '4'!
195 195 (use --hidden to access hidden revisions)
196 196 [255]
197 197 $ hg debugrevspec 'rev(6)'
198 198 $ hg debugrevspec 'rev(4)'
199 199 $ hg debugrevspec 'null'
200 200 -1
201 201
202 202 Check that public changeset are not accounted as obsolete:
203 203
204 204 $ hg --hidden phase --public 2
205 205 $ hg log -G
206 206 @ 5:5601fb93a350 (draft bumped) [tip ] add new_3_c
207 207 |
208 208 | o 2:245bde4270cd (public) [ ] add original_c
209 209 |/
210 210 o 1:7c3bad9141dc (public) [ ] add b
211 211 |
212 212 o 0:1f0dee641bb7 (public) [ ] add a
213 213
214 214
215 215 And that bumped changeset are detected
216 216 --------------------------------------
217 217
218 218 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
219 219 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
220 220 the public changeset
221 221
222 222 $ hg log --hidden -r 'bumped()'
223 223 5:5601fb93a350 (draft bumped) [tip ] add new_3_c
224 224
225 225 And that we can't push bumped changeset
226 226
227 227 $ hg push ../tmpa -r 0 --force #(make repo related)
228 228 pushing to ../tmpa
229 229 searching for changes
230 230 warning: repository is unrelated
231 231 adding changesets
232 232 adding manifests
233 233 adding file changes
234 234 added 1 changesets with 1 changes to 1 files (+1 heads)
235 235 $ hg push ../tmpa
236 236 pushing to ../tmpa
237 237 searching for changes
238 238 abort: push includes bumped changeset: 5601fb93a350!
239 239 [255]
240 240
241 241 Fixing "bumped" situation
242 242 We need to create a clone of 5 and add a special marker with a flag
243 243
244 244 $ hg summary
245 245 parent: 5:5601fb93a350 tip (bumped)
246 246 add new_3_c
247 247 branch: default
248 248 commit: (clean)
249 249 update: 1 new changesets, 2 branch heads (merge)
250 250 phases: 1 draft
251 251 bumped: 1 changesets
252 252 $ hg up '5^'
253 253 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
254 254 $ hg revert -ar 5
255 255 adding new_3_c
256 256 $ hg ci -m 'add n3w_3_c'
257 257 created new head
258 258 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
259 259 $ hg log -r 'bumped()'
260 260 $ hg log -G
261 261 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
262 262 |
263 263 | o 2:245bde4270cd (public) [ ] add original_c
264 264 |/
265 265 o 1:7c3bad9141dc (public) [ ] add b
266 266 |
267 267 o 0:1f0dee641bb7 (public) [ ] add a
268 268
269 269
270 270 $ cd ..
271 271
272 272 Revision 0 is hidden
273 273 --------------------
274 274
275 275 $ hg init rev0hidden
276 276 $ cd rev0hidden
277 277
278 278 $ mkcommit kill0
279 279 $ hg up -q null
280 280 $ hg debugobsolete `getid kill0`
281 281 $ mkcommit a
282 282 $ mkcommit b
283 283
284 284 Should pick the first visible revision as "repo" node
285 285
286 286 $ hg archive ../archive-null
287 287 $ cat ../archive-null/.hg_archival.txt
288 288 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
289 289 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
290 290 branch: default
291 291 latesttag: null
292 292 latesttagdistance: 2
293 293 changessincelatesttag: 2
294 294
295 295
296 296 $ cd ..
297 297
298 298 Exchange Test
299 299 ============================
300 300
301 301 Destination repo does not have any data
302 302 ---------------------------------------
303 303
304 304 Simple incoming test
305 305
306 306 $ hg init tmpc
307 307 $ cd tmpc
308 308 $ hg incoming ../tmpb
309 309 comparing with ../tmpb
310 310 0:1f0dee641bb7 (public) [ ] add a
311 311 1:7c3bad9141dc (public) [ ] add b
312 312 2:245bde4270cd (public) [ ] add original_c
313 313 6:6f9641995072 (draft) [tip ] add n3w_3_c
314 314
315 315 Try to pull markers
316 316 (extinct changeset are excluded but marker are pushed)
317 317
318 318 $ hg pull ../tmpb
319 319 pulling from ../tmpb
320 320 requesting all changes
321 321 adding changesets
322 322 adding manifests
323 323 adding file changes
324 324 added 4 changesets with 4 changes to 4 files (+1 heads)
325 325 5 new obsolescence markers
326 326 (run 'hg heads' to see heads, 'hg merge' to merge)
327 327 $ hg debugobsolete
328 328 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
329 329 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
330 330 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
331 331 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
332 332 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
333 333
334 334 Rollback//Transaction support
335 335
336 336 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
337 337 $ hg debugobsolete
338 338 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
339 339 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
340 340 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
341 341 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
342 342 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
343 343 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
344 344 $ hg rollback -n
345 345 repository tip rolled back to revision 3 (undo debugobsolete)
346 346 $ hg rollback
347 347 repository tip rolled back to revision 3 (undo debugobsolete)
348 348 $ hg debugobsolete
349 349 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
350 350 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
351 351 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
352 352 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
353 353 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
354 354
355 355 $ cd ..
356 356
357 357 Try to push markers
358 358
359 359 $ hg init tmpd
360 360 $ hg -R tmpb push tmpd
361 361 pushing to tmpd
362 362 searching for changes
363 363 adding changesets
364 364 adding manifests
365 365 adding file changes
366 366 added 4 changesets with 4 changes to 4 files (+1 heads)
367 367 5 new obsolescence markers
368 368 $ hg -R tmpd debugobsolete | sort
369 369 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
370 370 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
371 371 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
372 372 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
373 373 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
374 374
375 375 Check obsolete keys are exchanged only if source has an obsolete store
376 376
377 377 $ hg init empty
378 378 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
379 379 pushing to tmpd
380 380 listkeys phases
381 381 listkeys bookmarks
382 382 no changes found
383 383 listkeys phases
384 384 [1]
385 385
386 386 clone support
387 387 (markers are copied and extinct changesets are included to allow hardlinks)
388 388
389 389 $ hg clone tmpb clone-dest
390 390 updating to branch default
391 391 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 392 $ hg -R clone-dest log -G --hidden
393 393 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
394 394 |
395 395 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c
396 396 |/
397 397 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c
398 398 |/
399 399 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c
400 400 |/
401 401 | o 2:245bde4270cd (public) [ ] add original_c
402 402 |/
403 403 o 1:7c3bad9141dc (public) [ ] add b
404 404 |
405 405 o 0:1f0dee641bb7 (public) [ ] add a
406 406
407 407 $ hg -R clone-dest debugobsolete
408 408 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
409 409 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
410 410 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
411 411 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
412 412 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
413 413
414 414
415 415 Destination repo have existing data
416 416 ---------------------------------------
417 417
418 418 On pull
419 419
420 420 $ hg init tmpe
421 421 $ cd tmpe
422 422 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
423 423 $ hg pull ../tmpb
424 424 pulling from ../tmpb
425 425 requesting all changes
426 426 adding changesets
427 427 adding manifests
428 428 adding file changes
429 429 added 4 changesets with 4 changes to 4 files (+1 heads)
430 430 5 new obsolescence markers
431 431 (run 'hg heads' to see heads, 'hg merge' to merge)
432 432 $ hg debugobsolete
433 433 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
434 434 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
435 435 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
436 436 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
437 437 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
438 438 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
439 439
440 440
441 441 On push
442 442
443 443 $ hg push ../tmpc
444 444 pushing to ../tmpc
445 445 searching for changes
446 446 no changes found
447 447 1 new obsolescence markers
448 448 [1]
449 449 $ hg -R ../tmpc debugobsolete
450 450 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
451 451 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
452 452 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
453 453 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
454 454 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
455 455 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
456 456
457 457 detect outgoing obsolete and unstable
458 458 ---------------------------------------
459 459
460 460
461 461 $ hg log -G
462 462 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
463 463 |
464 464 | o 2:245bde4270cd (public) [ ] add original_c
465 465 |/
466 466 o 1:7c3bad9141dc (public) [ ] add b
467 467 |
468 468 o 0:1f0dee641bb7 (public) [ ] add a
469 469
470 470 $ hg up 'desc("n3w_3_c")'
471 471 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 472 $ mkcommit original_d
473 473 $ mkcommit original_e
474 474 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
475 475 $ hg debugobsolete | grep `getid original_d`
476 476 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
477 477 $ hg log -r 'obsolete()'
478 478 4:94b33453f93b (draft *obsolete*) [ ] add original_d
479 479 $ hg summary
480 480 parent: 5:cda648ca50f5 tip (unstable)
481 481 add original_e
482 482 branch: default
483 483 commit: (clean)
484 484 update: 1 new changesets, 2 branch heads (merge)
485 485 phases: 3 draft
486 486 unstable: 1 changesets
487 487 $ hg log -G -r '::unstable()'
488 488 @ 5:cda648ca50f5 (draft unstable) [tip ] add original_e
489 489 |
490 490 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d
491 491 |
492 492 o 3:6f9641995072 (draft) [ ] add n3w_3_c
493 493 |
494 494 o 1:7c3bad9141dc (public) [ ] add b
495 495 |
496 496 o 0:1f0dee641bb7 (public) [ ] add a
497 497
498 498
499 499 refuse to push obsolete changeset
500 500
501 501 $ hg push ../tmpc/ -r 'desc("original_d")'
502 502 pushing to ../tmpc/
503 503 searching for changes
504 504 abort: push includes obsolete changeset: 94b33453f93b!
505 505 [255]
506 506
507 507 refuse to push unstable changeset
508 508
509 509 $ hg push ../tmpc/
510 510 pushing to ../tmpc/
511 511 searching for changes
512 512 abort: push includes unstable changeset: cda648ca50f5!
513 513 [255]
514 514
515 515 Test that extinct changeset are properly detected
516 516
517 517 $ hg log -r 'extinct()'
518 518
519 519 Don't try to push extinct changeset
520 520
521 521 $ hg init ../tmpf
522 522 $ hg out ../tmpf
523 523 comparing with ../tmpf
524 524 searching for changes
525 525 0:1f0dee641bb7 (public) [ ] add a
526 526 1:7c3bad9141dc (public) [ ] add b
527 527 2:245bde4270cd (public) [ ] add original_c
528 528 3:6f9641995072 (draft) [ ] add n3w_3_c
529 529 4:94b33453f93b (draft *obsolete*) [ ] add original_d
530 530 5:cda648ca50f5 (draft unstable) [tip ] add original_e
531 531 $ hg push ../tmpf -f # -f because be push unstable too
532 532 pushing to ../tmpf
533 533 searching for changes
534 534 adding changesets
535 535 adding manifests
536 536 adding file changes
537 537 added 6 changesets with 6 changes to 6 files (+1 heads)
538 538 7 new obsolescence markers
539 539
540 540 no warning displayed
541 541
542 542 $ hg push ../tmpf
543 543 pushing to ../tmpf
544 544 searching for changes
545 545 no changes found
546 546 [1]
547 547
548 548 Do not warn about new head when the new head is a successors of a remote one
549 549
550 550 $ hg log -G
551 551 @ 5:cda648ca50f5 (draft unstable) [tip ] add original_e
552 552 |
553 553 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d
554 554 |
555 555 o 3:6f9641995072 (draft) [ ] add n3w_3_c
556 556 |
557 557 | o 2:245bde4270cd (public) [ ] add original_c
558 558 |/
559 559 o 1:7c3bad9141dc (public) [ ] add b
560 560 |
561 561 o 0:1f0dee641bb7 (public) [ ] add a
562 562
563 563 $ hg up -q 'desc(n3w_3_c)'
564 564 $ mkcommit obsolete_e
565 565 created new head
566 566 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
567 567 $ hg outgoing ../tmpf # parasite hg outgoing testin
568 568 comparing with ../tmpf
569 569 searching for changes
570 570 6:3de5eca88c00 (draft) [tip ] add obsolete_e
571 571 $ hg push ../tmpf
572 572 pushing to ../tmpf
573 573 searching for changes
574 574 adding changesets
575 575 adding manifests
576 576 adding file changes
577 577 added 1 changesets with 1 changes to 1 files (+1 heads)
578 578 1 new obsolescence markers
579 579
580 580 test relevance computation
581 581 ---------------------------------------
582 582
583 583 Checking simple case of "marker relevance".
584 584
585 585
586 586 Reminder of the repo situation
587 587
588 588 $ hg log --hidden --graph
589 589 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
590 590 |
591 591 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e
592 592 | |
593 593 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d
594 594 |/
595 595 o 3:6f9641995072 (draft) [ ] add n3w_3_c
596 596 |
597 597 | o 2:245bde4270cd (public) [ ] add original_c
598 598 |/
599 599 o 1:7c3bad9141dc (public) [ ] add b
600 600 |
601 601 o 0:1f0dee641bb7 (public) [ ] add a
602 602
603 603
604 604 List of all markers
605 605
606 606 $ hg debugobsolete
607 607 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
608 608 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
609 609 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
610 610 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
611 611 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
612 612 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
613 613 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
614 614 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
615 615
616 616 List of changesets with no chain
617 617
618 618 $ hg debugobsolete --hidden --rev ::2
619 619
620 620 List of changesets that are included on marker chain
621 621
622 622 $ hg debugobsolete --hidden --rev 6
623 623 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
624 624
625 625 List of changesets with a longer chain, (including a pruned children)
626 626
627 627 $ hg debugobsolete --hidden --rev 3
628 628 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
629 629 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
630 630 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
631 631 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
632 632 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
633 633 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
634 634 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
635 635
636 636 List of both
637 637
638 638 $ hg debugobsolete --hidden --rev 3::6
639 639 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
640 640 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
641 641 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
642 642 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
643 643 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
644 644 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
645 645 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
646 646 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
647 647
648 648 List of all markers in JSON
649 649
650 650 $ hg debugobsolete -Tjson
651 651 [
652 652 {
653 653 "date": [1339.0, 0],
654 654 "flag": 0,
655 655 "metadata": {"user": "test"},
656 656 "precnode": "1339133913391339133913391339133913391339",
657 657 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
658 658 },
659 659 {
660 660 "date": [1339.0, 0],
661 661 "flag": 0,
662 662 "metadata": {"user": "test"},
663 663 "precnode": "1337133713371337133713371337133713371337",
664 664 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
665 665 },
666 666 {
667 667 "date": [121.0, 120],
668 668 "flag": 12,
669 669 "metadata": {"user": "test"},
670 670 "precnode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
671 671 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
672 672 },
673 673 {
674 674 "date": [1338.0, 0],
675 675 "flag": 1,
676 676 "metadata": {"user": "test"},
677 677 "precnode": "5601fb93a350734d935195fee37f4054c529ff39",
678 678 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
679 679 },
680 680 {
681 681 "date": [1338.0, 0],
682 682 "flag": 0,
683 683 "metadata": {"user": "test"},
684 684 "precnode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
685 685 "succnodes": ["1337133713371337133713371337133713371337"]
686 686 },
687 687 {
688 688 "date": [1337.0, 0],
689 689 "flag": 0,
690 690 "metadata": {"user": "test"},
691 691 "precnode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
692 692 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
693 693 },
694 694 {
695 695 "date": [0.0, 0],
696 696 "flag": 0,
697 697 "metadata": {"user": "test"},
698 698 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
699 699 "precnode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
700 700 "succnodes": []
701 701 },
702 702 {
703 703 "date": *, (glob)
704 704 "flag": 0,
705 705 "metadata": {"user": "test"},
706 706 "precnode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
707 707 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
708 708 }
709 709 ]
710 710
711 711 Template keywords
712 712
713 713 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
714 714 3de5eca88c00 ????-??-?? (glob)
715 715 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
716 716 user=test
717 717 $ hg debugobsolete -r6 -T '{metadata}\n'
718 718 'user': 'test'
719 719 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
720 720 0 test
721 721
722 722 Test the debug output for exchange
723 723 ----------------------------------
724 724
725 725 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
726 726 pulling from ../tmpb
727 727 searching for changes
728 728 no changes found
729 729 obsmarker-exchange: 346 bytes received
730 730
731 731 check hgweb does not explode
732 732 ====================================
733 733
734 734 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
735 735 adding changesets
736 736 adding manifests
737 737 adding file changes
738 738 added 62 changesets with 63 changes to 9 files (+60 heads)
739 739 (run 'hg heads .' to see heads, 'hg merge' to merge)
740 740 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
741 741 > do
742 742 > hg debugobsolete $node
743 743 > done
744 744 $ hg up tip
745 745 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 746
747 747 #if serve
748 748
749 749 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
750 750 $ cat hg.pid >> $DAEMON_PIDS
751 751
752 752 check changelog view
753 753
754 754 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
755 755 200 Script output follows
756 756
757 757 check graph view
758 758
759 759 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
760 760 200 Script output follows
761 761
762 762 check filelog view
763 763
764 764 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
765 765 200 Script output follows
766 766
767 767 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
768 768 200 Script output follows
769 769 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
770 770 404 Not Found
771 771 [1]
772 772
773 773 check that web.view config option:
774 774
775 775 $ killdaemons.py hg.pid
776 776 $ cat >> .hg/hgrc << EOF
777 777 > [web]
778 778 > view=all
779 779 > EOF
780 780 $ wait
781 781 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
782 782 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
783 783 200 Script output follows
784 784 $ killdaemons.py hg.pid
785 785
786 786 Checking _enable=False warning if obsolete marker exists
787 787
788 788 $ echo '[experimental]' >> $HGRCPATH
789 789 $ echo "evolution=" >> $HGRCPATH
790 790 $ hg log -r tip
791 791 obsolete feature not enabled but 68 markers found!
792 792 68:c15e9edfca13 (draft) [tip ] add celestine
793 793
794 794 reenable for later test
795 795
796 796 $ echo '[experimental]' >> $HGRCPATH
797 797 $ echo "evolution=createmarkers,exchange" >> $HGRCPATH
798 798
799 799 $ rm hg.pid access.log errors.log
800 800 #endif
801 801
802 802 Several troubles on the same changeset (create an unstable and bumped changeset)
803 803
804 804 $ hg debugobsolete `getid obsolete_e`
805 805 $ hg debugobsolete `getid original_c` `getid babar`
806 806 $ hg log --config ui.logtemplate= -r 'bumped() and unstable()'
807 807 changeset: 7:50c51b361e60
808 808 user: test
809 809 date: Thu Jan 01 00:00:00 1970 +0000
810 810 trouble: unstable, bumped
811 811 summary: add babar
812 812
813 813
814 814 test the "obsolete" templatekw
815 815
816 816 $ hg log -r 'obsolete()'
817 817 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e
818 818
819 819 test the "troubles" templatekw
820 820
821 821 $ hg log -r 'bumped() and unstable()'
822 822 7:50c51b361e60 (draft unstable bumped) [ ] add babar
823 823
824 824 test the default cmdline template
825 825
826 826 $ hg log -T default -r 'bumped()'
827 827 changeset: 7:50c51b361e60
828 828 user: test
829 829 date: Thu Jan 01 00:00:00 1970 +0000
830 830 trouble: unstable, bumped
831 831 summary: add babar
832 832
833 833 $ hg log -T default -r 'obsolete()'
834 834 changeset: 6:3de5eca88c00
835 835 parent: 3:6f9641995072
836 836 user: test
837 837 date: Thu Jan 01 00:00:00 1970 +0000
838 838 summary: add obsolete_e
839 839
840 840
841 841 test summary output
842 842
843 843 $ hg up -r 'bumped() and unstable()'
844 844 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
845 845 $ hg summary
846 846 parent: 7:50c51b361e60 (unstable, bumped)
847 847 add babar
848 848 branch: default
849 849 commit: (clean)
850 850 update: 2 new changesets (update)
851 851 phases: 4 draft
852 852 unstable: 2 changesets
853 853 bumped: 1 changesets
854 854 $ hg up -r 'obsolete()'
855 855 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
856 856 $ hg summary
857 857 parent: 6:3de5eca88c00 (obsolete)
858 858 add obsolete_e
859 859 branch: default
860 860 commit: (clean)
861 861 update: 3 new changesets (update)
862 862 phases: 4 draft
863 863 unstable: 2 changesets
864 864 bumped: 1 changesets
865 865
866 866 Test incoming/outcoming with changesets obsoleted remotely, known locally
867 867 ===============================================================================
868 868
869 869 This test issue 3805
870 870
871 871 $ hg init repo-issue3805
872 872 $ cd repo-issue3805
873 873 $ echo "base" > base
874 874 $ hg ci -Am "base"
875 875 adding base
876 876 $ echo "foo" > foo
877 877 $ hg ci -Am "A"
878 878 adding foo
879 879 $ hg clone . ../other-issue3805
880 880 updating to branch default
881 881 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
882 882 $ echo "bar" >> foo
883 883 $ hg ci --amend
884 884 $ cd ../other-issue3805
885 885 $ hg log -G
886 886 @ 1:29f0c6921ddd (draft) [tip ] A
887 887 |
888 888 o 0:d20a80d4def3 (draft) [ ] base
889 889
890 890 $ hg log -G -R ../repo-issue3805
891 891 @ 3:323a9c3ddd91 (draft) [tip ] A
892 892 |
893 893 o 0:d20a80d4def3 (draft) [ ] base
894 894
895 895 $ hg incoming
896 896 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
897 897 searching for changes
898 898 3:323a9c3ddd91 (draft) [tip ] A
899 899 $ hg incoming --bundle ../issue3805.hg
900 900 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
901 901 searching for changes
902 902 3:323a9c3ddd91 (draft) [tip ] A
903 903 $ hg outgoing
904 904 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
905 905 searching for changes
906 906 1:29f0c6921ddd (draft) [tip ] A
907 907
908 908 #if serve
909 909
910 910 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
911 911 $ cat hg.pid >> $DAEMON_PIDS
912 912
913 913 $ hg incoming http://localhost:$HGPORT
914 914 comparing with http://localhost:$HGPORT/
915 915 searching for changes
916 916 2:323a9c3ddd91 (draft) [tip ] A
917 917 $ hg outgoing http://localhost:$HGPORT
918 918 comparing with http://localhost:$HGPORT/
919 919 searching for changes
920 920 1:29f0c6921ddd (draft) [tip ] A
921 921
922 922 $ killdaemons.py
923 923
924 924 #endif
925 925
926 926 This test issue 3814
927 927
928 928 (nothing to push but locally hidden changeset)
929 929
930 930 $ cd ..
931 931 $ hg init repo-issue3814
932 932 $ cd repo-issue3805
933 933 $ hg push -r 323a9c3ddd91 ../repo-issue3814
934 934 pushing to ../repo-issue3814
935 935 searching for changes
936 936 adding changesets
937 937 adding manifests
938 938 adding file changes
939 939 added 2 changesets with 2 changes to 2 files
940 940 2 new obsolescence markers
941 941 $ hg out ../repo-issue3814
942 942 comparing with ../repo-issue3814
943 943 searching for changes
944 944 no changes found
945 945 [1]
946 946
947 947 Test that a local tag blocks a changeset from being hidden
948 948
949 949 $ hg tag -l visible -r 1 --hidden
950 950 $ hg log -G
951 951 @ 3:323a9c3ddd91 (draft) [tip ] A
952 952 |
953 953 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A
954 954 |/
955 955 o 0:d20a80d4def3 (draft) [ ] base
956 956
957 957 Test that removing a local tag does not cause some commands to fail
958 958
959 959 $ hg tag -l -r tip tiptag
960 960 $ hg tags
961 961 tiptag 3:323a9c3ddd91
962 962 tip 3:323a9c3ddd91
963 963 visible 1:29f0c6921ddd
964 964 $ hg --config extensions.strip= strip -r tip --no-backup
965 965 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
966 966 $ hg tags
967 967 visible 1:29f0c6921ddd
968 968 tip 1:29f0c6921ddd
969 969
970 970 Test bundle overlay onto hidden revision
971 971
972 972 $ cd ..
973 973 $ hg init repo-bundleoverlay
974 974 $ cd repo-bundleoverlay
975 975 $ echo "A" > foo
976 976 $ hg ci -Am "A"
977 977 adding foo
978 978 $ echo "B" >> foo
979 979 $ hg ci -m "B"
980 980 $ hg up 0
981 981 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
982 982 $ echo "C" >> foo
983 983 $ hg ci -m "C"
984 984 created new head
985 985 $ hg log -G
986 986 @ 2:c186d7714947 (draft) [tip ] C
987 987 |
988 988 | o 1:44526ebb0f98 (draft) [ ] B
989 989 |/
990 990 o 0:4b34ecfb0d56 (draft) [ ] A
991 991
992 992
993 993 $ hg clone -r1 . ../other-bundleoverlay
994 994 adding changesets
995 995 adding manifests
996 996 adding file changes
997 997 added 2 changesets with 2 changes to 1 files
998 998 updating to branch default
999 999 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1000 1000 $ cd ../other-bundleoverlay
1001 1001 $ echo "B+" >> foo
1002 1002 $ hg ci --amend -m "B+"
1003 1003 $ hg log -G --hidden
1004 1004 @ 3:b7d587542d40 (draft) [tip ] B+
1005 1005 |
1006 1006 | x 2:eb95e9297e18 (draft *obsolete*) [ ] temporary amend commit for 44526ebb0f98
1007 1007 | |
1008 1008 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B
1009 1009 |/
1010 1010 o 0:4b34ecfb0d56 (draft) [ ] A
1011 1011
1012 1012
1013 1013 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1014 1014 comparing with ../repo-bundleoverlay
1015 1015 searching for changes
1016 1016 1:44526ebb0f98 (draft) [ ] B
1017 1017 2:c186d7714947 (draft) [tip ] C
1018 1018 $ hg log -G -R ../bundleoverlay.hg
1019 1019 o 4:c186d7714947 (draft) [tip ] C
1020 1020 |
1021 1021 | @ 3:b7d587542d40 (draft) [ ] B+
1022 1022 |/
1023 1023 o 0:4b34ecfb0d56 (draft) [ ] A
1024 1024
1025 1025
1026 1026 #if serve
1027 1027
1028 1028 Test issue 4506
1029 1029
1030 1030 $ cd ..
1031 1031 $ hg init repo-issue4506
1032 1032 $ cd repo-issue4506
1033 1033 $ echo "0" > foo
1034 1034 $ hg add foo
1035 1035 $ hg ci -m "content-0"
1036 1036
1037 1037 $ hg up null
1038 1038 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1039 1039 $ echo "1" > bar
1040 1040 $ hg add bar
1041 1041 $ hg ci -m "content-1"
1042 1042 created new head
1043 1043 $ hg up 0
1044 1044 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1045 1045 $ hg graft 1
1046 1046 grafting 1:1c9eddb02162 "content-1" (tip)
1047 1047
1048 1048 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1049 1049
1050 1050 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1051 1051 $ cat hg.pid >> $DAEMON_PIDS
1052 1052
1053 1053 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1054 1054 404 Not Found
1055 1055 [1]
1056 1056 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1057 1057 200 Script output follows
1058 1058 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1059 1059 200 Script output follows
1060 1060
1061 1061 $ killdaemons.py
1062 1062
1063 1063 #endif
1064 1064
1065 1065 Test heads computation on pending index changes with obsolescence markers
1066 1066 $ cd ..
1067 1067 $ cat >$TESTTMP/test_extension.py << EOF
1068 1068 > from mercurial import cmdutil, registrar
1069 1069 > from mercurial.i18n import _
1070 1070 >
1071 1071 > cmdtable = {}
1072 1072 > command = registrar.command(cmdtable)
1073 1073 > @command("amendtransient",[], _('hg amendtransient [rev]'))
1074 1074 > def amend(ui, repo, *pats, **opts):
1075 1075 > def commitfunc(ui, repo, message, match, opts):
1076 1076 > return repo.commit(message, repo['.'].user(), repo['.'].date(), match)
1077 1077 > opts['message'] = 'Test'
1078 1078 > opts['logfile'] = None
1079 1079 > cmdutil.amend(ui, repo, commitfunc, repo['.'], {}, pats, opts)
1080 1080 > ui.write('%s\n' % repo.changelog.headrevs())
1081 1081 > EOF
1082 1082 $ cat >> $HGRCPATH << EOF
1083 1083 > [extensions]
1084 1084 > testextension=$TESTTMP/test_extension.py
1085 1085 > EOF
1086 1086 $ hg init repo-issue-nativerevs-pending-changes
1087 1087 $ cd repo-issue-nativerevs-pending-changes
1088 1088 $ mkcommit a
1089 1089 $ mkcommit b
1090 1090 $ hg up ".^"
1091 1091 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1092 1092 $ echo aa > a
1093 1093 $ hg amendtransient
1094 1094 [1, 3]
1095 1095
1096 1096 Check that corrupted hidden cache does not crash
1097 1097
1098 1098 $ printf "" > .hg/cache/hidden
1099 1099 $ hg log -r . -T '{node}' --debug
1100 1100 corrupted hidden cache
1101 1101 8fd96dfc63e51ed5a8af1bec18eb4b19dbf83812 (no-eol)
1102 1102 $ hg log -r . -T '{node}' --debug
1103 1103 8fd96dfc63e51ed5a8af1bec18eb4b19dbf83812 (no-eol)
1104 1104
1105 1105 #if unix-permissions
1106 1106 Check that wrong hidden cache permission does not crash
1107 1107
1108 1108 $ chmod 000 .hg/cache/hidden
1109 1109 $ hg log -r . -T '{node}' --debug
1110 1110 cannot read hidden cache
1111 1111 error writing hidden changesets cache
1112 1112 8fd96dfc63e51ed5a8af1bec18eb4b19dbf83812 (no-eol)
1113 1113 #endif
1114 1114
1115 1115 Test cache consistency for the visible filter
1116 1116 1) We want to make sure that the cached filtered revs are invalidated when
1117 1117 bookmarks change
1118 1118 $ cd ..
1119 1119 $ cat >$TESTTMP/test_extension.py << EOF
1120 1120 > import weakref
1121 1121 > from mercurial import cmdutil, extensions, bookmarks, repoview
1122 1122 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1123 1123 > reporef = weakref.ref(bkmstoreinst._repo)
1124 1124 > def trhook(tr):
1125 1125 > repo = reporef()
1126 1126 > hidden1 = repoview.computehidden(repo)
1127 1127 > hidden = repoview.filterrevs(repo, 'visible')
1128 1128 > if sorted(hidden1) != sorted(hidden):
1129 1129 > print "cache inconsistency"
1130 1130 > bkmstoreinst._repo.currenttransaction().addpostclose('test_extension', trhook)
1131 1131 > orig(bkmstoreinst, *args, **kwargs)
1132 1132 > def extsetup(ui):
1133 1133 > extensions.wrapfunction(bookmarks.bmstore, 'recordchange',
1134 1134 > _bookmarkchanged)
1135 1135 > EOF
1136 1136
1137 1137 $ hg init repo-cache-inconsistency
1138 1138 $ cd repo-issue-nativerevs-pending-changes
1139 1139 $ mkcommit a
1140 1140 a already tracked!
1141 1141 $ mkcommit b
1142 1142 $ hg id
1143 1143 13bedc178fce tip
1144 1144 $ echo "hello" > b
1145 1145 $ hg commit --amend -m "message"
1146 1146 $ hg book bookb -r 13bedc178fce --hidden
1147 1147 $ hg log -r 13bedc178fce
1148 1148 5:13bedc178fce (draft *obsolete*) [ bookb] add b
1149 1149 $ hg book -d bookb
1150 1150 $ hg log -r 13bedc178fce
1151 1151 abort: hidden revision '13bedc178fce'!
1152 1152 (use --hidden to access hidden revisions)
1153 1153 [255]
1154 1154
1155 1155 Empty out the test extension, as it isn't compatible with later parts
1156 1156 of the test.
1157 1157 $ echo > $TESTTMP/test_extension.py
1158 1158
1159 1159 Test ability to pull changeset with locally applying obsolescence markers
1160 1160 (issue4945)
1161 1161
1162 1162 $ cd ..
1163 1163 $ hg init issue4845
1164 1164 $ cd issue4845
1165 1165
1166 1166 $ echo foo > f0
1167 1167 $ hg add f0
1168 1168 $ hg ci -m '0'
1169 1169 $ echo foo > f1
1170 1170 $ hg add f1
1171 1171 $ hg ci -m '1'
1172 1172 $ echo foo > f2
1173 1173 $ hg add f2
1174 1174 $ hg ci -m '2'
1175 1175
1176 1176 $ echo bar > f2
1177 1177 $ hg commit --amend --config experimetnal.evolution=createmarkers
1178 1178 $ hg log -G
1179 1179 @ 4:b0551702f918 (draft) [tip ] 2
1180 1180 |
1181 1181 o 1:e016b03fd86f (draft) [ ] 1
1182 1182 |
1183 1183 o 0:a78f55e5508c (draft) [ ] 0
1184 1184
1185 1185 $ hg log -G --hidden
1186 1186 @ 4:b0551702f918 (draft) [tip ] 2
1187 1187 |
1188 1188 | x 3:f27abbcc1f77 (draft *obsolete*) [ ] temporary amend commit for e008cf283490
1189 1189 | |
1190 1190 | x 2:e008cf283490 (draft *obsolete*) [ ] 2
1191 1191 |/
1192 1192 o 1:e016b03fd86f (draft) [ ] 1
1193 1193 |
1194 1194 o 0:a78f55e5508c (draft) [ ] 0
1195 1195
1196 1196
1197 1197 $ hg strip -r 1 --config extensions.strip=
1198 1198 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1199 1199 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-c41c6bcc-backup.hg (glob)
1200 1200 $ hg log -G
1201 1201 @ 0:a78f55e5508c (draft) [tip ] 0
1202 1202
1203 1203 $ hg log -G --hidden
1204 1204 @ 0:a78f55e5508c (draft) [tip ] 0
1205 1205
1206 1206
1207 1207 $ hg pull .hg/strip-backup/*
1208 1208 pulling from .hg/strip-backup/e016b03fd86f-c41c6bcc-backup.hg
1209 1209 searching for changes
1210 1210 adding changesets
1211 1211 adding manifests
1212 1212 adding file changes
1213 1213 added 2 changesets with 2 changes to 2 files
1214 1214 (run 'hg update' to get a working copy)
1215 1215 $ hg log -G
1216 1216 o 2:b0551702f918 (draft) [tip ] 2
1217 1217 |
1218 1218 o 1:e016b03fd86f (draft) [ ] 1
1219 1219 |
1220 1220 @ 0:a78f55e5508c (draft) [ ] 0
1221 1221
1222 1222 $ hg log -G --hidden
1223 1223 o 2:b0551702f918 (draft) [tip ] 2
1224 1224 |
1225 1225 o 1:e016b03fd86f (draft) [ ] 1
1226 1226 |
1227 1227 @ 0:a78f55e5508c (draft) [ ] 0
1228 1228
1229 1229 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1230 1230 only a subset of those are displayed (because of --rev option)
1231 1231 $ hg init doindexrev
1232 1232 $ cd doindexrev
1233 1233 $ echo a > a
1234 1234 $ hg ci -Am a
1235 1235 adding a
1236 1236 $ hg ci --amend -m aa
1237 1237 $ echo b > b
1238 1238 $ hg ci -Am b
1239 1239 adding b
1240 1240 $ hg ci --amend -m bb
1241 1241 $ echo c > c
1242 1242 $ hg ci -Am c
1243 1243 adding c
1244 1244 $ hg ci --amend -m cc
1245 1245 $ echo d > d
1246 1246 $ hg ci -Am d
1247 1247 adding d
1248 $ hg ci --amend -m dd
1248 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1249 1249 $ hg debugobsolete --index --rev "3+7"
1250 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1250 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 \(.*\) {'user': 'test'} (re)
1251 1251 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1252 1252 $ hg debugobsolete --index --rev "3+7" -Tjson
1253 1253 [
1254 1254 {
1255 1255 "date": *, (glob)
1256 1256 "flag": 0,
1257 1257 "index": 1,
1258 "metadata": {"operation": "amend", "user": "test"},
1258 "metadata": {"user": "test"},
1259 1259 "precnode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1260 1260 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1261 1261 },
1262 1262 {
1263 1263 "date": *, (glob)
1264 1264 "flag": 0,
1265 1265 "index": 3,
1266 1266 "metadata": {"operation": "amend", "user": "test"},
1267 1267 "precnode": "4715cf767440ed891755448016c2b8cf70760c30",
1268 1268 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1269 1269 }
1270 1270 ]
1271 1271
1272 1272 Test the --delete option of debugobsolete command
1273 1273 $ hg debugobsolete --index
1274 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1275 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1276 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1277 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1274 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 \(.*\) {'user': 'test'} (re)
1275 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 \(.*\) {'user': 'test'} (re)
1276 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'user': 'test'} (re)
1277 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (*) {'operation': 'amend', 'user': 'test'} (glob)
1278 1278 $ hg debugobsolete --delete 1 --delete 3
1279 1279 deleted 2 obsolescence markers
1280 1280 $ hg debugobsolete
1281 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1282 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'operation': 'amend', 'user': 'test'} (re)
1281 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 \(.*\) {'user': 'test'} (re)
1282 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'user': 'test'} (re)
1283 1283 $ cd ..
1284 1284
@@ -1,980 +1,982 b''
1 1 ==========================
2 2 Test rebase with obsolete
3 3 ==========================
4 4
5 5 Enable obsolete
6 6
7 7 $ cat >> $HGRCPATH << EOF
8 8 > [ui]
9 9 > logtemplate= {rev}:{node|short} {desc|firstline}
10 10 > [experimental]
11 11 > evolution=createmarkers,allowunstable
12 12 > [phases]
13 13 > publish=False
14 14 > [extensions]
15 15 > rebase=
16 16 > EOF
17 17
18 18 Setup rebase canonical repo
19 19
20 20 $ hg init base
21 21 $ cd base
22 22 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
23 23 adding changesets
24 24 adding manifests
25 25 adding file changes
26 26 added 8 changesets with 7 changes to 7 files (+2 heads)
27 27 (run 'hg heads' to see heads, 'hg merge' to merge)
28 28 $ hg up tip
29 29 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 30 $ hg log -G
31 31 @ 7:02de42196ebe H
32 32 |
33 33 | o 6:eea13746799a G
34 34 |/|
35 35 o | 5:24b6387c8c8c F
36 36 | |
37 37 | o 4:9520eea781bc E
38 38 |/
39 39 | o 3:32af7686d403 D
40 40 | |
41 41 | o 2:5fddd98957c8 C
42 42 | |
43 43 | o 1:42ccdea3bb16 B
44 44 |/
45 45 o 0:cd010b8cd998 A
46 46
47 47 $ cd ..
48 48
49 49 simple rebase
50 50 ---------------------------------
51 51
52 52 $ hg clone base simple
53 53 updating to branch default
54 54 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 55 $ cd simple
56 56 $ hg up 32af7686d403
57 57 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
58 58 $ hg rebase -d eea13746799a
59 59 rebasing 1:42ccdea3bb16 "B"
60 60 rebasing 2:5fddd98957c8 "C"
61 61 rebasing 3:32af7686d403 "D"
62 62 $ hg log -G
63 63 @ 10:8eeb3c33ad33 D
64 64 |
65 65 o 9:2327fea05063 C
66 66 |
67 67 o 8:e4e5be0395b2 B
68 68 |
69 69 | o 7:02de42196ebe H
70 70 | |
71 71 o | 6:eea13746799a G
72 72 |\|
73 73 | o 5:24b6387c8c8c F
74 74 | |
75 75 o | 4:9520eea781bc E
76 76 |/
77 77 o 0:cd010b8cd998 A
78 78
79 79 $ hg log --hidden -G
80 80 @ 10:8eeb3c33ad33 D
81 81 |
82 82 o 9:2327fea05063 C
83 83 |
84 84 o 8:e4e5be0395b2 B
85 85 |
86 86 | o 7:02de42196ebe H
87 87 | |
88 88 o | 6:eea13746799a G
89 89 |\|
90 90 | o 5:24b6387c8c8c F
91 91 | |
92 92 o | 4:9520eea781bc E
93 93 |/
94 94 | x 3:32af7686d403 D
95 95 | |
96 96 | x 2:5fddd98957c8 C
97 97 | |
98 98 | x 1:42ccdea3bb16 B
99 99 |/
100 100 o 0:cd010b8cd998 A
101 101
102 102 $ hg debugobsolete
103 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
104 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
105 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
103 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (*) {'user': 'test'} (glob)
104 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (*) {'user': 'test'} (glob)
105 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (*) {'user': 'test'} (glob)
106 106
107 107
108 108 $ cd ..
109 109
110 110 empty changeset
111 111 ---------------------------------
112 112
113 113 $ hg clone base empty
114 114 updating to branch default
115 115 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 116 $ cd empty
117 117 $ hg up eea13746799a
118 118 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
119 119
120 120 We make a copy of both the first changeset in the rebased and some other in the
121 121 set.
122 122
123 123 $ hg graft 42ccdea3bb16 32af7686d403
124 124 grafting 1:42ccdea3bb16 "B"
125 125 grafting 3:32af7686d403 "D"
126 126 $ hg rebase -s 42ccdea3bb16 -d .
127 127 rebasing 1:42ccdea3bb16 "B"
128 128 note: rebase of 1:42ccdea3bb16 created no changes to commit
129 129 rebasing 2:5fddd98957c8 "C"
130 130 rebasing 3:32af7686d403 "D"
131 131 note: rebase of 3:32af7686d403 created no changes to commit
132 132 $ hg log -G
133 133 o 10:5ae4c968c6ac C
134 134 |
135 135 @ 9:08483444fef9 D
136 136 |
137 137 o 8:8877864f1edb B
138 138 |
139 139 | o 7:02de42196ebe H
140 140 | |
141 141 o | 6:eea13746799a G
142 142 |\|
143 143 | o 5:24b6387c8c8c F
144 144 | |
145 145 o | 4:9520eea781bc E
146 146 |/
147 147 o 0:cd010b8cd998 A
148 148
149 149 $ hg log --hidden -G
150 150 o 10:5ae4c968c6ac C
151 151 |
152 152 @ 9:08483444fef9 D
153 153 |
154 154 o 8:8877864f1edb B
155 155 |
156 156 | o 7:02de42196ebe H
157 157 | |
158 158 o | 6:eea13746799a G
159 159 |\|
160 160 | o 5:24b6387c8c8c F
161 161 | |
162 162 o | 4:9520eea781bc E
163 163 |/
164 164 | x 3:32af7686d403 D
165 165 | |
166 166 | x 2:5fddd98957c8 C
167 167 | |
168 168 | x 1:42ccdea3bb16 B
169 169 |/
170 170 o 0:cd010b8cd998 A
171 171
172 172 $ hg debugobsolete
173 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'operation': 'rebase', 'user': 'test'} (glob)
174 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
175 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'operation': 'rebase', 'user': 'test'} (glob)
173 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
174 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
175 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
176 176
177 177
178 178 More complex case where part of the rebase set were already rebased
179 179
180 180 $ hg rebase --rev 'desc(D)' --dest 'desc(H)'
181 181 rebasing 9:08483444fef9 "D"
182 182 $ hg debugobsolete
183 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'operation': 'rebase', 'user': 'test'} (glob)
184 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
185 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'operation': 'rebase', 'user': 'test'} (glob)
186 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
183 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
184 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
185 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
186 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
187 187 $ hg log -G
188 188 @ 11:4596109a6a43 D
189 189 |
190 190 | o 10:5ae4c968c6ac C
191 191 | |
192 192 | x 9:08483444fef9 D
193 193 | |
194 194 | o 8:8877864f1edb B
195 195 | |
196 196 o | 7:02de42196ebe H
197 197 | |
198 198 | o 6:eea13746799a G
199 199 |/|
200 200 o | 5:24b6387c8c8c F
201 201 | |
202 202 | o 4:9520eea781bc E
203 203 |/
204 204 o 0:cd010b8cd998 A
205 205
206 206 $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
207 207 rebasing 8:8877864f1edb "B"
208 208 note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D"
209 209 rebasing 10:5ae4c968c6ac "C"
210 210 $ hg debugobsolete
211 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'operation': 'rebase', 'user': 'test'} (glob)
212 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
213 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'operation': 'rebase', 'user': 'test'} (glob)
214 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
215 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
216 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
211 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
212 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
213 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
214 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
215 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
216 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
217 217 $ hg log --rev 'divergent()'
218 218 $ hg log -G
219 219 o 13:98f6af4ee953 C
220 220 |
221 221 o 12:462a34d07e59 B
222 222 |
223 223 @ 11:4596109a6a43 D
224 224 |
225 225 o 7:02de42196ebe H
226 226 |
227 227 | o 6:eea13746799a G
228 228 |/|
229 229 o | 5:24b6387c8c8c F
230 230 | |
231 231 | o 4:9520eea781bc E
232 232 |/
233 233 o 0:cd010b8cd998 A
234 234
235 235 $ hg log --style default --debug -r 4596109a6a4328c398bde3a4a3b6737cfade3003
236 236 changeset: 11:4596109a6a4328c398bde3a4a3b6737cfade3003
237 237 phase: draft
238 238 parent: 7:02de42196ebee42ef284b6780a87cdc96e8eaab6
239 239 parent: -1:0000000000000000000000000000000000000000
240 240 manifest: 11:a91006e3a02f1edf631f7018e6e5684cf27dd905
241 241 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
242 242 date: Sat Apr 30 15:24:48 2011 +0200
243 243 files+: D
244 244 extra: branch=default
245 245 extra: rebase_source=08483444fef91d6224f6655ee586a65d263ad34c
246 246 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
247 247 description:
248 248 D
249 249
250 250
251 251 $ hg up -qr 'desc(G)'
252 252 $ hg graft 4596109a6a4328c398bde3a4a3b6737cfade3003
253 253 grafting 11:4596109a6a43 "D"
254 254 $ hg up -qr 'desc(E)'
255 255 $ hg rebase -s tip -d .
256 256 rebasing 14:9e36056a46e3 "D" (tip)
257 257 $ hg log --style default --debug -r tip
258 258 changeset: 15:627d4614809036ba22b9e7cb31638ddc06ab99ab
259 259 tag: tip
260 260 phase: draft
261 261 parent: 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba
262 262 parent: -1:0000000000000000000000000000000000000000
263 263 manifest: 15:648e8ede73ae3e497d093d3a4c8fcc2daa864f42
264 264 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
265 265 date: Sat Apr 30 15:24:48 2011 +0200
266 266 files+: D
267 267 extra: branch=default
268 268 extra: intermediate-source=4596109a6a4328c398bde3a4a3b6737cfade3003
269 269 extra: rebase_source=9e36056a46e37c9776168c7375734eebc70e294f
270 270 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
271 271 description:
272 272 D
273 273
274 274
275 275 Start rebase from a commit that is obsolete but not hidden only because it's
276 276 a working copy parent. We should be moved back to the starting commit as usual
277 277 even though it is hidden (until we're moved there).
278 278
279 279 $ hg --hidden up -qr 'first(hidden())'
280 280 $ hg rebase --rev 13 --dest 15
281 281 rebasing 13:98f6af4ee953 "C"
282 282 $ hg log -G
283 283 o 16:294a2b93eb4d C
284 284 |
285 285 o 15:627d46148090 D
286 286 |
287 287 | o 12:462a34d07e59 B
288 288 | |
289 289 | o 11:4596109a6a43 D
290 290 | |
291 291 | o 7:02de42196ebe H
292 292 | |
293 293 +---o 6:eea13746799a G
294 294 | |/
295 295 | o 5:24b6387c8c8c F
296 296 | |
297 297 o | 4:9520eea781bc E
298 298 |/
299 299 | @ 1:42ccdea3bb16 B
300 300 |/
301 301 o 0:cd010b8cd998 A
302 302
303 303
304 304 $ cd ..
305 305
306 306 collapse rebase
307 307 ---------------------------------
308 308
309 309 $ hg clone base collapse
310 310 updating to branch default
311 311 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 312 $ cd collapse
313 313 $ hg rebase -s 42ccdea3bb16 -d eea13746799a --collapse
314 314 rebasing 1:42ccdea3bb16 "B"
315 315 rebasing 2:5fddd98957c8 "C"
316 316 rebasing 3:32af7686d403 "D"
317 317 $ hg log -G
318 318 o 8:4dc2197e807b Collapsed revision
319 319 |
320 320 | @ 7:02de42196ebe H
321 321 | |
322 322 o | 6:eea13746799a G
323 323 |\|
324 324 | o 5:24b6387c8c8c F
325 325 | |
326 326 o | 4:9520eea781bc E
327 327 |/
328 328 o 0:cd010b8cd998 A
329 329
330 330 $ hg log --hidden -G
331 331 o 8:4dc2197e807b Collapsed revision
332 332 |
333 333 | @ 7:02de42196ebe H
334 334 | |
335 335 o | 6:eea13746799a G
336 336 |\|
337 337 | o 5:24b6387c8c8c F
338 338 | |
339 339 o | 4:9520eea781bc E
340 340 |/
341 341 | x 3:32af7686d403 D
342 342 | |
343 343 | x 2:5fddd98957c8 C
344 344 | |
345 345 | x 1:42ccdea3bb16 B
346 346 |/
347 347 o 0:cd010b8cd998 A
348 348
349 349 $ hg id --debug -r tip
350 350 4dc2197e807bae9817f09905b50ab288be2dbbcf tip
351 351 $ hg debugobsolete
352 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
353 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
354 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
352 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
353 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
354 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
355 355
356 356 $ cd ..
357 357
358 358 Rebase set has hidden descendants
359 359 ---------------------------------
360 360
361 361 We rebase a changeset which has a hidden changeset. The hidden changeset must
362 362 not be rebased.
363 363
364 364 $ hg clone base hidden
365 365 updating to branch default
366 366 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 367 $ cd hidden
368 368 $ hg rebase -s 5fddd98957c8 -d eea13746799a
369 369 rebasing 2:5fddd98957c8 "C"
370 370 rebasing 3:32af7686d403 "D"
371 371 $ hg rebase -s 42ccdea3bb16 -d 02de42196ebe
372 372 rebasing 1:42ccdea3bb16 "B"
373 373 $ hg log -G
374 374 o 10:7c6027df6a99 B
375 375 |
376 376 | o 9:cf44d2f5a9f4 D
377 377 | |
378 378 | o 8:e273c5e7d2d2 C
379 379 | |
380 380 @ | 7:02de42196ebe H
381 381 | |
382 382 | o 6:eea13746799a G
383 383 |/|
384 384 o | 5:24b6387c8c8c F
385 385 | |
386 386 | o 4:9520eea781bc E
387 387 |/
388 388 o 0:cd010b8cd998 A
389 389
390 390 $ hg log --hidden -G
391 391 o 10:7c6027df6a99 B
392 392 |
393 393 | o 9:cf44d2f5a9f4 D
394 394 | |
395 395 | o 8:e273c5e7d2d2 C
396 396 | |
397 397 @ | 7:02de42196ebe H
398 398 | |
399 399 | o 6:eea13746799a G
400 400 |/|
401 401 o | 5:24b6387c8c8c F
402 402 | |
403 403 | o 4:9520eea781bc E
404 404 |/
405 405 | x 3:32af7686d403 D
406 406 | |
407 407 | x 2:5fddd98957c8 C
408 408 | |
409 409 | x 1:42ccdea3bb16 B
410 410 |/
411 411 o 0:cd010b8cd998 A
412 412
413 413 $ hg debugobsolete
414 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
415 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
416 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (*) {'operation': 'rebase', 'user': 'test'} (glob)
414 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (*) {'user': 'test'} (glob)
415 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (*) {'user': 'test'} (glob)
416 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (*) {'user': 'test'} (glob)
417 417
418 418 Test that rewriting leaving instability behind is allowed
419 419 ---------------------------------------------------------------------
420 420
421 421 $ hg log -r 'children(8)'
422 422 9:cf44d2f5a9f4 D (no-eol)
423 423 $ hg rebase -r 8
424 424 rebasing 8:e273c5e7d2d2 "C"
425 425 $ hg log -G
426 426 o 11:0d8f238b634c C
427 427 |
428 428 o 10:7c6027df6a99 B
429 429 |
430 430 | o 9:cf44d2f5a9f4 D
431 431 | |
432 432 | x 8:e273c5e7d2d2 C
433 433 | |
434 434 @ | 7:02de42196ebe H
435 435 | |
436 436 | o 6:eea13746799a G
437 437 |/|
438 438 o | 5:24b6387c8c8c F
439 439 | |
440 440 | o 4:9520eea781bc E
441 441 |/
442 442 o 0:cd010b8cd998 A
443 443
444 444
445 445
446 446 Test multiple root handling
447 447 ------------------------------------
448 448
449 449 $ hg rebase --dest 4 --rev '7+11+9'
450 450 rebasing 9:cf44d2f5a9f4 "D"
451 451 rebasing 7:02de42196ebe "H"
452 452 not rebasing ignored 10:7c6027df6a99 "B"
453 453 rebasing 11:0d8f238b634c "C" (tip)
454 454 $ hg log -G
455 455 o 14:1e8370e38cca C
456 456 |
457 457 @ 13:bfe264faf697 H
458 458 |
459 459 | o 12:102b4c1d889b D
460 460 |/
461 461 | o 10:7c6027df6a99 B
462 462 | |
463 463 | x 7:02de42196ebe H
464 464 | |
465 465 +---o 6:eea13746799a G
466 466 | |/
467 467 | o 5:24b6387c8c8c F
468 468 | |
469 469 o | 4:9520eea781bc E
470 470 |/
471 471 o 0:cd010b8cd998 A
472 472
473 473 $ cd ..
474 474
475 475 test on rebase dropping a merge
476 476
477 477 (setup)
478 478
479 479 $ hg init dropmerge
480 480 $ cd dropmerge
481 481 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
482 482 adding changesets
483 483 adding manifests
484 484 adding file changes
485 485 added 8 changesets with 7 changes to 7 files (+2 heads)
486 486 (run 'hg heads' to see heads, 'hg merge' to merge)
487 487 $ hg up 3
488 488 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 489 $ hg merge 7
490 490 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
491 491 (branch merge, don't forget to commit)
492 492 $ hg ci -m 'M'
493 493 $ echo I > I
494 494 $ hg add I
495 495 $ hg ci -m I
496 496 $ hg log -G
497 497 @ 9:4bde274eefcf I
498 498 |
499 499 o 8:53a6a128b2b7 M
500 500 |\
501 501 | o 7:02de42196ebe H
502 502 | |
503 503 | | o 6:eea13746799a G
504 504 | |/|
505 505 | o | 5:24b6387c8c8c F
506 506 | | |
507 507 | | o 4:9520eea781bc E
508 508 | |/
509 509 o | 3:32af7686d403 D
510 510 | |
511 511 o | 2:5fddd98957c8 C
512 512 | |
513 513 o | 1:42ccdea3bb16 B
514 514 |/
515 515 o 0:cd010b8cd998 A
516 516
517 517 (actual test)
518 518
519 519 $ hg rebase --dest 6 --rev '((desc(H) + desc(D))::) - desc(M)'
520 520 rebasing 3:32af7686d403 "D"
521 521 rebasing 7:02de42196ebe "H"
522 522 not rebasing ignored 8:53a6a128b2b7 "M"
523 523 rebasing 9:4bde274eefcf "I" (tip)
524 524 $ hg log -G
525 525 @ 12:acd174b7ab39 I
526 526 |
527 527 o 11:6c11a6218c97 H
528 528 |
529 529 | o 10:b5313c85b22e D
530 530 |/
531 531 | o 8:53a6a128b2b7 M
532 532 | |\
533 533 | | x 7:02de42196ebe H
534 534 | | |
535 535 o---+ 6:eea13746799a G
536 536 | | |
537 537 | | o 5:24b6387c8c8c F
538 538 | | |
539 539 o---+ 4:9520eea781bc E
540 540 / /
541 541 x | 3:32af7686d403 D
542 542 | |
543 543 o | 2:5fddd98957c8 C
544 544 | |
545 545 o | 1:42ccdea3bb16 B
546 546 |/
547 547 o 0:cd010b8cd998 A
548 548
549 549
550 550 Test hidden changesets in the rebase set (issue4504)
551 551
552 552 $ hg up --hidden 9
553 553 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
554 554 $ echo J > J
555 555 $ hg add J
556 556 $ hg commit -m J
557 557 $ hg debugobsolete `hg log --rev . -T '{node}'`
558 558
559 559 $ hg rebase --rev .~1::. --dest 'max(desc(D))' --traceback --config experimental.rebaseskipobsolete=off
560 560 rebasing 9:4bde274eefcf "I"
561 561 rebasing 13:06edfc82198f "J" (tip)
562 562 $ hg log -G
563 563 @ 15:5ae8a643467b J
564 564 |
565 565 o 14:9ad579b4a5de I
566 566 |
567 567 | o 12:acd174b7ab39 I
568 568 | |
569 569 | o 11:6c11a6218c97 H
570 570 | |
571 571 o | 10:b5313c85b22e D
572 572 |/
573 573 | o 8:53a6a128b2b7 M
574 574 | |\
575 575 | | x 7:02de42196ebe H
576 576 | | |
577 577 o---+ 6:eea13746799a G
578 578 | | |
579 579 | | o 5:24b6387c8c8c F
580 580 | | |
581 581 o---+ 4:9520eea781bc E
582 582 / /
583 583 x | 3:32af7686d403 D
584 584 | |
585 585 o | 2:5fddd98957c8 C
586 586 | |
587 587 o | 1:42ccdea3bb16 B
588 588 |/
589 589 o 0:cd010b8cd998 A
590 590
591 591 $ hg up 14 -C
592 592 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
593 593 $ echo "K" > K
594 594 $ hg add K
595 595 $ hg commit --amend -m "K"
596 596 $ echo "L" > L
597 597 $ hg add L
598 598 $ hg commit -m "L"
599 599 $ hg up '.^'
600 600 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
601 601 $ echo "M" > M
602 602 $ hg add M
603 603 $ hg commit --amend -m "M"
604 604 $ hg log -G
605 605 @ 20:bfaedf8eb73b M
606 606 |
607 607 | o 18:97219452e4bd L
608 608 | |
609 609 | x 17:fc37a630c901 K
610 610 |/
611 611 | o 15:5ae8a643467b J
612 612 | |
613 613 | x 14:9ad579b4a5de I
614 614 |/
615 615 | o 12:acd174b7ab39 I
616 616 | |
617 617 | o 11:6c11a6218c97 H
618 618 | |
619 619 o | 10:b5313c85b22e D
620 620 |/
621 621 | o 8:53a6a128b2b7 M
622 622 | |\
623 623 | | x 7:02de42196ebe H
624 624 | | |
625 625 o---+ 6:eea13746799a G
626 626 | | |
627 627 | | o 5:24b6387c8c8c F
628 628 | | |
629 629 o---+ 4:9520eea781bc E
630 630 / /
631 631 x | 3:32af7686d403 D
632 632 | |
633 633 o | 2:5fddd98957c8 C
634 634 | |
635 635 o | 1:42ccdea3bb16 B
636 636 |/
637 637 o 0:cd010b8cd998 A
638 638
639 639 $ hg rebase -s 14 -d 18 --config experimental.rebaseskipobsolete=True
640 640 note: not rebasing 14:9ad579b4a5de "I", already in destination as 17:fc37a630c901 "K"
641 641 rebasing 15:5ae8a643467b "J"
642 642
643 643 $ cd ..
644 644
645 645 Skip obsolete changeset even with multiple hops
646 646 -----------------------------------------------
647 647
648 648 setup
649 649
650 650 $ hg init obsskip
651 651 $ cd obsskip
652 652 $ cat << EOF >> .hg/hgrc
653 653 > [experimental]
654 654 > rebaseskipobsolete = True
655 655 > [extensions]
656 656 > strip =
657 657 > EOF
658 658 $ echo A > A
659 659 $ hg add A
660 660 $ hg commit -m A
661 661 $ echo B > B
662 662 $ hg add B
663 663 $ hg commit -m B0
664 664 $ hg commit --amend -m B1
665 665 $ hg commit --amend -m B2
666 666 $ hg up --hidden 'desc(B0)'
667 667 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
668 668 $ echo C > C
669 669 $ hg add C
670 670 $ hg commit -m C
671 671
672 672 Rebase finds its way in a chain of marker
673 673
674 674 $ hg rebase -d 'desc(B2)'
675 675 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 3:261e70097290 "B2"
676 676 rebasing 4:212cb178bcbb "C" (tip)
677 677
678 678 Even when the chain include missing node
679 679
680 680 $ hg up --hidden 'desc(B0)'
681 681 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
682 682 $ echo D > D
683 683 $ hg add D
684 684 $ hg commit -m D
685 685 $ hg --hidden strip -r 'desc(B1)'
686 686 saved backup bundle to $TESTTMP/obsskip/.hg/strip-backup/86f6414ccda7-b1c452ee-backup.hg (glob)
687 687
688 688 $ hg rebase -d 'desc(B2)'
689 689 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 2:261e70097290 "B2"
690 690 rebasing 5:1a79b7535141 "D" (tip)
691 691 $ hg up 4
692 692 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
693 693 $ echo "O" > O
694 694 $ hg add O
695 695 $ hg commit -m O
696 696 $ echo "P" > P
697 697 $ hg add P
698 698 $ hg commit -m P
699 699 $ hg log -G
700 700 @ 8:8d47583e023f P
701 701 |
702 702 o 7:360bbaa7d3ce O
703 703 |
704 704 | o 6:9c48361117de D
705 705 | |
706 706 o | 4:ff2c4d47b71d C
707 707 |/
708 708 o 2:261e70097290 B2
709 709 |
710 710 o 0:4a2df7238c3b A
711 711
712 712 $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.evolution=all
713 713 $ hg rebase -d 6 -r "4::"
714 714 rebasing 4:ff2c4d47b71d "C"
715 715 note: not rebasing 7:360bbaa7d3ce "O", it has no successor
716 716 rebasing 8:8d47583e023f "P" (tip)
717 717
718 718 If all the changeset to be rebased are obsolete and present in the destination, we
719 719 should display a friendly error message
720 720
721 721 $ hg log -G
722 722 @ 10:121d9e3bc4c6 P
723 723 |
724 724 o 9:4be60e099a77 C
725 725 |
726 726 o 6:9c48361117de D
727 727 |
728 728 o 2:261e70097290 B2
729 729 |
730 730 o 0:4a2df7238c3b A
731 731
732 732
733 733 $ hg up 9
734 734 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
735 735 $ echo "non-relevant change" > nonrelevant
736 736 $ hg add nonrelevant
737 737 $ hg commit -m nonrelevant
738 738 created new head
739 739 $ hg debugobsolete `hg log -r 11 -T '{node}\n'` --config experimental.evolution=all
740 740 $ hg rebase -r . -d 10
741 741 note: not rebasing 11:f44da1f4954c "nonrelevant" (tip), it has no successor
742 742
743 743 If a rebase is going to create divergence, it should abort
744 744
745 745 $ hg log -G
746 746 @ 11:f44da1f4954c nonrelevant
747 747 |
748 748 | o 10:121d9e3bc4c6 P
749 749 |/
750 750 o 9:4be60e099a77 C
751 751 |
752 752 o 6:9c48361117de D
753 753 |
754 754 o 2:261e70097290 B2
755 755 |
756 756 o 0:4a2df7238c3b A
757 757
758 758
759 759 $ hg up 9
760 760 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
761 761 $ echo "john" > doe
762 762 $ hg add doe
763 763 $ hg commit -m "john doe"
764 764 created new head
765 765 $ hg up 10
766 766 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
767 767 $ echo "foo" > bar
768 768 $ hg add bar
769 769 $ hg commit --amend -m "10'"
770 770 $ hg up 10 --hidden
771 771 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
772 772 $ echo "bar" > foo
773 773 $ hg add foo
774 774 $ hg commit -m "bar foo"
775 775 $ hg log -G
776 776 @ 15:73568ab6879d bar foo
777 777 |
778 778 | o 14:77d874d096a2 10'
779 779 | |
780 780 | | o 12:3eb461388009 john doe
781 781 | |/
782 782 x | 10:121d9e3bc4c6 P
783 783 |/
784 784 o 9:4be60e099a77 C
785 785 |
786 786 o 6:9c48361117de D
787 787 |
788 788 o 2:261e70097290 B2
789 789 |
790 790 o 0:4a2df7238c3b A
791 791
792 792 $ hg summary
793 793 parent: 15:73568ab6879d tip (unstable)
794 794 bar foo
795 795 branch: default
796 796 commit: (clean)
797 797 update: 2 new changesets, 3 branch heads (merge)
798 798 phases: 8 draft
799 799 unstable: 1 changesets
800 800 $ hg rebase -s 10 -d 12
801 801 abort: this rebase will cause divergences from: 121d9e3bc4c6
802 802 (to force the rebase please set experimental.allowdivergence=True)
803 803 [255]
804 804 $ hg log -G
805 805 @ 15:73568ab6879d bar foo
806 806 |
807 807 | o 14:77d874d096a2 10'
808 808 | |
809 809 | | o 12:3eb461388009 john doe
810 810 | |/
811 811 x | 10:121d9e3bc4c6 P
812 812 |/
813 813 o 9:4be60e099a77 C
814 814 |
815 815 o 6:9c48361117de D
816 816 |
817 817 o 2:261e70097290 B2
818 818 |
819 819 o 0:4a2df7238c3b A
820 820
821 821 With experimental.allowdivergence=True, rebase can create divergence
822 822
823 823 $ hg rebase -s 10 -d 12 --config experimental.allowdivergence=True
824 824 rebasing 10:121d9e3bc4c6 "P"
825 825 rebasing 15:73568ab6879d "bar foo" (tip)
826 826 $ hg summary
827 827 parent: 17:61bd55f69bc4 tip
828 828 bar foo
829 829 branch: default
830 830 commit: (clean)
831 831 update: 1 new changesets, 2 branch heads (merge)
832 832 phases: 8 draft
833 833 divergent: 2 changesets
834 834
835 835 rebase --continue + skipped rev because their successors are in destination
836 836 we make a change in trunk and work on conflicting changes to make rebase abort.
837 837
838 838 $ hg log -G -r 17::
839 839 @ 17:61bd55f69bc4 bar foo
840 840 |
841 841 ~
842 842
843 843 Create the two changes in trunk
844 844 $ printf "a" > willconflict
845 845 $ hg add willconflict
846 846 $ hg commit -m "willconflict first version"
847 847
848 848 $ printf "dummy" > C
849 849 $ hg commit -m "dummy change successor"
850 850
851 851 Create the changes that we will rebase
852 852 $ hg update -C 17 -q
853 853 $ printf "b" > willconflict
854 854 $ hg add willconflict
855 855 $ hg commit -m "willconflict second version"
856 856 created new head
857 857 $ printf "dummy" > K
858 858 $ hg add K
859 859 $ hg commit -m "dummy change"
860 860 $ printf "dummy" > L
861 861 $ hg add L
862 862 $ hg commit -m "dummy change"
863 863 $ hg debugobsolete `hg log -r ".^" -T '{node}'` `hg log -r 19 -T '{node}'` --config experimental.evolution=all
864 864
865 865 $ hg log -G -r 17::
866 866 @ 22:7bdc8a87673d dummy change
867 867 |
868 868 x 21:8b31da3c4919 dummy change
869 869 |
870 870 o 20:b82fb57ea638 willconflict second version
871 871 |
872 872 | o 19:601db7a18f51 dummy change successor
873 873 | |
874 874 | o 18:357ddf1602d5 willconflict first version
875 875 |/
876 876 o 17:61bd55f69bc4 bar foo
877 877 |
878 878 ~
879 879 $ hg rebase -r ".^^ + .^ + ." -d 19
880 880 rebasing 20:b82fb57ea638 "willconflict second version"
881 881 merging willconflict
882 882 warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark')
883 883 unresolved conflicts (see hg resolve, then hg rebase --continue)
884 884 [1]
885 885
886 886 $ hg resolve --mark willconflict
887 887 (no more unresolved files)
888 888 continue: hg rebase --continue
889 889 $ hg rebase --continue
890 890 rebasing 20:b82fb57ea638 "willconflict second version"
891 891 note: not rebasing 21:8b31da3c4919 "dummy change", already in destination as 19:601db7a18f51 "dummy change successor"
892 892 rebasing 22:7bdc8a87673d "dummy change" (tip)
893 893 $ cd ..
894 894
895 895 rebase source is obsoleted (issue5198)
896 896 ---------------------------------
897 897
898 898 $ hg clone base amended
899 899 updating to branch default
900 900 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
901 901 $ cd amended
902 902 $ hg up 9520eea781bc
903 903 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
904 904 $ echo 1 >> E
905 905 $ hg commit --amend -m "E'"
906 906 $ hg log -G
907 907 @ 9:69abe8906104 E'
908 908 |
909 909 | o 7:02de42196ebe H
910 910 | |
911 911 | | o 6:eea13746799a G
912 912 | |/|
913 913 | o | 5:24b6387c8c8c F
914 914 |/ /
915 915 | x 4:9520eea781bc E
916 916 |/
917 917 | o 3:32af7686d403 D
918 918 | |
919 919 | o 2:5fddd98957c8 C
920 920 | |
921 921 | o 1:42ccdea3bb16 B
922 922 |/
923 923 o 0:cd010b8cd998 A
924 924
925 925 $ hg rebase -d . -s 9520eea781bc
926 926 note: not rebasing 4:9520eea781bc "E", already in destination as 9:69abe8906104 "E'"
927 927 rebasing 6:eea13746799a "G"
928 928 $ hg log -G
929 929 o 10:17be06e82e95 G
930 930 |\
931 931 | @ 9:69abe8906104 E'
932 932 | |
933 933 +---o 7:02de42196ebe H
934 934 | |
935 935 o | 5:24b6387c8c8c F
936 936 |/
937 937 | o 3:32af7686d403 D
938 938 | |
939 939 | o 2:5fddd98957c8 C
940 940 | |
941 941 | o 1:42ccdea3bb16 B
942 942 |/
943 943 o 0:cd010b8cd998 A
944 944
945 945 $ cd ..
946 946
947 947 Test that bookmark is moved and working dir is updated when all changesets have
948 948 equivalents in destination
949 949 $ hg init rbsrepo && cd rbsrepo
950 950 $ echo "[experimental]" > .hg/hgrc
951 951 $ echo "evolution=all" >> .hg/hgrc
952 952 $ echo "rebaseskipobsolete=on" >> .hg/hgrc
953 953 $ echo root > root && hg ci -Am root
954 954 adding root
955 955 $ echo a > a && hg ci -Am a
956 956 adding a
957 957 $ hg up 0
958 958 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
959 959 $ echo b > b && hg ci -Am b
960 960 adding b
961 961 created new head
962 962 $ hg rebase -r 2 -d 1
963 963 rebasing 2:1e9a3c00cbe9 "b" (tip)
964 964 $ hg log -r . # working dir is at rev 3 (successor of 2)
965 965 3:be1832deae9a b (no-eol)
966 966 $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now
967 967 $ hg up 2 && hg log -r . # working dir is at rev 2 again
968 968 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
969 969 2:1e9a3c00cbe9 b (no-eol)
970 $ hg rebase -r 2 -d 3
970 $ hg rebase -r 2 -d 3 --config experimental.evolution.track-operation=1
971 971 note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b"
972 972 Check that working directory was updated to rev 3 although rev 2 was skipped
973 973 during the rebase operation
974 974 $ hg log -r .
975 975 3:be1832deae9a b (no-eol)
976 976
977 977 Check that bookmark was moved to rev 3 although rev 2 was skipped
978 978 during the rebase operation
979 979 $ hg bookmarks
980 980 mybook 3:be1832deae9a
981 $ hg debugobsolete --rev tip
982 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (*) {'user': 'test'} (glob)
General Comments 0
You need to be logged in to leave comments. Login now