##// END OF EJS Templates
rebase: use cmdutil.check_incompatible_arguments() for action+confirm/dryrun...
Martin von Zweigbergk -
r44379:905b2178 default
parent child Browse files
Show More
@@ -1,2308 +1,2308 b''
1 1 # rebase.py - rebasing feature for mercurial
2 2 #
3 3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''command to move sets of revisions to a different ancestor
9 9
10 10 This extension lets you rebase changesets in an existing Mercurial
11 11 repository.
12 12
13 13 For more information:
14 14 https://mercurial-scm.org/wiki/RebaseExtension
15 15 '''
16 16
17 17 from __future__ import absolute_import
18 18
19 19 import errno
20 20 import os
21 21
22 22 from mercurial.i18n import _
23 23 from mercurial.node import (
24 24 nullrev,
25 25 short,
26 26 )
27 27 from mercurial.pycompat import open
28 28 from mercurial import (
29 29 bookmarks,
30 30 cmdutil,
31 31 commands,
32 32 copies,
33 33 destutil,
34 34 dirstateguard,
35 35 error,
36 36 extensions,
37 37 hg,
38 38 merge as mergemod,
39 39 mergeutil,
40 40 obsolete,
41 41 obsutil,
42 42 patch,
43 43 phases,
44 44 pycompat,
45 45 registrar,
46 46 repair,
47 47 revset,
48 48 revsetlang,
49 49 scmutil,
50 50 smartset,
51 51 state as statemod,
52 52 util,
53 53 )
54 54
55 55 # The following constants are used throughout the rebase module. The ordering of
56 56 # their values must be maintained.
57 57
58 58 # Indicates that a revision needs to be rebased
59 59 revtodo = -1
60 60 revtodostr = b'-1'
61 61
62 62 # legacy revstates no longer needed in current code
63 63 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
64 64 legacystates = {b'-2', b'-3', b'-4', b'-5'}
65 65
66 66 cmdtable = {}
67 67 command = registrar.command(cmdtable)
68 68 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
69 69 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
70 70 # be specifying the version(s) of Mercurial they are tested with, or
71 71 # leave the attribute unspecified.
72 72 testedwith = b'ships-with-hg-core'
73 73
74 74
75 75 def _nothingtorebase():
76 76 return 1
77 77
78 78
79 79 def _savegraft(ctx, extra):
80 80 s = ctx.extra().get(b'source', None)
81 81 if s is not None:
82 82 extra[b'source'] = s
83 83 s = ctx.extra().get(b'intermediate-source', None)
84 84 if s is not None:
85 85 extra[b'intermediate-source'] = s
86 86
87 87
88 88 def _savebranch(ctx, extra):
89 89 extra[b'branch'] = ctx.branch()
90 90
91 91
92 92 def _destrebase(repo, sourceset, destspace=None):
93 93 """small wrapper around destmerge to pass the right extra args
94 94
95 95 Please wrap destutil.destmerge instead."""
96 96 return destutil.destmerge(
97 97 repo,
98 98 action=b'rebase',
99 99 sourceset=sourceset,
100 100 onheadcheck=False,
101 101 destspace=destspace,
102 102 )
103 103
104 104
105 105 revsetpredicate = registrar.revsetpredicate()
106 106
107 107
108 108 @revsetpredicate(b'_destrebase')
109 109 def _revsetdestrebase(repo, subset, x):
110 110 # ``_rebasedefaultdest()``
111 111
112 112 # default destination for rebase.
113 113 # # XXX: Currently private because I expect the signature to change.
114 114 # # XXX: - bailing out in case of ambiguity vs returning all data.
115 115 # i18n: "_rebasedefaultdest" is a keyword
116 116 sourceset = None
117 117 if x is not None:
118 118 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
119 119 return subset & smartset.baseset([_destrebase(repo, sourceset)])
120 120
121 121
122 122 @revsetpredicate(b'_destautoorphanrebase')
123 123 def _revsetdestautoorphanrebase(repo, subset, x):
124 124 # ``_destautoorphanrebase()``
125 125
126 126 # automatic rebase destination for a single orphan revision.
127 127 unfi = repo.unfiltered()
128 128 obsoleted = unfi.revs(b'obsolete()')
129 129
130 130 src = revset.getset(repo, subset, x).first()
131 131
132 132 # Empty src or already obsoleted - Do not return a destination
133 133 if not src or src in obsoleted:
134 134 return smartset.baseset()
135 135 dests = destutil.orphanpossibledestination(repo, src)
136 136 if len(dests) > 1:
137 137 raise error.Abort(
138 138 _(b"ambiguous automatic rebase: %r could end up on any of %r")
139 139 % (src, dests)
140 140 )
141 141 # We have zero or one destination, so we can just return here.
142 142 return smartset.baseset(dests)
143 143
144 144
145 145 def _ctxdesc(ctx):
146 146 """short description for a context"""
147 147 desc = b'%d:%s "%s"' % (
148 148 ctx.rev(),
149 149 ctx,
150 150 ctx.description().split(b'\n', 1)[0],
151 151 )
152 152 repo = ctx.repo()
153 153 names = []
154 154 for nsname, ns in pycompat.iteritems(repo.names):
155 155 if nsname == b'branches':
156 156 continue
157 157 names.extend(ns.names(repo, ctx.node()))
158 158 if names:
159 159 desc += b' (%s)' % b' '.join(names)
160 160 return desc
161 161
162 162
163 163 class rebaseruntime(object):
164 164 """This class is a container for rebase runtime state"""
165 165
166 166 def __init__(self, repo, ui, inmemory=False, opts=None):
167 167 if opts is None:
168 168 opts = {}
169 169
170 170 # prepared: whether we have rebasestate prepared or not. Currently it
171 171 # decides whether "self.repo" is unfiltered or not.
172 172 # The rebasestate has explicit hash to hash instructions not depending
173 173 # on visibility. If rebasestate exists (in-memory or on-disk), use
174 174 # unfiltered repo to avoid visibility issues.
175 175 # Before knowing rebasestate (i.e. when starting a new rebase (not
176 176 # --continue or --abort)), the original repo should be used so
177 177 # visibility-dependent revsets are correct.
178 178 self.prepared = False
179 179 self._repo = repo
180 180
181 181 self.ui = ui
182 182 self.opts = opts
183 183 self.originalwd = None
184 184 self.external = nullrev
185 185 # Mapping between the old revision id and either what is the new rebased
186 186 # revision or what needs to be done with the old revision. The state
187 187 # dict will be what contains most of the rebase progress state.
188 188 self.state = {}
189 189 self.activebookmark = None
190 190 self.destmap = {}
191 191 self.skipped = set()
192 192
193 193 self.collapsef = opts.get(b'collapse', False)
194 194 self.collapsemsg = cmdutil.logmessage(ui, opts)
195 195 self.date = opts.get(b'date', None)
196 196
197 197 e = opts.get(b'extrafn') # internal, used by e.g. hgsubversion
198 198 self.extrafns = [_savegraft]
199 199 if e:
200 200 self.extrafns = [e]
201 201
202 202 self.backupf = ui.configbool(b'rewrite', b'backup-bundle')
203 203 self.keepf = opts.get(b'keep', False)
204 204 self.keepbranchesf = opts.get(b'keepbranches', False)
205 205 self.obsoletenotrebased = {}
206 206 self.obsoletewithoutsuccessorindestination = set()
207 207 self.inmemory = inmemory
208 208 self.stateobj = statemod.cmdstate(repo, b'rebasestate')
209 209
210 210 @property
211 211 def repo(self):
212 212 if self.prepared:
213 213 return self._repo.unfiltered()
214 214 else:
215 215 return self._repo
216 216
217 217 def storestatus(self, tr=None):
218 218 """Store the current status to allow recovery"""
219 219 if tr:
220 220 tr.addfilegenerator(
221 221 b'rebasestate',
222 222 (b'rebasestate',),
223 223 self._writestatus,
224 224 location=b'plain',
225 225 )
226 226 else:
227 227 with self.repo.vfs(b"rebasestate", b"w") as f:
228 228 self._writestatus(f)
229 229
230 230 def _writestatus(self, f):
231 231 repo = self.repo
232 232 assert repo.filtername is None
233 233 f.write(repo[self.originalwd].hex() + b'\n')
234 234 # was "dest". we now write dest per src root below.
235 235 f.write(b'\n')
236 236 f.write(repo[self.external].hex() + b'\n')
237 237 f.write(b'%d\n' % int(self.collapsef))
238 238 f.write(b'%d\n' % int(self.keepf))
239 239 f.write(b'%d\n' % int(self.keepbranchesf))
240 240 f.write(b'%s\n' % (self.activebookmark or b''))
241 241 destmap = self.destmap
242 242 for d, v in pycompat.iteritems(self.state):
243 243 oldrev = repo[d].hex()
244 244 if v >= 0:
245 245 newrev = repo[v].hex()
246 246 else:
247 247 newrev = b"%d" % v
248 248 destnode = repo[destmap[d]].hex()
249 249 f.write(b"%s:%s:%s\n" % (oldrev, newrev, destnode))
250 250 repo.ui.debug(b'rebase status stored\n')
251 251
252 252 def restorestatus(self):
253 253 """Restore a previously stored status"""
254 254 if not self.stateobj.exists():
255 255 cmdutil.wrongtooltocontinue(self.repo, _(b'rebase'))
256 256
257 257 data = self._read()
258 258 self.repo.ui.debug(b'rebase status resumed\n')
259 259
260 260 self.originalwd = data[b'originalwd']
261 261 self.destmap = data[b'destmap']
262 262 self.state = data[b'state']
263 263 self.skipped = data[b'skipped']
264 264 self.collapsef = data[b'collapse']
265 265 self.keepf = data[b'keep']
266 266 self.keepbranchesf = data[b'keepbranches']
267 267 self.external = data[b'external']
268 268 self.activebookmark = data[b'activebookmark']
269 269
270 270 def _read(self):
271 271 self.prepared = True
272 272 repo = self.repo
273 273 assert repo.filtername is None
274 274 data = {
275 275 b'keepbranches': None,
276 276 b'collapse': None,
277 277 b'activebookmark': None,
278 278 b'external': nullrev,
279 279 b'keep': None,
280 280 b'originalwd': None,
281 281 }
282 282 legacydest = None
283 283 state = {}
284 284 destmap = {}
285 285
286 286 if True:
287 287 f = repo.vfs(b"rebasestate")
288 288 for i, l in enumerate(f.read().splitlines()):
289 289 if i == 0:
290 290 data[b'originalwd'] = repo[l].rev()
291 291 elif i == 1:
292 292 # this line should be empty in newer version. but legacy
293 293 # clients may still use it
294 294 if l:
295 295 legacydest = repo[l].rev()
296 296 elif i == 2:
297 297 data[b'external'] = repo[l].rev()
298 298 elif i == 3:
299 299 data[b'collapse'] = bool(int(l))
300 300 elif i == 4:
301 301 data[b'keep'] = bool(int(l))
302 302 elif i == 5:
303 303 data[b'keepbranches'] = bool(int(l))
304 304 elif i == 6 and not (len(l) == 81 and b':' in l):
305 305 # line 6 is a recent addition, so for backwards
306 306 # compatibility check that the line doesn't look like the
307 307 # oldrev:newrev lines
308 308 data[b'activebookmark'] = l
309 309 else:
310 310 args = l.split(b':')
311 311 oldrev = repo[args[0]].rev()
312 312 newrev = args[1]
313 313 if newrev in legacystates:
314 314 continue
315 315 if len(args) > 2:
316 316 destrev = repo[args[2]].rev()
317 317 else:
318 318 destrev = legacydest
319 319 destmap[oldrev] = destrev
320 320 if newrev == revtodostr:
321 321 state[oldrev] = revtodo
322 322 # Legacy compat special case
323 323 else:
324 324 state[oldrev] = repo[newrev].rev()
325 325
326 326 if data[b'keepbranches'] is None:
327 327 raise error.Abort(_(b'.hg/rebasestate is incomplete'))
328 328
329 329 data[b'destmap'] = destmap
330 330 data[b'state'] = state
331 331 skipped = set()
332 332 # recompute the set of skipped revs
333 333 if not data[b'collapse']:
334 334 seen = set(destmap.values())
335 335 for old, new in sorted(state.items()):
336 336 if new != revtodo and new in seen:
337 337 skipped.add(old)
338 338 seen.add(new)
339 339 data[b'skipped'] = skipped
340 340 repo.ui.debug(
341 341 b'computed skipped revs: %s\n'
342 342 % (b' '.join(b'%d' % r for r in sorted(skipped)) or b'')
343 343 )
344 344
345 345 return data
346 346
347 347 def _handleskippingobsolete(self, obsoleterevs, destmap):
348 348 """Compute structures necessary for skipping obsolete revisions
349 349
350 350 obsoleterevs: iterable of all obsolete revisions in rebaseset
351 351 destmap: {srcrev: destrev} destination revisions
352 352 """
353 353 self.obsoletenotrebased = {}
354 354 if not self.ui.configbool(b'experimental', b'rebaseskipobsolete'):
355 355 return
356 356 obsoleteset = set(obsoleterevs)
357 357 (
358 358 self.obsoletenotrebased,
359 359 self.obsoletewithoutsuccessorindestination,
360 360 obsoleteextinctsuccessors,
361 361 ) = _computeobsoletenotrebased(self.repo, obsoleteset, destmap)
362 362 skippedset = set(self.obsoletenotrebased)
363 363 skippedset.update(self.obsoletewithoutsuccessorindestination)
364 364 skippedset.update(obsoleteextinctsuccessors)
365 365 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
366 366
367 367 def _prepareabortorcontinue(self, isabort, backup=True, suppwarns=False):
368 368 try:
369 369 self.restorestatus()
370 370 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
371 371 except error.RepoLookupError:
372 372 if isabort:
373 373 clearstatus(self.repo)
374 374 clearcollapsemsg(self.repo)
375 375 self.repo.ui.warn(
376 376 _(
377 377 b'rebase aborted (no revision is removed,'
378 378 b' only broken state is cleared)\n'
379 379 )
380 380 )
381 381 return 0
382 382 else:
383 383 msg = _(b'cannot continue inconsistent rebase')
384 384 hint = _(b'use "hg rebase --abort" to clear broken state')
385 385 raise error.Abort(msg, hint=hint)
386 386
387 387 if isabort:
388 388 backup = backup and self.backupf
389 389 return self._abort(backup=backup, suppwarns=suppwarns)
390 390
391 391 def _preparenewrebase(self, destmap):
392 392 if not destmap:
393 393 return _nothingtorebase()
394 394
395 395 rebaseset = destmap.keys()
396 396 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
397 397 if not (self.keepf or allowunstable) and self.repo.revs(
398 398 b'first(children(%ld) - %ld)', rebaseset, rebaseset
399 399 ):
400 400 raise error.Abort(
401 401 _(
402 402 b"can't remove original changesets with"
403 403 b" unrebased descendants"
404 404 ),
405 405 hint=_(b'use --keep to keep original changesets'),
406 406 )
407 407
408 408 result = buildstate(self.repo, destmap, self.collapsef)
409 409
410 410 if not result:
411 411 # Empty state built, nothing to rebase
412 412 self.ui.status(_(b'nothing to rebase\n'))
413 413 return _nothingtorebase()
414 414
415 415 for root in self.repo.set(b'roots(%ld)', rebaseset):
416 416 if not self.keepf and not root.mutable():
417 417 raise error.Abort(
418 418 _(b"can't rebase public changeset %s") % root,
419 419 hint=_(b"see 'hg help phases' for details"),
420 420 )
421 421
422 422 (self.originalwd, self.destmap, self.state) = result
423 423 if self.collapsef:
424 424 dests = set(self.destmap.values())
425 425 if len(dests) != 1:
426 426 raise error.Abort(
427 427 _(b'--collapse does not work with multiple destinations')
428 428 )
429 429 destrev = next(iter(dests))
430 430 destancestors = self.repo.changelog.ancestors(
431 431 [destrev], inclusive=True
432 432 )
433 433 self.external = externalparent(self.repo, self.state, destancestors)
434 434
435 435 for destrev in sorted(set(destmap.values())):
436 436 dest = self.repo[destrev]
437 437 if dest.closesbranch() and not self.keepbranchesf:
438 438 self.ui.status(_(b'reopening closed branch head %s\n') % dest)
439 439
440 440 self.prepared = True
441 441
442 442 def _assignworkingcopy(self):
443 443 if self.inmemory:
444 444 from mercurial.context import overlayworkingctx
445 445
446 446 self.wctx = overlayworkingctx(self.repo)
447 447 self.repo.ui.debug(b"rebasing in-memory\n")
448 448 else:
449 449 self.wctx = self.repo[None]
450 450 self.repo.ui.debug(b"rebasing on disk\n")
451 451 self.repo.ui.log(
452 452 b"rebase",
453 453 b"using in-memory rebase: %r\n",
454 454 self.inmemory,
455 455 rebase_imm_used=self.inmemory,
456 456 )
457 457
458 458 def _performrebase(self, tr):
459 459 self._assignworkingcopy()
460 460 repo, ui = self.repo, self.ui
461 461 if self.keepbranchesf:
462 462 # insert _savebranch at the start of extrafns so if
463 463 # there's a user-provided extrafn it can clobber branch if
464 464 # desired
465 465 self.extrafns.insert(0, _savebranch)
466 466 if self.collapsef:
467 467 branches = set()
468 468 for rev in self.state:
469 469 branches.add(repo[rev].branch())
470 470 if len(branches) > 1:
471 471 raise error.Abort(
472 472 _(b'cannot collapse multiple named branches')
473 473 )
474 474
475 475 # Calculate self.obsoletenotrebased
476 476 obsrevs = _filterobsoleterevs(self.repo, self.state)
477 477 self._handleskippingobsolete(obsrevs, self.destmap)
478 478
479 479 # Keep track of the active bookmarks in order to reset them later
480 480 self.activebookmark = self.activebookmark or repo._activebookmark
481 481 if self.activebookmark:
482 482 bookmarks.deactivate(repo)
483 483
484 484 # Store the state before we begin so users can run 'hg rebase --abort'
485 485 # if we fail before the transaction closes.
486 486 self.storestatus()
487 487 if tr:
488 488 # When using single transaction, store state when transaction
489 489 # commits.
490 490 self.storestatus(tr)
491 491
492 492 cands = [k for k, v in pycompat.iteritems(self.state) if v == revtodo]
493 493 p = repo.ui.makeprogress(
494 494 _(b"rebasing"), unit=_(b'changesets'), total=len(cands)
495 495 )
496 496
497 497 def progress(ctx):
498 498 p.increment(item=(b"%d:%s" % (ctx.rev(), ctx)))
499 499
500 500 allowdivergence = self.ui.configbool(
501 501 b'experimental', b'evolution.allowdivergence'
502 502 )
503 503 for subset in sortsource(self.destmap):
504 504 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset)
505 505 if not allowdivergence:
506 506 sortedrevs -= self.repo.revs(
507 507 b'descendants(%ld) and not %ld',
508 508 self.obsoletewithoutsuccessorindestination,
509 509 self.obsoletewithoutsuccessorindestination,
510 510 )
511 511 for rev in sortedrevs:
512 512 self._rebasenode(tr, rev, allowdivergence, progress)
513 513 p.complete()
514 514 ui.note(_(b'rebase merging completed\n'))
515 515
516 516 def _concludenode(self, rev, p1, p2, editor, commitmsg=None):
517 517 '''Commit the wd changes with parents p1 and p2.
518 518
519 519 Reuse commit info from rev but also store useful information in extra.
520 520 Return node of committed revision.'''
521 521 repo = self.repo
522 522 ctx = repo[rev]
523 523 if commitmsg is None:
524 524 commitmsg = ctx.description()
525 525 date = self.date
526 526 if date is None:
527 527 date = ctx.date()
528 528 extra = {b'rebase_source': ctx.hex()}
529 529 for c in self.extrafns:
530 530 c(ctx, extra)
531 531 keepbranch = self.keepbranchesf and repo[p1].branch() != ctx.branch()
532 532 destphase = max(ctx.phase(), phases.draft)
533 533 overrides = {(b'phases', b'new-commit'): destphase}
534 534 if keepbranch:
535 535 overrides[(b'ui', b'allowemptycommit')] = True
536 536 with repo.ui.configoverride(overrides, b'rebase'):
537 537 if self.inmemory:
538 538 newnode = commitmemorynode(
539 539 repo,
540 540 p1,
541 541 p2,
542 542 wctx=self.wctx,
543 543 extra=extra,
544 544 commitmsg=commitmsg,
545 545 editor=editor,
546 546 user=ctx.user(),
547 547 date=date,
548 548 )
549 549 mergemod.mergestate.clean(repo)
550 550 else:
551 551 newnode = commitnode(
552 552 repo,
553 553 p1,
554 554 p2,
555 555 extra=extra,
556 556 commitmsg=commitmsg,
557 557 editor=editor,
558 558 user=ctx.user(),
559 559 date=date,
560 560 )
561 561
562 562 if newnode is None:
563 563 # If it ended up being a no-op commit, then the normal
564 564 # merge state clean-up path doesn't happen, so do it
565 565 # here. Fix issue5494
566 566 mergemod.mergestate.clean(repo)
567 567 return newnode
568 568
569 569 def _rebasenode(self, tr, rev, allowdivergence, progressfn):
570 570 repo, ui, opts = self.repo, self.ui, self.opts
571 571 dest = self.destmap[rev]
572 572 ctx = repo[rev]
573 573 desc = _ctxdesc(ctx)
574 574 if self.state[rev] == rev:
575 575 ui.status(_(b'already rebased %s\n') % desc)
576 576 elif (
577 577 not allowdivergence
578 578 and rev in self.obsoletewithoutsuccessorindestination
579 579 ):
580 580 msg = (
581 581 _(
582 582 b'note: not rebasing %s and its descendants as '
583 583 b'this would cause divergence\n'
584 584 )
585 585 % desc
586 586 )
587 587 repo.ui.status(msg)
588 588 self.skipped.add(rev)
589 589 elif rev in self.obsoletenotrebased:
590 590 succ = self.obsoletenotrebased[rev]
591 591 if succ is None:
592 592 msg = _(b'note: not rebasing %s, it has no successor\n') % desc
593 593 else:
594 594 succdesc = _ctxdesc(repo[succ])
595 595 msg = _(
596 596 b'note: not rebasing %s, already in destination as %s\n'
597 597 ) % (desc, succdesc)
598 598 repo.ui.status(msg)
599 599 # Make clearrebased aware state[rev] is not a true successor
600 600 self.skipped.add(rev)
601 601 # Record rev as moved to its desired destination in self.state.
602 602 # This helps bookmark and working parent movement.
603 603 dest = max(
604 604 adjustdest(repo, rev, self.destmap, self.state, self.skipped)
605 605 )
606 606 self.state[rev] = dest
607 607 elif self.state[rev] == revtodo:
608 608 ui.status(_(b'rebasing %s\n') % desc)
609 609 progressfn(ctx)
610 610 p1, p2, base = defineparents(
611 611 repo,
612 612 rev,
613 613 self.destmap,
614 614 self.state,
615 615 self.skipped,
616 616 self.obsoletenotrebased,
617 617 )
618 618 if not self.inmemory and len(repo[None].parents()) == 2:
619 619 repo.ui.debug(b'resuming interrupted rebase\n')
620 620 else:
621 621 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
622 622 with ui.configoverride(overrides, b'rebase'):
623 623 stats = rebasenode(
624 624 repo,
625 625 rev,
626 626 p1,
627 627 base,
628 628 self.collapsef,
629 629 dest,
630 630 wctx=self.wctx,
631 631 )
632 632 if stats.unresolvedcount > 0:
633 633 if self.inmemory:
634 634 raise error.InMemoryMergeConflictsError()
635 635 else:
636 636 raise error.InterventionRequired(
637 637 _(
638 638 b'unresolved conflicts (see hg '
639 639 b'resolve, then hg rebase --continue)'
640 640 )
641 641 )
642 642 if not self.collapsef:
643 643 merging = p2 != nullrev
644 644 editform = cmdutil.mergeeditform(merging, b'rebase')
645 645 editor = cmdutil.getcommiteditor(
646 646 editform=editform, **pycompat.strkwargs(opts)
647 647 )
648 648 newnode = self._concludenode(rev, p1, p2, editor)
649 649 else:
650 650 # Skip commit if we are collapsing
651 651 if self.inmemory:
652 652 self.wctx.setbase(repo[p1])
653 653 else:
654 654 repo.setparents(repo[p1].node())
655 655 newnode = None
656 656 # Update the state
657 657 if newnode is not None:
658 658 self.state[rev] = repo[newnode].rev()
659 659 ui.debug(b'rebased as %s\n' % short(newnode))
660 660 else:
661 661 if not self.collapsef:
662 662 ui.warn(
663 663 _(
664 664 b'note: not rebasing %s, its destination already '
665 665 b'has all its changes\n'
666 666 )
667 667 % desc
668 668 )
669 669 self.skipped.add(rev)
670 670 self.state[rev] = p1
671 671 ui.debug(b'next revision set to %d\n' % p1)
672 672 else:
673 673 ui.status(
674 674 _(b'already rebased %s as %s\n') % (desc, repo[self.state[rev]])
675 675 )
676 676 if not tr:
677 677 # When not using single transaction, store state after each
678 678 # commit is completely done. On InterventionRequired, we thus
679 679 # won't store the status. Instead, we'll hit the "len(parents) == 2"
680 680 # case and realize that the commit was in progress.
681 681 self.storestatus()
682 682
683 683 def _finishrebase(self):
684 684 repo, ui, opts = self.repo, self.ui, self.opts
685 685 fm = ui.formatter(b'rebase', opts)
686 686 fm.startitem()
687 687 if self.collapsef:
688 688 p1, p2, _base = defineparents(
689 689 repo,
690 690 min(self.state),
691 691 self.destmap,
692 692 self.state,
693 693 self.skipped,
694 694 self.obsoletenotrebased,
695 695 )
696 696 editopt = opts.get(b'edit')
697 697 editform = b'rebase.collapse'
698 698 if self.collapsemsg:
699 699 commitmsg = self.collapsemsg
700 700 else:
701 701 commitmsg = b'Collapsed revision'
702 702 for rebased in sorted(self.state):
703 703 if rebased not in self.skipped:
704 704 commitmsg += b'\n* %s' % repo[rebased].description()
705 705 editopt = True
706 706 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
707 707 revtoreuse = max(self.state)
708 708
709 709 newnode = self._concludenode(
710 710 revtoreuse, p1, self.external, editor, commitmsg=commitmsg
711 711 )
712 712
713 713 if newnode is not None:
714 714 newrev = repo[newnode].rev()
715 715 for oldrev in self.state:
716 716 self.state[oldrev] = newrev
717 717
718 718 if b'qtip' in repo.tags():
719 719 updatemq(repo, self.state, self.skipped, **pycompat.strkwargs(opts))
720 720
721 721 # restore original working directory
722 722 # (we do this before stripping)
723 723 newwd = self.state.get(self.originalwd, self.originalwd)
724 724 if newwd < 0:
725 725 # original directory is a parent of rebase set root or ignored
726 726 newwd = self.originalwd
727 727 if newwd not in [c.rev() for c in repo[None].parents()]:
728 728 ui.note(_(b"update back to initial working directory parent\n"))
729 729 hg.updaterepo(repo, newwd, overwrite=False)
730 730
731 731 collapsedas = None
732 732 if self.collapsef and not self.keepf:
733 733 collapsedas = newnode
734 734 clearrebased(
735 735 ui,
736 736 repo,
737 737 self.destmap,
738 738 self.state,
739 739 self.skipped,
740 740 collapsedas,
741 741 self.keepf,
742 742 fm=fm,
743 743 backup=self.backupf,
744 744 )
745 745
746 746 clearstatus(repo)
747 747 clearcollapsemsg(repo)
748 748
749 749 ui.note(_(b"rebase completed\n"))
750 750 util.unlinkpath(repo.sjoin(b'undo'), ignoremissing=True)
751 751 if self.skipped:
752 752 skippedlen = len(self.skipped)
753 753 ui.note(_(b"%d revisions have been skipped\n") % skippedlen)
754 754 fm.end()
755 755
756 756 if (
757 757 self.activebookmark
758 758 and self.activebookmark in repo._bookmarks
759 759 and repo[b'.'].node() == repo._bookmarks[self.activebookmark]
760 760 ):
761 761 bookmarks.activate(repo, self.activebookmark)
762 762
763 763 def _abort(self, backup=True, suppwarns=False):
764 764 '''Restore the repository to its original state.'''
765 765
766 766 repo = self.repo
767 767 try:
768 768 # If the first commits in the rebased set get skipped during the
769 769 # rebase, their values within the state mapping will be the dest
770 770 # rev id. The rebased list must must not contain the dest rev
771 771 # (issue4896)
772 772 rebased = [
773 773 s
774 774 for r, s in self.state.items()
775 775 if s >= 0 and s != r and s != self.destmap[r]
776 776 ]
777 777 immutable = [d for d in rebased if not repo[d].mutable()]
778 778 cleanup = True
779 779 if immutable:
780 780 repo.ui.warn(
781 781 _(b"warning: can't clean up public changesets %s\n")
782 782 % b', '.join(bytes(repo[r]) for r in immutable),
783 783 hint=_(b"see 'hg help phases' for details"),
784 784 )
785 785 cleanup = False
786 786
787 787 descendants = set()
788 788 if rebased:
789 789 descendants = set(repo.changelog.descendants(rebased))
790 790 if descendants - set(rebased):
791 791 repo.ui.warn(
792 792 _(
793 793 b"warning: new changesets detected on "
794 794 b"destination branch, can't strip\n"
795 795 )
796 796 )
797 797 cleanup = False
798 798
799 799 if cleanup:
800 800 shouldupdate = False
801 801 if rebased:
802 802 strippoints = [
803 803 c.node() for c in repo.set(b'roots(%ld)', rebased)
804 804 ]
805 805
806 806 updateifonnodes = set(rebased)
807 807 updateifonnodes.update(self.destmap.values())
808 808 updateifonnodes.add(self.originalwd)
809 809 shouldupdate = repo[b'.'].rev() in updateifonnodes
810 810
811 811 # Update away from the rebase if necessary
812 812 if shouldupdate or needupdate(repo, self.state):
813 813 mergemod.update(
814 814 repo, self.originalwd, branchmerge=False, force=True
815 815 )
816 816
817 817 # Strip from the first rebased revision
818 818 if rebased:
819 819 repair.strip(repo.ui, repo, strippoints, backup=backup)
820 820
821 821 if self.activebookmark and self.activebookmark in repo._bookmarks:
822 822 bookmarks.activate(repo, self.activebookmark)
823 823
824 824 finally:
825 825 clearstatus(repo)
826 826 clearcollapsemsg(repo)
827 827 if not suppwarns:
828 828 repo.ui.warn(_(b'rebase aborted\n'))
829 829 return 0
830 830
831 831
832 832 @command(
833 833 b'rebase',
834 834 [
835 835 (
836 836 b's',
837 837 b'source',
838 838 b'',
839 839 _(b'rebase the specified changeset and descendants'),
840 840 _(b'REV'),
841 841 ),
842 842 (
843 843 b'b',
844 844 b'base',
845 845 b'',
846 846 _(b'rebase everything from branching point of specified changeset'),
847 847 _(b'REV'),
848 848 ),
849 849 (b'r', b'rev', [], _(b'rebase these revisions'), _(b'REV')),
850 850 (
851 851 b'd',
852 852 b'dest',
853 853 b'',
854 854 _(b'rebase onto the specified changeset'),
855 855 _(b'REV'),
856 856 ),
857 857 (b'', b'collapse', False, _(b'collapse the rebased changesets')),
858 858 (
859 859 b'm',
860 860 b'message',
861 861 b'',
862 862 _(b'use text as collapse commit message'),
863 863 _(b'TEXT'),
864 864 ),
865 865 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
866 866 (
867 867 b'l',
868 868 b'logfile',
869 869 b'',
870 870 _(b'read collapse commit message from file'),
871 871 _(b'FILE'),
872 872 ),
873 873 (b'k', b'keep', False, _(b'keep original changesets')),
874 874 (b'', b'keepbranches', False, _(b'keep original branch names')),
875 875 (b'D', b'detach', False, _(b'(DEPRECATED)')),
876 876 (b'i', b'interactive', False, _(b'(DEPRECATED)')),
877 877 (b't', b'tool', b'', _(b'specify merge tool')),
878 878 (b'', b'stop', False, _(b'stop interrupted rebase')),
879 879 (b'c', b'continue', False, _(b'continue an interrupted rebase')),
880 880 (b'a', b'abort', False, _(b'abort an interrupted rebase')),
881 881 (
882 882 b'',
883 883 b'auto-orphans',
884 884 b'',
885 885 _(
886 886 b'automatically rebase orphan revisions '
887 887 b'in the specified revset (EXPERIMENTAL)'
888 888 ),
889 889 ),
890 890 ]
891 891 + cmdutil.dryrunopts
892 892 + cmdutil.formatteropts
893 893 + cmdutil.confirmopts,
894 894 _(b'[-s REV | -b REV] [-d REV] [OPTION]'),
895 895 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
896 896 )
897 897 def rebase(ui, repo, **opts):
898 898 """move changeset (and descendants) to a different branch
899 899
900 900 Rebase uses repeated merging to graft changesets from one part of
901 901 history (the source) onto another (the destination). This can be
902 902 useful for linearizing *local* changes relative to a master
903 903 development tree.
904 904
905 905 Published commits cannot be rebased (see :hg:`help phases`).
906 906 To copy commits, see :hg:`help graft`.
907 907
908 908 If you don't specify a destination changeset (``-d/--dest``), rebase
909 909 will use the same logic as :hg:`merge` to pick a destination. if
910 910 the current branch contains exactly one other head, the other head
911 911 is merged with by default. Otherwise, an explicit revision with
912 912 which to merge with must be provided. (destination changeset is not
913 913 modified by rebasing, but new changesets are added as its
914 914 descendants.)
915 915
916 916 Here are the ways to select changesets:
917 917
918 918 1. Explicitly select them using ``--rev``.
919 919
920 920 2. Use ``--source`` to select a root changeset and include all of its
921 921 descendants.
922 922
923 923 3. Use ``--base`` to select a changeset; rebase will find ancestors
924 924 and their descendants which are not also ancestors of the destination.
925 925
926 926 4. If you do not specify any of ``--rev``, ``--source``, or ``--base``,
927 927 rebase will use ``--base .`` as above.
928 928
929 929 If ``--source`` or ``--rev`` is used, special names ``SRC`` and ``ALLSRC``
930 930 can be used in ``--dest``. Destination would be calculated per source
931 931 revision with ``SRC`` substituted by that single source revision and
932 932 ``ALLSRC`` substituted by all source revisions.
933 933
934 934 Rebase will destroy original changesets unless you use ``--keep``.
935 935 It will also move your bookmarks (even if you do).
936 936
937 937 Some changesets may be dropped if they do not contribute changes
938 938 (e.g. merges from the destination branch).
939 939
940 940 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
941 941 a named branch with two heads. You will need to explicitly specify source
942 942 and/or destination.
943 943
944 944 If you need to use a tool to automate merge/conflict decisions, you
945 945 can specify one with ``--tool``, see :hg:`help merge-tools`.
946 946 As a caveat: the tool will not be used to mediate when a file was
947 947 deleted, there is no hook presently available for this.
948 948
949 949 If a rebase is interrupted to manually resolve a conflict, it can be
950 950 continued with --continue/-c, aborted with --abort/-a, or stopped with
951 951 --stop.
952 952
953 953 .. container:: verbose
954 954
955 955 Examples:
956 956
957 957 - move "local changes" (current commit back to branching point)
958 958 to the current branch tip after a pull::
959 959
960 960 hg rebase
961 961
962 962 - move a single changeset to the stable branch::
963 963
964 964 hg rebase -r 5f493448 -d stable
965 965
966 966 - splice a commit and all its descendants onto another part of history::
967 967
968 968 hg rebase --source c0c3 --dest 4cf9
969 969
970 970 - rebase everything on a branch marked by a bookmark onto the
971 971 default branch::
972 972
973 973 hg rebase --base myfeature --dest default
974 974
975 975 - collapse a sequence of changes into a single commit::
976 976
977 977 hg rebase --collapse -r 1520:1525 -d .
978 978
979 979 - move a named branch while preserving its name::
980 980
981 981 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
982 982
983 983 - stabilize orphaned changesets so history looks linear::
984 984
985 985 hg rebase -r 'orphan()-obsolete()'\
986 986 -d 'first(max((successors(max(roots(ALLSRC) & ::SRC)^)-obsolete())::) +\
987 987 max(::((roots(ALLSRC) & ::SRC)^)-obsolete()))'
988 988
989 989 Configuration Options:
990 990
991 991 You can make rebase require a destination if you set the following config
992 992 option::
993 993
994 994 [commands]
995 995 rebase.requiredest = True
996 996
997 997 By default, rebase will close the transaction after each commit. For
998 998 performance purposes, you can configure rebase to use a single transaction
999 999 across the entire rebase. WARNING: This setting introduces a significant
1000 1000 risk of losing the work you've done in a rebase if the rebase aborts
1001 1001 unexpectedly::
1002 1002
1003 1003 [rebase]
1004 1004 singletransaction = True
1005 1005
1006 1006 By default, rebase writes to the working copy, but you can configure it to
1007 1007 run in-memory for better performance. When the rebase is not moving the
1008 1008 parent(s) of the working copy (AKA the "currently checked out changesets"),
1009 1009 this may also allow it to run even if the working copy is dirty::
1010 1010
1011 1011 [rebase]
1012 1012 experimental.inmemory = True
1013 1013
1014 1014 Return Values:
1015 1015
1016 1016 Returns 0 on success, 1 if nothing to rebase or there are
1017 1017 unresolved conflicts.
1018 1018
1019 1019 """
1020 1020 opts = pycompat.byteskwargs(opts)
1021 1021 inmemory = ui.configbool(b'rebase', b'experimental.inmemory')
1022 1022 dryrun = opts.get(b'dry_run')
1023 1023 confirm = opts.get(b'confirm')
1024 1024 action = cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
1025 if dryrun and action:
1026 raise error.Abort(_(b'cannot specify both --dry-run and --%s') % action)
1027 if confirm and action:
1028 raise error.Abort(_(b'cannot specify both --confirm and --%s') % action)
1025 if action:
1026 cmdutil.check_incompatible_arguments(
1027 opts, action, b'confirm', b'dry_run'
1028 )
1029 1029 cmdutil.check_at_most_one_arg(opts, b'confirm', b'dry_run')
1030 1030
1031 1031 if action or repo.currenttransaction() is not None:
1032 1032 # in-memory rebase is not compatible with resuming rebases.
1033 1033 # (Or if it is run within a transaction, since the restart logic can
1034 1034 # fail the entire transaction.)
1035 1035 inmemory = False
1036 1036
1037 1037 if opts.get(b'auto_orphans'):
1038 1038 for key in opts:
1039 1039 if key != b'auto_orphans' and opts.get(key):
1040 1040 raise error.Abort(
1041 1041 _(b'--auto-orphans is incompatible with %s') % (b'--' + key)
1042 1042 )
1043 1043 userrevs = list(repo.revs(opts.get(b'auto_orphans')))
1044 1044 opts[b'rev'] = [revsetlang.formatspec(b'%ld and orphan()', userrevs)]
1045 1045 opts[b'dest'] = b'_destautoorphanrebase(SRC)'
1046 1046
1047 1047 if dryrun or confirm:
1048 1048 return _dryrunrebase(ui, repo, action, opts)
1049 1049 elif action == b'stop':
1050 1050 rbsrt = rebaseruntime(repo, ui)
1051 1051 with repo.wlock(), repo.lock():
1052 1052 rbsrt.restorestatus()
1053 1053 if rbsrt.collapsef:
1054 1054 raise error.Abort(_(b"cannot stop in --collapse session"))
1055 1055 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1056 1056 if not (rbsrt.keepf or allowunstable):
1057 1057 raise error.Abort(
1058 1058 _(
1059 1059 b"cannot remove original changesets with"
1060 1060 b" unrebased descendants"
1061 1061 ),
1062 1062 hint=_(
1063 1063 b'either enable obsmarkers to allow unstable '
1064 1064 b'revisions or use --keep to keep original '
1065 1065 b'changesets'
1066 1066 ),
1067 1067 )
1068 1068 if needupdate(repo, rbsrt.state):
1069 1069 # update to the current working revision
1070 1070 # to clear interrupted merge
1071 1071 hg.updaterepo(repo, rbsrt.originalwd, overwrite=True)
1072 1072 rbsrt._finishrebase()
1073 1073 return 0
1074 1074 elif inmemory:
1075 1075 try:
1076 1076 # in-memory merge doesn't support conflicts, so if we hit any, abort
1077 1077 # and re-run as an on-disk merge.
1078 1078 overrides = {(b'rebase', b'singletransaction'): True}
1079 1079 with ui.configoverride(overrides, b'rebase'):
1080 1080 return _dorebase(ui, repo, action, opts, inmemory=inmemory)
1081 1081 except error.InMemoryMergeConflictsError:
1082 1082 ui.warn(
1083 1083 _(
1084 1084 b'hit merge conflicts; re-running rebase without in-memory'
1085 1085 b' merge\n'
1086 1086 )
1087 1087 )
1088 1088 # TODO: Make in-memory merge not use the on-disk merge state, so
1089 1089 # we don't have to clean it here
1090 1090 mergemod.mergestate.clean(repo)
1091 1091 clearstatus(repo)
1092 1092 clearcollapsemsg(repo)
1093 1093 return _dorebase(ui, repo, action, opts, inmemory=False)
1094 1094 else:
1095 1095 return _dorebase(ui, repo, action, opts)
1096 1096
1097 1097
1098 1098 def _dryrunrebase(ui, repo, action, opts):
1099 1099 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
1100 1100 confirm = opts.get(b'confirm')
1101 1101 if confirm:
1102 1102 ui.status(_(b'starting in-memory rebase\n'))
1103 1103 else:
1104 1104 ui.status(
1105 1105 _(b'starting dry-run rebase; repository will not be changed\n')
1106 1106 )
1107 1107 with repo.wlock(), repo.lock():
1108 1108 needsabort = True
1109 1109 try:
1110 1110 overrides = {(b'rebase', b'singletransaction'): True}
1111 1111 with ui.configoverride(overrides, b'rebase'):
1112 1112 _origrebase(
1113 1113 ui,
1114 1114 repo,
1115 1115 action,
1116 1116 opts,
1117 1117 rbsrt,
1118 1118 inmemory=True,
1119 1119 leaveunfinished=True,
1120 1120 )
1121 1121 except error.InMemoryMergeConflictsError:
1122 1122 ui.status(_(b'hit a merge conflict\n'))
1123 1123 return 1
1124 1124 except error.Abort:
1125 1125 needsabort = False
1126 1126 raise
1127 1127 else:
1128 1128 if confirm:
1129 1129 ui.status(_(b'rebase completed successfully\n'))
1130 1130 if not ui.promptchoice(_(b'apply changes (yn)?$$ &Yes $$ &No')):
1131 1131 # finish unfinished rebase
1132 1132 rbsrt._finishrebase()
1133 1133 else:
1134 1134 rbsrt._prepareabortorcontinue(
1135 1135 isabort=True, backup=False, suppwarns=True
1136 1136 )
1137 1137 needsabort = False
1138 1138 else:
1139 1139 ui.status(
1140 1140 _(
1141 1141 b'dry-run rebase completed successfully; run without'
1142 1142 b' -n/--dry-run to perform this rebase\n'
1143 1143 )
1144 1144 )
1145 1145 return 0
1146 1146 finally:
1147 1147 if needsabort:
1148 1148 # no need to store backup in case of dryrun
1149 1149 rbsrt._prepareabortorcontinue(
1150 1150 isabort=True, backup=False, suppwarns=True
1151 1151 )
1152 1152
1153 1153
1154 1154 def _dorebase(ui, repo, action, opts, inmemory=False):
1155 1155 rbsrt = rebaseruntime(repo, ui, inmemory, opts)
1156 1156 return _origrebase(ui, repo, action, opts, rbsrt, inmemory=inmemory)
1157 1157
1158 1158
1159 1159 def _origrebase(
1160 1160 ui, repo, action, opts, rbsrt, inmemory=False, leaveunfinished=False
1161 1161 ):
1162 1162 assert action != b'stop'
1163 1163 with repo.wlock(), repo.lock():
1164 1164 # Validate input and define rebasing points
1165 1165 destf = opts.get(b'dest', None)
1166 1166 srcf = opts.get(b'source', None)
1167 1167 basef = opts.get(b'base', None)
1168 1168 revf = opts.get(b'rev', [])
1169 1169 # search default destination in this space
1170 1170 # used in the 'hg pull --rebase' case, see issue 5214.
1171 1171 destspace = opts.get(b'_destspace')
1172 1172 if opts.get(b'interactive'):
1173 1173 try:
1174 1174 if extensions.find(b'histedit'):
1175 1175 enablehistedit = b''
1176 1176 except KeyError:
1177 1177 enablehistedit = b" --config extensions.histedit="
1178 1178 help = b"hg%s help -e histedit" % enablehistedit
1179 1179 msg = (
1180 1180 _(
1181 1181 b"interactive history editing is supported by the "
1182 1182 b"'histedit' extension (see \"%s\")"
1183 1183 )
1184 1184 % help
1185 1185 )
1186 1186 raise error.Abort(msg)
1187 1187
1188 1188 if rbsrt.collapsemsg and not rbsrt.collapsef:
1189 1189 raise error.Abort(_(b'message can only be specified with collapse'))
1190 1190
1191 1191 if action:
1192 1192 if rbsrt.collapsef:
1193 1193 raise error.Abort(
1194 1194 _(b'cannot use collapse with continue or abort')
1195 1195 )
1196 1196 if srcf or basef or destf:
1197 1197 raise error.Abort(
1198 1198 _(b'abort and continue do not allow specifying revisions')
1199 1199 )
1200 1200 if action == b'abort' and opts.get(b'tool', False):
1201 1201 ui.warn(_(b'tool option will be ignored\n'))
1202 1202 if action == b'continue':
1203 1203 ms = mergemod.mergestate.read(repo)
1204 1204 mergeutil.checkunresolved(ms)
1205 1205
1206 1206 retcode = rbsrt._prepareabortorcontinue(
1207 1207 isabort=(action == b'abort')
1208 1208 )
1209 1209 if retcode is not None:
1210 1210 return retcode
1211 1211 else:
1212 1212 destmap = _definedestmap(
1213 1213 ui,
1214 1214 repo,
1215 1215 inmemory,
1216 1216 destf,
1217 1217 srcf,
1218 1218 basef,
1219 1219 revf,
1220 1220 destspace=destspace,
1221 1221 )
1222 1222 retcode = rbsrt._preparenewrebase(destmap)
1223 1223 if retcode is not None:
1224 1224 return retcode
1225 1225 storecollapsemsg(repo, rbsrt.collapsemsg)
1226 1226
1227 1227 tr = None
1228 1228
1229 1229 singletr = ui.configbool(b'rebase', b'singletransaction')
1230 1230 if singletr:
1231 1231 tr = repo.transaction(b'rebase')
1232 1232
1233 1233 # If `rebase.singletransaction` is enabled, wrap the entire operation in
1234 1234 # one transaction here. Otherwise, transactions are obtained when
1235 1235 # committing each node, which is slower but allows partial success.
1236 1236 with util.acceptintervention(tr):
1237 1237 # Same logic for the dirstate guard, except we don't create one when
1238 1238 # rebasing in-memory (it's not needed).
1239 1239 dsguard = None
1240 1240 if singletr and not inmemory:
1241 1241 dsguard = dirstateguard.dirstateguard(repo, b'rebase')
1242 1242 with util.acceptintervention(dsguard):
1243 1243 rbsrt._performrebase(tr)
1244 1244 if not leaveunfinished:
1245 1245 rbsrt._finishrebase()
1246 1246
1247 1247
1248 1248 def _definedestmap(
1249 1249 ui,
1250 1250 repo,
1251 1251 inmemory,
1252 1252 destf=None,
1253 1253 srcf=None,
1254 1254 basef=None,
1255 1255 revf=None,
1256 1256 destspace=None,
1257 1257 ):
1258 1258 """use revisions argument to define destmap {srcrev: destrev}"""
1259 1259 if revf is None:
1260 1260 revf = []
1261 1261
1262 1262 # destspace is here to work around issues with `hg pull --rebase` see
1263 1263 # issue5214 for details
1264 1264 if srcf and basef:
1265 1265 raise error.Abort(_(b'cannot specify both a source and a base'))
1266 1266 if revf and basef:
1267 1267 raise error.Abort(_(b'cannot specify both a revision and a base'))
1268 1268 if revf and srcf:
1269 1269 raise error.Abort(_(b'cannot specify both a revision and a source'))
1270 1270
1271 1271 cmdutil.checkunfinished(repo)
1272 1272 if not inmemory:
1273 1273 cmdutil.bailifchanged(repo)
1274 1274
1275 1275 if ui.configbool(b'commands', b'rebase.requiredest') and not destf:
1276 1276 raise error.Abort(
1277 1277 _(b'you must specify a destination'),
1278 1278 hint=_(b'use: hg rebase -d REV'),
1279 1279 )
1280 1280
1281 1281 dest = None
1282 1282
1283 1283 if revf:
1284 1284 rebaseset = scmutil.revrange(repo, revf)
1285 1285 if not rebaseset:
1286 1286 ui.status(_(b'empty "rev" revision set - nothing to rebase\n'))
1287 1287 return None
1288 1288 elif srcf:
1289 1289 src = scmutil.revrange(repo, [srcf])
1290 1290 if not src:
1291 1291 ui.status(_(b'empty "source" revision set - nothing to rebase\n'))
1292 1292 return None
1293 1293 rebaseset = repo.revs(b'(%ld)::', src)
1294 1294 assert rebaseset
1295 1295 else:
1296 1296 base = scmutil.revrange(repo, [basef or b'.'])
1297 1297 if not base:
1298 1298 ui.status(
1299 1299 _(b'empty "base" revision set - ' b"can't compute rebase set\n")
1300 1300 )
1301 1301 return None
1302 1302 if destf:
1303 1303 # --base does not support multiple destinations
1304 1304 dest = scmutil.revsingle(repo, destf)
1305 1305 else:
1306 1306 dest = repo[_destrebase(repo, base, destspace=destspace)]
1307 1307 destf = bytes(dest)
1308 1308
1309 1309 roots = [] # selected children of branching points
1310 1310 bpbase = {} # {branchingpoint: [origbase]}
1311 1311 for b in base: # group bases by branching points
1312 1312 bp = repo.revs(b'ancestor(%d, %d)', b, dest.rev()).first()
1313 1313 bpbase[bp] = bpbase.get(bp, []) + [b]
1314 1314 if None in bpbase:
1315 1315 # emulate the old behavior, showing "nothing to rebase" (a better
1316 1316 # behavior may be abort with "cannot find branching point" error)
1317 1317 bpbase.clear()
1318 1318 for bp, bs in pycompat.iteritems(bpbase): # calculate roots
1319 1319 roots += list(repo.revs(b'children(%d) & ancestors(%ld)', bp, bs))
1320 1320
1321 1321 rebaseset = repo.revs(b'%ld::', roots)
1322 1322
1323 1323 if not rebaseset:
1324 1324 # transform to list because smartsets are not comparable to
1325 1325 # lists. This should be improved to honor laziness of
1326 1326 # smartset.
1327 1327 if list(base) == [dest.rev()]:
1328 1328 if basef:
1329 1329 ui.status(
1330 1330 _(
1331 1331 b'nothing to rebase - %s is both "base"'
1332 1332 b' and destination\n'
1333 1333 )
1334 1334 % dest
1335 1335 )
1336 1336 else:
1337 1337 ui.status(
1338 1338 _(
1339 1339 b'nothing to rebase - working directory '
1340 1340 b'parent is also destination\n'
1341 1341 )
1342 1342 )
1343 1343 elif not repo.revs(b'%ld - ::%d', base, dest.rev()):
1344 1344 if basef:
1345 1345 ui.status(
1346 1346 _(
1347 1347 b'nothing to rebase - "base" %s is '
1348 1348 b'already an ancestor of destination '
1349 1349 b'%s\n'
1350 1350 )
1351 1351 % (b'+'.join(bytes(repo[r]) for r in base), dest)
1352 1352 )
1353 1353 else:
1354 1354 ui.status(
1355 1355 _(
1356 1356 b'nothing to rebase - working '
1357 1357 b'directory parent is already an '
1358 1358 b'ancestor of destination %s\n'
1359 1359 )
1360 1360 % dest
1361 1361 )
1362 1362 else: # can it happen?
1363 1363 ui.status(
1364 1364 _(b'nothing to rebase from %s to %s\n')
1365 1365 % (b'+'.join(bytes(repo[r]) for r in base), dest)
1366 1366 )
1367 1367 return None
1368 1368
1369 1369 rebasingwcp = repo[b'.'].rev() in rebaseset
1370 1370 ui.log(
1371 1371 b"rebase",
1372 1372 b"rebasing working copy parent: %r\n",
1373 1373 rebasingwcp,
1374 1374 rebase_rebasing_wcp=rebasingwcp,
1375 1375 )
1376 1376 if inmemory and rebasingwcp:
1377 1377 # Check these since we did not before.
1378 1378 cmdutil.checkunfinished(repo)
1379 1379 cmdutil.bailifchanged(repo)
1380 1380
1381 1381 if not destf:
1382 1382 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
1383 1383 destf = bytes(dest)
1384 1384
1385 1385 allsrc = revsetlang.formatspec(b'%ld', rebaseset)
1386 1386 alias = {b'ALLSRC': allsrc}
1387 1387
1388 1388 if dest is None:
1389 1389 try:
1390 1390 # fast path: try to resolve dest without SRC alias
1391 1391 dest = scmutil.revsingle(repo, destf, localalias=alias)
1392 1392 except error.RepoLookupError:
1393 1393 # multi-dest path: resolve dest for each SRC separately
1394 1394 destmap = {}
1395 1395 for r in rebaseset:
1396 1396 alias[b'SRC'] = revsetlang.formatspec(b'%d', r)
1397 1397 # use repo.anyrevs instead of scmutil.revsingle because we
1398 1398 # don't want to abort if destset is empty.
1399 1399 destset = repo.anyrevs([destf], user=True, localalias=alias)
1400 1400 size = len(destset)
1401 1401 if size == 1:
1402 1402 destmap[r] = destset.first()
1403 1403 elif size == 0:
1404 1404 ui.note(_(b'skipping %s - empty destination\n') % repo[r])
1405 1405 else:
1406 1406 raise error.Abort(
1407 1407 _(b'rebase destination for %s is not unique') % repo[r]
1408 1408 )
1409 1409
1410 1410 if dest is not None:
1411 1411 # single-dest case: assign dest to each rev in rebaseset
1412 1412 destrev = dest.rev()
1413 1413 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
1414 1414
1415 1415 if not destmap:
1416 1416 ui.status(_(b'nothing to rebase - empty destination\n'))
1417 1417 return None
1418 1418
1419 1419 return destmap
1420 1420
1421 1421
1422 1422 def externalparent(repo, state, destancestors):
1423 1423 """Return the revision that should be used as the second parent
1424 1424 when the revisions in state is collapsed on top of destancestors.
1425 1425 Abort if there is more than one parent.
1426 1426 """
1427 1427 parents = set()
1428 1428 source = min(state)
1429 1429 for rev in state:
1430 1430 if rev == source:
1431 1431 continue
1432 1432 for p in repo[rev].parents():
1433 1433 if p.rev() not in state and p.rev() not in destancestors:
1434 1434 parents.add(p.rev())
1435 1435 if not parents:
1436 1436 return nullrev
1437 1437 if len(parents) == 1:
1438 1438 return parents.pop()
1439 1439 raise error.Abort(
1440 1440 _(
1441 1441 b'unable to collapse on top of %d, there is more '
1442 1442 b'than one external parent: %s'
1443 1443 )
1444 1444 % (max(destancestors), b', '.join(b"%d" % p for p in sorted(parents)))
1445 1445 )
1446 1446
1447 1447
1448 1448 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg):
1449 1449 '''Commit the memory changes with parents p1 and p2.
1450 1450 Return node of committed revision.'''
1451 1451 # Replicates the empty check in ``repo.commit``.
1452 1452 if wctx.isempty() and not repo.ui.configbool(b'ui', b'allowemptycommit'):
1453 1453 return None
1454 1454
1455 1455 # By convention, ``extra['branch']`` (set by extrafn) clobbers
1456 1456 # ``branch`` (used when passing ``--keepbranches``).
1457 1457 branch = repo[p1].branch()
1458 1458 if b'branch' in extra:
1459 1459 branch = extra[b'branch']
1460 1460
1461 1461 memctx = wctx.tomemctx(
1462 1462 commitmsg,
1463 1463 parents=(p1, p2),
1464 1464 date=date,
1465 1465 extra=extra,
1466 1466 user=user,
1467 1467 branch=branch,
1468 1468 editor=editor,
1469 1469 )
1470 1470 commitres = repo.commitctx(memctx)
1471 1471 wctx.clean() # Might be reused
1472 1472 return commitres
1473 1473
1474 1474
1475 1475 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg):
1476 1476 '''Commit the wd changes with parents p1 and p2.
1477 1477 Return node of committed revision.'''
1478 1478 dsguard = util.nullcontextmanager()
1479 1479 if not repo.ui.configbool(b'rebase', b'singletransaction'):
1480 1480 dsguard = dirstateguard.dirstateguard(repo, b'rebase')
1481 1481 with dsguard:
1482 1482 repo.setparents(repo[p1].node(), repo[p2].node())
1483 1483
1484 1484 # Commit might fail if unresolved files exist
1485 1485 newnode = repo.commit(
1486 1486 text=commitmsg, user=user, date=date, extra=extra, editor=editor
1487 1487 )
1488 1488
1489 1489 repo.dirstate.setbranch(repo[newnode].branch())
1490 1490 return newnode
1491 1491
1492 1492
1493 1493 def rebasenode(repo, rev, p1, base, collapse, dest, wctx):
1494 1494 """Rebase a single revision rev on top of p1 using base as merge ancestor"""
1495 1495 # Merge phase
1496 1496 # Update to destination and merge it with local
1497 1497 if wctx.isinmemory():
1498 1498 wctx.setbase(repo[p1])
1499 1499 else:
1500 1500 if repo[b'.'].rev() != p1:
1501 1501 repo.ui.debug(b" update to %d:%s\n" % (p1, repo[p1]))
1502 1502 mergemod.update(repo, p1, branchmerge=False, force=True)
1503 1503 else:
1504 1504 repo.ui.debug(b" already in destination\n")
1505 1505 # This is, alas, necessary to invalidate workingctx's manifest cache,
1506 1506 # as well as other data we litter on it in other places.
1507 1507 wctx = repo[None]
1508 1508 repo.dirstate.write(repo.currenttransaction())
1509 1509 repo.ui.debug(b" merge against %d:%s\n" % (rev, repo[rev]))
1510 1510 if base is not None:
1511 1511 repo.ui.debug(b" detach base %d:%s\n" % (base, repo[base]))
1512 1512 # When collapsing in-place, the parent is the common ancestor, we
1513 1513 # have to allow merging with it.
1514 1514 stats = mergemod.update(
1515 1515 repo,
1516 1516 rev,
1517 1517 branchmerge=True,
1518 1518 force=True,
1519 1519 ancestor=base,
1520 1520 mergeancestor=collapse,
1521 1521 labels=[b'dest', b'source'],
1522 1522 wc=wctx,
1523 1523 )
1524 1524 if collapse:
1525 1525 copies.duplicatecopies(repo, wctx, rev, dest)
1526 1526 else:
1527 1527 # If we're not using --collapse, we need to
1528 1528 # duplicate copies between the revision we're
1529 1529 # rebasing and its first parent, but *not*
1530 1530 # duplicate any copies that have already been
1531 1531 # performed in the destination.
1532 1532 p1rev = repo[rev].p1().rev()
1533 1533 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
1534 1534 return stats
1535 1535
1536 1536
1537 1537 def adjustdest(repo, rev, destmap, state, skipped):
1538 1538 r"""adjust rebase destination given the current rebase state
1539 1539
1540 1540 rev is what is being rebased. Return a list of two revs, which are the
1541 1541 adjusted destinations for rev's p1 and p2, respectively. If a parent is
1542 1542 nullrev, return dest without adjustment for it.
1543 1543
1544 1544 For example, when doing rebasing B+E to F, C to G, rebase will first move B
1545 1545 to B1, and E's destination will be adjusted from F to B1.
1546 1546
1547 1547 B1 <- written during rebasing B
1548 1548 |
1549 1549 F <- original destination of B, E
1550 1550 |
1551 1551 | E <- rev, which is being rebased
1552 1552 | |
1553 1553 | D <- prev, one parent of rev being checked
1554 1554 | |
1555 1555 | x <- skipped, ex. no successor or successor in (::dest)
1556 1556 | |
1557 1557 | C <- rebased as C', different destination
1558 1558 | |
1559 1559 | B <- rebased as B1 C'
1560 1560 |/ |
1561 1561 A G <- destination of C, different
1562 1562
1563 1563 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
1564 1564 first move C to C1, G to G1, and when it's checking H, the adjusted
1565 1565 destinations will be [C1, G1].
1566 1566
1567 1567 H C1 G1
1568 1568 /| | /
1569 1569 F G |/
1570 1570 K | | -> K
1571 1571 | C D |
1572 1572 | |/ |
1573 1573 | B | ...
1574 1574 |/ |/
1575 1575 A A
1576 1576
1577 1577 Besides, adjust dest according to existing rebase information. For example,
1578 1578
1579 1579 B C D B needs to be rebased on top of C, C needs to be rebased on top
1580 1580 \|/ of D. We will rebase C first.
1581 1581 A
1582 1582
1583 1583 C' After rebasing C, when considering B's destination, use C'
1584 1584 | instead of the original C.
1585 1585 B D
1586 1586 \ /
1587 1587 A
1588 1588 """
1589 1589 # pick already rebased revs with same dest from state as interesting source
1590 1590 dest = destmap[rev]
1591 1591 source = [
1592 1592 s
1593 1593 for s, d in state.items()
1594 1594 if d > 0 and destmap[s] == dest and s not in skipped
1595 1595 ]
1596 1596
1597 1597 result = []
1598 1598 for prev in repo.changelog.parentrevs(rev):
1599 1599 adjusted = dest
1600 1600 if prev != nullrev:
1601 1601 candidate = repo.revs(b'max(%ld and (::%d))', source, prev).first()
1602 1602 if candidate is not None:
1603 1603 adjusted = state[candidate]
1604 1604 if adjusted == dest and dest in state:
1605 1605 adjusted = state[dest]
1606 1606 if adjusted == revtodo:
1607 1607 # sortsource should produce an order that makes this impossible
1608 1608 raise error.ProgrammingError(
1609 1609 b'rev %d should be rebased already at this time' % dest
1610 1610 )
1611 1611 result.append(adjusted)
1612 1612 return result
1613 1613
1614 1614
1615 1615 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1616 1616 """
1617 1617 Abort if rebase will create divergence or rebase is noop because of markers
1618 1618
1619 1619 `rebaseobsrevs`: set of obsolete revision in source
1620 1620 `rebaseobsskipped`: set of revisions from source skipped because they have
1621 1621 successors in destination or no non-obsolete successor.
1622 1622 """
1623 1623 # Obsolete node with successors not in dest leads to divergence
1624 1624 divergenceok = ui.configbool(b'experimental', b'evolution.allowdivergence')
1625 1625 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1626 1626
1627 1627 if divergencebasecandidates and not divergenceok:
1628 1628 divhashes = (bytes(repo[r]) for r in divergencebasecandidates)
1629 1629 msg = _(b"this rebase will cause divergences from: %s")
1630 1630 h = _(
1631 1631 b"to force the rebase please set "
1632 1632 b"experimental.evolution.allowdivergence=True"
1633 1633 )
1634 1634 raise error.Abort(msg % (b",".join(divhashes),), hint=h)
1635 1635
1636 1636
1637 1637 def successorrevs(unfi, rev):
1638 1638 """yield revision numbers for successors of rev"""
1639 1639 assert unfi.filtername is None
1640 1640 get_rev = unfi.changelog.index.get_rev
1641 1641 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1642 1642 r = get_rev(s)
1643 1643 if r is not None:
1644 1644 yield r
1645 1645
1646 1646
1647 1647 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1648 1648 """Return new parents and optionally a merge base for rev being rebased
1649 1649
1650 1650 The destination specified by "dest" cannot always be used directly because
1651 1651 previously rebase result could affect destination. For example,
1652 1652
1653 1653 D E rebase -r C+D+E -d B
1654 1654 |/ C will be rebased to C'
1655 1655 B C D's new destination will be C' instead of B
1656 1656 |/ E's new destination will be C' instead of B
1657 1657 A
1658 1658
1659 1659 The new parents of a merge is slightly more complicated. See the comment
1660 1660 block below.
1661 1661 """
1662 1662 # use unfiltered changelog since successorrevs may return filtered nodes
1663 1663 assert repo.filtername is None
1664 1664 cl = repo.changelog
1665 1665 isancestor = cl.isancestorrev
1666 1666
1667 1667 dest = destmap[rev]
1668 1668 oldps = repo.changelog.parentrevs(rev) # old parents
1669 1669 newps = [nullrev, nullrev] # new parents
1670 1670 dests = adjustdest(repo, rev, destmap, state, skipped)
1671 1671 bases = list(oldps) # merge base candidates, initially just old parents
1672 1672
1673 1673 if all(r == nullrev for r in oldps[1:]):
1674 1674 # For non-merge changeset, just move p to adjusted dest as requested.
1675 1675 newps[0] = dests[0]
1676 1676 else:
1677 1677 # For merge changeset, if we move p to dests[i] unconditionally, both
1678 1678 # parents may change and the end result looks like "the merge loses a
1679 1679 # parent", which is a surprise. This is a limit because "--dest" only
1680 1680 # accepts one dest per src.
1681 1681 #
1682 1682 # Therefore, only move p with reasonable conditions (in this order):
1683 1683 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1684 1684 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1685 1685 #
1686 1686 # Comparing with adjustdest, the logic here does some additional work:
1687 1687 # 1. decide which parents will not be moved towards dest
1688 1688 # 2. if the above decision is "no", should a parent still be moved
1689 1689 # because it was rebased?
1690 1690 #
1691 1691 # For example:
1692 1692 #
1693 1693 # C # "rebase -r C -d D" is an error since none of the parents
1694 1694 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1695 1695 # A B D # B (using rule "2."), since B will be rebased.
1696 1696 #
1697 1697 # The loop tries to be not rely on the fact that a Mercurial node has
1698 1698 # at most 2 parents.
1699 1699 for i, p in enumerate(oldps):
1700 1700 np = p # new parent
1701 1701 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1702 1702 np = dests[i]
1703 1703 elif p in state and state[p] > 0:
1704 1704 np = state[p]
1705 1705
1706 1706 # "bases" only record "special" merge bases that cannot be
1707 1707 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1708 1708 # For example:
1709 1709 #
1710 1710 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1711 1711 # | C # is B', but merge base for C is B, instead of
1712 1712 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1713 1713 # | B # "state" edges are merged (so there will be an edge from
1714 1714 # |/ # B to B'), the merge base is still ancestor(C, B') in
1715 1715 # A # the merged graph.
1716 1716 #
1717 1717 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1718 1718 # which uses "virtual null merge" to explain this situation.
1719 1719 if isancestor(p, np):
1720 1720 bases[i] = nullrev
1721 1721
1722 1722 # If one parent becomes an ancestor of the other, drop the ancestor
1723 1723 for j, x in enumerate(newps[:i]):
1724 1724 if x == nullrev:
1725 1725 continue
1726 1726 if isancestor(np, x): # CASE-1
1727 1727 np = nullrev
1728 1728 elif isancestor(x, np): # CASE-2
1729 1729 newps[j] = np
1730 1730 np = nullrev
1731 1731 # New parents forming an ancestor relationship does not
1732 1732 # mean the old parents have a similar relationship. Do not
1733 1733 # set bases[x] to nullrev.
1734 1734 bases[j], bases[i] = bases[i], bases[j]
1735 1735
1736 1736 newps[i] = np
1737 1737
1738 1738 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1739 1739 # base. If only p2 changes, merging using unchanged p1 as merge base is
1740 1740 # suboptimal. Therefore swap parents to make the merge sane.
1741 1741 if newps[1] != nullrev and oldps[0] == newps[0]:
1742 1742 assert len(newps) == 2 and len(oldps) == 2
1743 1743 newps.reverse()
1744 1744 bases.reverse()
1745 1745
1746 1746 # No parent change might be an error because we fail to make rev a
1747 1747 # descendent of requested dest. This can happen, for example:
1748 1748 #
1749 1749 # C # rebase -r C -d D
1750 1750 # /| # None of A and B will be changed to D and rebase fails.
1751 1751 # A B D
1752 1752 if set(newps) == set(oldps) and dest not in newps:
1753 1753 raise error.Abort(
1754 1754 _(
1755 1755 b'cannot rebase %d:%s without '
1756 1756 b'moving at least one of its parents'
1757 1757 )
1758 1758 % (rev, repo[rev])
1759 1759 )
1760 1760
1761 1761 # Source should not be ancestor of dest. The check here guarantees it's
1762 1762 # impossible. With multi-dest, the initial check does not cover complex
1763 1763 # cases since we don't have abstractions to dry-run rebase cheaply.
1764 1764 if any(p != nullrev and isancestor(rev, p) for p in newps):
1765 1765 raise error.Abort(_(b'source is ancestor of destination'))
1766 1766
1767 1767 # "rebasenode" updates to new p1, use the corresponding merge base.
1768 1768 if bases[0] != nullrev:
1769 1769 base = bases[0]
1770 1770 else:
1771 1771 base = None
1772 1772
1773 1773 # Check if the merge will contain unwanted changes. That may happen if
1774 1774 # there are multiple special (non-changelog ancestor) merge bases, which
1775 1775 # cannot be handled well by the 3-way merge algorithm. For example:
1776 1776 #
1777 1777 # F
1778 1778 # /|
1779 1779 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1780 1780 # | | # as merge base, the difference between D and F will include
1781 1781 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1782 1782 # |/ # chosen, the rebased F will contain B.
1783 1783 # A Z
1784 1784 #
1785 1785 # But our merge base candidates (D and E in above case) could still be
1786 1786 # better than the default (ancestor(F, Z) == null). Therefore still
1787 1787 # pick one (so choose p1 above).
1788 1788 if sum(1 for b in set(bases) if b != nullrev) > 1:
1789 1789 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1790 1790 for i, base in enumerate(bases):
1791 1791 if base == nullrev:
1792 1792 continue
1793 1793 # Revisions in the side (not chosen as merge base) branch that
1794 1794 # might contain "surprising" contents
1795 1795 siderevs = list(
1796 1796 repo.revs(b'((%ld-%d) %% (%d+%d))', bases, base, base, dest)
1797 1797 )
1798 1798
1799 1799 # If those revisions are covered by rebaseset, the result is good.
1800 1800 # A merge in rebaseset would be considered to cover its ancestors.
1801 1801 if siderevs:
1802 1802 rebaseset = [
1803 1803 r for r, d in state.items() if d > 0 and r not in obsskipped
1804 1804 ]
1805 1805 merges = [
1806 1806 r for r in rebaseset if cl.parentrevs(r)[1] != nullrev
1807 1807 ]
1808 1808 unwanted[i] = list(
1809 1809 repo.revs(
1810 1810 b'%ld - (::%ld) - %ld', siderevs, merges, rebaseset
1811 1811 )
1812 1812 )
1813 1813
1814 1814 # Choose a merge base that has a minimal number of unwanted revs.
1815 1815 l, i = min(
1816 1816 (len(revs), i)
1817 1817 for i, revs in enumerate(unwanted)
1818 1818 if revs is not None
1819 1819 )
1820 1820 base = bases[i]
1821 1821
1822 1822 # newps[0] should match merge base if possible. Currently, if newps[i]
1823 1823 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1824 1824 # the other's ancestor. In that case, it's fine to not swap newps here.
1825 1825 # (see CASE-1 and CASE-2 above)
1826 1826 if i != 0 and newps[i] != nullrev:
1827 1827 newps[0], newps[i] = newps[i], newps[0]
1828 1828
1829 1829 # The merge will include unwanted revisions. Abort now. Revisit this if
1830 1830 # we have a more advanced merge algorithm that handles multiple bases.
1831 1831 if l > 0:
1832 1832 unwanteddesc = _(b' or ').join(
1833 1833 (
1834 1834 b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
1835 1835 for revs in unwanted
1836 1836 if revs is not None
1837 1837 )
1838 1838 )
1839 1839 raise error.Abort(
1840 1840 _(b'rebasing %d:%s will include unwanted changes from %s')
1841 1841 % (rev, repo[rev], unwanteddesc)
1842 1842 )
1843 1843
1844 1844 repo.ui.debug(b" future parents are %d and %d\n" % tuple(newps))
1845 1845
1846 1846 return newps[0], newps[1], base
1847 1847
1848 1848
1849 1849 def isagitpatch(repo, patchname):
1850 1850 """Return true if the given patch is in git format"""
1851 1851 mqpatch = os.path.join(repo.mq.path, patchname)
1852 1852 for line in patch.linereader(open(mqpatch, b'rb')):
1853 1853 if line.startswith(b'diff --git'):
1854 1854 return True
1855 1855 return False
1856 1856
1857 1857
1858 1858 def updatemq(repo, state, skipped, **opts):
1859 1859 """Update rebased mq patches - finalize and then import them"""
1860 1860 mqrebase = {}
1861 1861 mq = repo.mq
1862 1862 original_series = mq.fullseries[:]
1863 1863 skippedpatches = set()
1864 1864
1865 1865 for p in mq.applied:
1866 1866 rev = repo[p.node].rev()
1867 1867 if rev in state:
1868 1868 repo.ui.debug(
1869 1869 b'revision %d is an mq patch (%s), finalize it.\n'
1870 1870 % (rev, p.name)
1871 1871 )
1872 1872 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1873 1873 else:
1874 1874 # Applied but not rebased, not sure this should happen
1875 1875 skippedpatches.add(p.name)
1876 1876
1877 1877 if mqrebase:
1878 1878 mq.finish(repo, mqrebase.keys())
1879 1879
1880 1880 # We must start import from the newest revision
1881 1881 for rev in sorted(mqrebase, reverse=True):
1882 1882 if rev not in skipped:
1883 1883 name, isgit = mqrebase[rev]
1884 1884 repo.ui.note(
1885 1885 _(b'updating mq patch %s to %d:%s\n')
1886 1886 % (name, state[rev], repo[state[rev]])
1887 1887 )
1888 1888 mq.qimport(
1889 1889 repo,
1890 1890 (),
1891 1891 patchname=name,
1892 1892 git=isgit,
1893 1893 rev=[b"%d" % state[rev]],
1894 1894 )
1895 1895 else:
1896 1896 # Rebased and skipped
1897 1897 skippedpatches.add(mqrebase[rev][0])
1898 1898
1899 1899 # Patches were either applied and rebased and imported in
1900 1900 # order, applied and removed or unapplied. Discard the removed
1901 1901 # ones while preserving the original series order and guards.
1902 1902 newseries = [
1903 1903 s
1904 1904 for s in original_series
1905 1905 if mq.guard_re.split(s, 1)[0] not in skippedpatches
1906 1906 ]
1907 1907 mq.fullseries[:] = newseries
1908 1908 mq.seriesdirty = True
1909 1909 mq.savedirty()
1910 1910
1911 1911
1912 1912 def storecollapsemsg(repo, collapsemsg):
1913 1913 """Store the collapse message to allow recovery"""
1914 1914 collapsemsg = collapsemsg or b''
1915 1915 f = repo.vfs(b"last-message.txt", b"w")
1916 1916 f.write(b"%s\n" % collapsemsg)
1917 1917 f.close()
1918 1918
1919 1919
1920 1920 def clearcollapsemsg(repo):
1921 1921 """Remove collapse message file"""
1922 1922 repo.vfs.unlinkpath(b"last-message.txt", ignoremissing=True)
1923 1923
1924 1924
1925 1925 def restorecollapsemsg(repo, isabort):
1926 1926 """Restore previously stored collapse message"""
1927 1927 try:
1928 1928 f = repo.vfs(b"last-message.txt")
1929 1929 collapsemsg = f.readline().strip()
1930 1930 f.close()
1931 1931 except IOError as err:
1932 1932 if err.errno != errno.ENOENT:
1933 1933 raise
1934 1934 if isabort:
1935 1935 # Oh well, just abort like normal
1936 1936 collapsemsg = b''
1937 1937 else:
1938 1938 raise error.Abort(_(b'missing .hg/last-message.txt for rebase'))
1939 1939 return collapsemsg
1940 1940
1941 1941
1942 1942 def clearstatus(repo):
1943 1943 """Remove the status files"""
1944 1944 # Make sure the active transaction won't write the state file
1945 1945 tr = repo.currenttransaction()
1946 1946 if tr:
1947 1947 tr.removefilegenerator(b'rebasestate')
1948 1948 repo.vfs.unlinkpath(b"rebasestate", ignoremissing=True)
1949 1949
1950 1950
1951 1951 def needupdate(repo, state):
1952 1952 '''check whether we should `update --clean` away from a merge, or if
1953 1953 somehow the working dir got forcibly updated, e.g. by older hg'''
1954 1954 parents = [p.rev() for p in repo[None].parents()]
1955 1955
1956 1956 # Are we in a merge state at all?
1957 1957 if len(parents) < 2:
1958 1958 return False
1959 1959
1960 1960 # We should be standing on the first as-of-yet unrebased commit.
1961 1961 firstunrebased = min(
1962 1962 [old for old, new in pycompat.iteritems(state) if new == nullrev]
1963 1963 )
1964 1964 if firstunrebased in parents:
1965 1965 return True
1966 1966
1967 1967 return False
1968 1968
1969 1969
1970 1970 def sortsource(destmap):
1971 1971 """yield source revisions in an order that we only rebase things once
1972 1972
1973 1973 If source and destination overlaps, we should filter out revisions
1974 1974 depending on other revisions which hasn't been rebased yet.
1975 1975
1976 1976 Yield a sorted list of revisions each time.
1977 1977
1978 1978 For example, when rebasing A to B, B to C. This function yields [B], then
1979 1979 [A], indicating B needs to be rebased first.
1980 1980
1981 1981 Raise if there is a cycle so the rebase is impossible.
1982 1982 """
1983 1983 srcset = set(destmap)
1984 1984 while srcset:
1985 1985 srclist = sorted(srcset)
1986 1986 result = []
1987 1987 for r in srclist:
1988 1988 if destmap[r] not in srcset:
1989 1989 result.append(r)
1990 1990 if not result:
1991 1991 raise error.Abort(_(b'source and destination form a cycle'))
1992 1992 srcset -= set(result)
1993 1993 yield result
1994 1994
1995 1995
1996 1996 def buildstate(repo, destmap, collapse):
1997 1997 '''Define which revisions are going to be rebased and where
1998 1998
1999 1999 repo: repo
2000 2000 destmap: {srcrev: destrev}
2001 2001 '''
2002 2002 rebaseset = destmap.keys()
2003 2003 originalwd = repo[b'.'].rev()
2004 2004
2005 2005 # This check isn't strictly necessary, since mq detects commits over an
2006 2006 # applied patch. But it prevents messing up the working directory when
2007 2007 # a partially completed rebase is blocked by mq.
2008 2008 if b'qtip' in repo.tags():
2009 2009 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
2010 2010 if set(destmap.values()) & mqapplied:
2011 2011 raise error.Abort(_(b'cannot rebase onto an applied mq patch'))
2012 2012
2013 2013 # Get "cycle" error early by exhausting the generator.
2014 2014 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
2015 2015 if not sortedsrc:
2016 2016 raise error.Abort(_(b'no matching revisions'))
2017 2017
2018 2018 # Only check the first batch of revisions to rebase not depending on other
2019 2019 # rebaseset. This means "source is ancestor of destination" for the second
2020 2020 # (and following) batches of revisions are not checked here. We rely on
2021 2021 # "defineparents" to do that check.
2022 2022 roots = list(repo.set(b'roots(%ld)', sortedsrc[0]))
2023 2023 if not roots:
2024 2024 raise error.Abort(_(b'no matching revisions'))
2025 2025
2026 2026 def revof(r):
2027 2027 return r.rev()
2028 2028
2029 2029 roots = sorted(roots, key=revof)
2030 2030 state = dict.fromkeys(rebaseset, revtodo)
2031 2031 emptyrebase = len(sortedsrc) == 1
2032 2032 for root in roots:
2033 2033 dest = repo[destmap[root.rev()]]
2034 2034 commonbase = root.ancestor(dest)
2035 2035 if commonbase == root:
2036 2036 raise error.Abort(_(b'source is ancestor of destination'))
2037 2037 if commonbase == dest:
2038 2038 wctx = repo[None]
2039 2039 if dest == wctx.p1():
2040 2040 # when rebasing to '.', it will use the current wd branch name
2041 2041 samebranch = root.branch() == wctx.branch()
2042 2042 else:
2043 2043 samebranch = root.branch() == dest.branch()
2044 2044 if not collapse and samebranch and dest in root.parents():
2045 2045 # mark the revision as done by setting its new revision
2046 2046 # equal to its old (current) revisions
2047 2047 state[root.rev()] = root.rev()
2048 2048 repo.ui.debug(b'source is a child of destination\n')
2049 2049 continue
2050 2050
2051 2051 emptyrebase = False
2052 2052 repo.ui.debug(b'rebase onto %s starting from %s\n' % (dest, root))
2053 2053 if emptyrebase:
2054 2054 return None
2055 2055 for rev in sorted(state):
2056 2056 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
2057 2057 # if all parents of this revision are done, then so is this revision
2058 2058 if parents and all((state.get(p) == p for p in parents)):
2059 2059 state[rev] = rev
2060 2060 return originalwd, destmap, state
2061 2061
2062 2062
2063 2063 def clearrebased(
2064 2064 ui,
2065 2065 repo,
2066 2066 destmap,
2067 2067 state,
2068 2068 skipped,
2069 2069 collapsedas=None,
2070 2070 keepf=False,
2071 2071 fm=None,
2072 2072 backup=True,
2073 2073 ):
2074 2074 """dispose of rebased revision at the end of the rebase
2075 2075
2076 2076 If `collapsedas` is not None, the rebase was a collapse whose result if the
2077 2077 `collapsedas` node.
2078 2078
2079 2079 If `keepf` is not True, the rebase has --keep set and no nodes should be
2080 2080 removed (but bookmarks still need to be moved).
2081 2081
2082 2082 If `backup` is False, no backup will be stored when stripping rebased
2083 2083 revisions.
2084 2084 """
2085 2085 tonode = repo.changelog.node
2086 2086 replacements = {}
2087 2087 moves = {}
2088 2088 stripcleanup = not obsolete.isenabled(repo, obsolete.createmarkersopt)
2089 2089
2090 2090 collapsednodes = []
2091 2091 for rev, newrev in sorted(state.items()):
2092 2092 if newrev >= 0 and newrev != rev:
2093 2093 oldnode = tonode(rev)
2094 2094 newnode = collapsedas or tonode(newrev)
2095 2095 moves[oldnode] = newnode
2096 2096 succs = None
2097 2097 if rev in skipped:
2098 2098 if stripcleanup or not repo[rev].obsolete():
2099 2099 succs = ()
2100 2100 elif collapsedas:
2101 2101 collapsednodes.append(oldnode)
2102 2102 else:
2103 2103 succs = (newnode,)
2104 2104 if succs is not None:
2105 2105 replacements[(oldnode,)] = succs
2106 2106 if collapsednodes:
2107 2107 replacements[tuple(collapsednodes)] = (collapsedas,)
2108 2108 if fm:
2109 2109 hf = fm.hexfunc
2110 2110 fl = fm.formatlist
2111 2111 fd = fm.formatdict
2112 2112 changes = {}
2113 2113 for oldns, newn in pycompat.iteritems(replacements):
2114 2114 for oldn in oldns:
2115 2115 changes[hf(oldn)] = fl([hf(n) for n in newn], name=b'node')
2116 2116 nodechanges = fd(changes, key=b"oldnode", value=b"newnodes")
2117 2117 fm.data(nodechanges=nodechanges)
2118 2118 if keepf:
2119 2119 replacements = {}
2120 2120 scmutil.cleanupnodes(repo, replacements, b'rebase', moves, backup=backup)
2121 2121
2122 2122
2123 2123 def pullrebase(orig, ui, repo, *args, **opts):
2124 2124 """Call rebase after pull if the latter has been invoked with --rebase"""
2125 2125 if opts.get('rebase'):
2126 2126 if ui.configbool(b'commands', b'rebase.requiredest'):
2127 2127 msg = _(b'rebase destination required by configuration')
2128 2128 hint = _(b'use hg pull followed by hg rebase -d DEST')
2129 2129 raise error.Abort(msg, hint=hint)
2130 2130
2131 2131 with repo.wlock(), repo.lock():
2132 2132 if opts.get('update'):
2133 2133 del opts['update']
2134 2134 ui.debug(
2135 2135 b'--update and --rebase are not compatible, ignoring '
2136 2136 b'the update flag\n'
2137 2137 )
2138 2138
2139 2139 cmdutil.checkunfinished(repo, skipmerge=True)
2140 2140 cmdutil.bailifchanged(
2141 2141 repo,
2142 2142 hint=_(
2143 2143 b'cannot pull with rebase: '
2144 2144 b'please commit or shelve your changes first'
2145 2145 ),
2146 2146 )
2147 2147
2148 2148 revsprepull = len(repo)
2149 2149 origpostincoming = commands.postincoming
2150 2150
2151 2151 def _dummy(*args, **kwargs):
2152 2152 pass
2153 2153
2154 2154 commands.postincoming = _dummy
2155 2155 try:
2156 2156 ret = orig(ui, repo, *args, **opts)
2157 2157 finally:
2158 2158 commands.postincoming = origpostincoming
2159 2159 revspostpull = len(repo)
2160 2160 if revspostpull > revsprepull:
2161 2161 # --rev option from pull conflict with rebase own --rev
2162 2162 # dropping it
2163 2163 if 'rev' in opts:
2164 2164 del opts['rev']
2165 2165 # positional argument from pull conflicts with rebase's own
2166 2166 # --source.
2167 2167 if 'source' in opts:
2168 2168 del opts['source']
2169 2169 # revsprepull is the len of the repo, not revnum of tip.
2170 2170 destspace = list(repo.changelog.revs(start=revsprepull))
2171 2171 opts['_destspace'] = destspace
2172 2172 try:
2173 2173 rebase(ui, repo, **opts)
2174 2174 except error.NoMergeDestAbort:
2175 2175 # we can maybe update instead
2176 2176 rev, _a, _b = destutil.destupdate(repo)
2177 2177 if rev == repo[b'.'].rev():
2178 2178 ui.status(_(b'nothing to rebase\n'))
2179 2179 else:
2180 2180 ui.status(_(b'nothing to rebase - updating instead\n'))
2181 2181 # not passing argument to get the bare update behavior
2182 2182 # with warning and trumpets
2183 2183 commands.update(ui, repo)
2184 2184 else:
2185 2185 if opts.get('tool'):
2186 2186 raise error.Abort(_(b'--tool can only be used with --rebase'))
2187 2187 ret = orig(ui, repo, *args, **opts)
2188 2188
2189 2189 return ret
2190 2190
2191 2191
2192 2192 def _filterobsoleterevs(repo, revs):
2193 2193 """returns a set of the obsolete revisions in revs"""
2194 2194 return set(r for r in revs if repo[r].obsolete())
2195 2195
2196 2196
2197 2197 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
2198 2198 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination).
2199 2199
2200 2200 `obsoletenotrebased` is a mapping mapping obsolete => successor for all
2201 2201 obsolete nodes to be rebased given in `rebaseobsrevs`.
2202 2202
2203 2203 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions
2204 2204 without a successor in destination.
2205 2205
2206 2206 `obsoleteextinctsuccessors` is a set of obsolete revisions with only
2207 2207 obsolete successors.
2208 2208 """
2209 2209 obsoletenotrebased = {}
2210 2210 obsoletewithoutsuccessorindestination = set()
2211 2211 obsoleteextinctsuccessors = set()
2212 2212
2213 2213 assert repo.filtername is None
2214 2214 cl = repo.changelog
2215 2215 get_rev = cl.index.get_rev
2216 2216 extinctrevs = set(repo.revs(b'extinct()'))
2217 2217 for srcrev in rebaseobsrevs:
2218 2218 srcnode = cl.node(srcrev)
2219 2219 # XXX: more advanced APIs are required to handle split correctly
2220 2220 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode]))
2221 2221 # obsutil.allsuccessors includes node itself
2222 2222 successors.remove(srcnode)
2223 2223 succrevs = {get_rev(s) for s in successors}
2224 2224 succrevs.discard(None)
2225 2225 if succrevs.issubset(extinctrevs):
2226 2226 # all successors are extinct
2227 2227 obsoleteextinctsuccessors.add(srcrev)
2228 2228 if not successors:
2229 2229 # no successor
2230 2230 obsoletenotrebased[srcrev] = None
2231 2231 else:
2232 2232 dstrev = destmap[srcrev]
2233 2233 for succrev in succrevs:
2234 2234 if cl.isancestorrev(succrev, dstrev):
2235 2235 obsoletenotrebased[srcrev] = succrev
2236 2236 break
2237 2237 else:
2238 2238 # If 'srcrev' has a successor in rebase set but none in
2239 2239 # destination (which would be catched above), we shall skip it
2240 2240 # and its descendants to avoid divergence.
2241 2241 if srcrev in extinctrevs or any(s in destmap for s in succrevs):
2242 2242 obsoletewithoutsuccessorindestination.add(srcrev)
2243 2243
2244 2244 return (
2245 2245 obsoletenotrebased,
2246 2246 obsoletewithoutsuccessorindestination,
2247 2247 obsoleteextinctsuccessors,
2248 2248 )
2249 2249
2250 2250
2251 2251 def abortrebase(ui, repo):
2252 2252 with repo.wlock(), repo.lock():
2253 2253 rbsrt = rebaseruntime(repo, ui)
2254 2254 rbsrt._prepareabortorcontinue(isabort=True)
2255 2255
2256 2256
2257 2257 def continuerebase(ui, repo):
2258 2258 with repo.wlock(), repo.lock():
2259 2259 rbsrt = rebaseruntime(repo, ui)
2260 2260 ms = mergemod.mergestate.read(repo)
2261 2261 mergeutil.checkunresolved(ms)
2262 2262 retcode = rbsrt._prepareabortorcontinue(isabort=False)
2263 2263 if retcode is not None:
2264 2264 return retcode
2265 2265 rbsrt._performrebase(None)
2266 2266 rbsrt._finishrebase()
2267 2267
2268 2268
2269 2269 def summaryhook(ui, repo):
2270 2270 if not repo.vfs.exists(b'rebasestate'):
2271 2271 return
2272 2272 try:
2273 2273 rbsrt = rebaseruntime(repo, ui, {})
2274 2274 rbsrt.restorestatus()
2275 2275 state = rbsrt.state
2276 2276 except error.RepoLookupError:
2277 2277 # i18n: column positioning for "hg summary"
2278 2278 msg = _(b'rebase: (use "hg rebase --abort" to clear broken state)\n')
2279 2279 ui.write(msg)
2280 2280 return
2281 2281 numrebased = len([i for i in pycompat.itervalues(state) if i >= 0])
2282 2282 # i18n: column positioning for "hg summary"
2283 2283 ui.write(
2284 2284 _(b'rebase: %s, %s (rebase --continue)\n')
2285 2285 % (
2286 2286 ui.label(_(b'%d rebased'), b'rebase.rebased') % numrebased,
2287 2287 ui.label(_(b'%d remaining'), b'rebase.remaining')
2288 2288 % (len(state) - numrebased),
2289 2289 )
2290 2290 )
2291 2291
2292 2292
2293 2293 def uisetup(ui):
2294 2294 # Replace pull with a decorator to provide --rebase option
2295 2295 entry = extensions.wrapcommand(commands.table, b'pull', pullrebase)
2296 2296 entry[1].append(
2297 2297 (b'', b'rebase', None, _(b"rebase working directory to branch head"))
2298 2298 )
2299 2299 entry[1].append((b't', b'tool', b'', _(b"specify merge tool for rebase")))
2300 2300 cmdutil.summaryhooks.add(b'rebase', summaryhook)
2301 2301 statemod.addunfinished(
2302 2302 b'rebase',
2303 2303 fname=b'rebasestate',
2304 2304 stopflag=True,
2305 2305 continueflag=True,
2306 2306 abortfunc=abortrebase,
2307 2307 continuefunc=continuerebase,
2308 2308 )
@@ -1,922 +1,922 b''
1 1 #require symlink execbit
2 2 $ cat << EOF >> $HGRCPATH
3 3 > [phases]
4 4 > publish=False
5 5 > [extensions]
6 6 > amend=
7 7 > rebase=
8 8 > debugdrawdag=$TESTDIR/drawdag.py
9 9 > strip=
10 10 > [rebase]
11 11 > experimental.inmemory=1
12 12 > [diff]
13 13 > git=1
14 14 > [alias]
15 15 > tglog = log -G --template "{rev}: {node|short} '{desc}'\n"
16 16 > EOF
17 17
18 18 Rebase a simple DAG:
19 19 $ hg init repo1
20 20 $ cd repo1
21 21 $ hg debugdrawdag <<'EOS'
22 22 > c b
23 23 > |/
24 24 > d
25 25 > |
26 26 > a
27 27 > EOS
28 28 $ hg up -C a
29 29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 30 $ hg tglog
31 31 o 3: 814f6bd05178 'c'
32 32 |
33 33 | o 2: db0e82a16a62 'b'
34 34 |/
35 35 o 1: 02952614a83d 'd'
36 36 |
37 37 @ 0: b173517d0057 'a'
38 38
39 39 $ hg cat -r 3 c
40 40 c (no-eol)
41 41 $ hg cat -r 2 b
42 42 b (no-eol)
43 43 $ hg rebase --debug -r b -d c | grep rebasing
44 44 rebasing in-memory
45 45 rebasing 2:db0e82a16a62 "b" (b)
46 46 $ hg tglog
47 47 o 3: ca58782ad1e4 'b'
48 48 |
49 49 o 2: 814f6bd05178 'c'
50 50 |
51 51 o 1: 02952614a83d 'd'
52 52 |
53 53 @ 0: b173517d0057 'a'
54 54
55 55 $ hg cat -r 3 b
56 56 b (no-eol)
57 57 $ hg cat -r 2 c
58 58 c (no-eol)
59 59 $ cd ..
60 60
61 61 Case 2:
62 62 $ hg init repo2
63 63 $ cd repo2
64 64 $ hg debugdrawdag <<'EOS'
65 65 > c b
66 66 > |/
67 67 > d
68 68 > |
69 69 > a
70 70 > EOS
71 71
72 72 Add a symlink and executable file:
73 73 $ hg up -C c
74 74 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 75 $ ln -s somefile e
76 76 $ echo f > f
77 77 $ chmod +x f
78 78 $ hg add e f
79 79 $ hg amend -q
80 80 $ hg up -Cq a
81 81
82 82 Write files to the working copy, and ensure they're still there after the rebase
83 83 $ echo "abc" > a
84 84 $ ln -s def b
85 85 $ echo "ghi" > c
86 86 $ echo "jkl" > d
87 87 $ echo "mno" > e
88 88 $ hg tglog
89 89 o 3: f56b71190a8f 'c'
90 90 |
91 91 | o 2: db0e82a16a62 'b'
92 92 |/
93 93 o 1: 02952614a83d 'd'
94 94 |
95 95 @ 0: b173517d0057 'a'
96 96
97 97 $ hg cat -r 3 c
98 98 c (no-eol)
99 99 $ hg cat -r 2 b
100 100 b (no-eol)
101 101 $ hg cat -r 3 e
102 102 somefile (no-eol)
103 103 $ hg rebase --debug -s b -d a | grep rebasing
104 104 rebasing in-memory
105 105 rebasing 2:db0e82a16a62 "b" (b)
106 106 $ hg tglog
107 107 o 3: fc055c3b4d33 'b'
108 108 |
109 109 | o 2: f56b71190a8f 'c'
110 110 | |
111 111 | o 1: 02952614a83d 'd'
112 112 |/
113 113 @ 0: b173517d0057 'a'
114 114
115 115 $ hg cat -r 2 c
116 116 c (no-eol)
117 117 $ hg cat -r 3 b
118 118 b (no-eol)
119 119 $ hg rebase --debug -s 1 -d 3 | grep rebasing
120 120 rebasing in-memory
121 121 rebasing 1:02952614a83d "d" (d)
122 122 rebasing 2:f56b71190a8f "c"
123 123 $ hg tglog
124 124 o 3: 753feb6fd12a 'c'
125 125 |
126 126 o 2: 09c044d2cb43 'd'
127 127 |
128 128 o 1: fc055c3b4d33 'b'
129 129 |
130 130 @ 0: b173517d0057 'a'
131 131
132 132 Ensure working copy files are still there:
133 133 $ cat a
134 134 abc
135 135 $ readlink.py b
136 136 b -> def
137 137 $ cat e
138 138 mno
139 139
140 140 Ensure symlink and executable files were rebased properly:
141 141 $ hg up -Cq 3
142 142 $ readlink.py e
143 143 e -> somefile
144 144 $ ls -l f | cut -c -10
145 145 -rwxr-xr-x
146 146
147 147 Rebase the working copy parent
148 148 $ hg up -C 3
149 149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 150 $ hg rebase -r 3 -d 0 --debug | grep rebasing
151 151 rebasing in-memory
152 152 rebasing 3:753feb6fd12a "c" (tip)
153 153 $ hg tglog
154 154 @ 3: 844a7de3e617 'c'
155 155 |
156 156 | o 2: 09c044d2cb43 'd'
157 157 | |
158 158 | o 1: fc055c3b4d33 'b'
159 159 |/
160 160 o 0: b173517d0057 'a'
161 161
162 162
163 163 Test reporting of path conflicts
164 164
165 165 $ hg rm a
166 166 $ mkdir a
167 167 $ touch a/a
168 168 $ hg ci -Am "a/a"
169 169 adding a/a
170 170 $ hg tglog
171 171 @ 4: daf7dfc139cb 'a/a'
172 172 |
173 173 o 3: 844a7de3e617 'c'
174 174 |
175 175 | o 2: 09c044d2cb43 'd'
176 176 | |
177 177 | o 1: fc055c3b4d33 'b'
178 178 |/
179 179 o 0: b173517d0057 'a'
180 180
181 181 $ hg rebase -r . -d 2
182 182 rebasing 4:daf7dfc139cb "a/a" (tip)
183 183 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
184 184
185 185 $ hg tglog
186 186 @ 4: c6ad37a4f250 'a/a'
187 187 |
188 188 | o 3: 844a7de3e617 'c'
189 189 | |
190 190 o | 2: 09c044d2cb43 'd'
191 191 | |
192 192 o | 1: fc055c3b4d33 'b'
193 193 |/
194 194 o 0: b173517d0057 'a'
195 195
196 196 $ echo foo > foo
197 197 $ hg ci -Aqm "added foo"
198 198 $ hg up '.^'
199 199 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 200 $ echo bar > bar
201 201 $ hg ci -Aqm "added bar"
202 202 $ hg rm a/a
203 203 $ echo a > a
204 204 $ hg ci -Aqm "added a back!"
205 205 $ hg tglog
206 206 @ 7: 855e9797387e 'added a back!'
207 207 |
208 208 o 6: d14530e5e3e6 'added bar'
209 209 |
210 210 | o 5: 9b94b9373deb 'added foo'
211 211 |/
212 212 o 4: c6ad37a4f250 'a/a'
213 213 |
214 214 | o 3: 844a7de3e617 'c'
215 215 | |
216 216 o | 2: 09c044d2cb43 'd'
217 217 | |
218 218 o | 1: fc055c3b4d33 'b'
219 219 |/
220 220 o 0: b173517d0057 'a'
221 221
222 222 $ hg rebase -r . -d 5
223 223 rebasing 7:855e9797387e "added a back!" (tip)
224 224 saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
225 225
226 226 $ hg tglog
227 227 @ 7: bb3f02be2688 'added a back!'
228 228 |
229 229 | o 6: d14530e5e3e6 'added bar'
230 230 | |
231 231 o | 5: 9b94b9373deb 'added foo'
232 232 |/
233 233 o 4: c6ad37a4f250 'a/a'
234 234 |
235 235 | o 3: 844a7de3e617 'c'
236 236 | |
237 237 o | 2: 09c044d2cb43 'd'
238 238 | |
239 239 o | 1: fc055c3b4d33 'b'
240 240 |/
241 241 o 0: b173517d0057 'a'
242 242
243 243 $ mkdir -p c/subdir
244 244 $ echo c > c/subdir/file.txt
245 245 $ hg add c/subdir/file.txt
246 246 $ hg ci -m 'c/subdir/file.txt'
247 247 $ hg rebase -r . -d 3 -n
248 248 starting dry-run rebase; repository will not be changed
249 249 rebasing 8:e147e6e3c490 "c/subdir/file.txt" (tip)
250 250 abort: error: 'c/subdir/file.txt' conflicts with file 'c' in 3.
251 251 [255]
252 252 FIXME: shouldn't need this, but when we hit path conflicts in dryrun mode, we
253 253 don't clean up rebasestate.
254 254 $ hg rebase --abort
255 255 rebase aborted
256 256 $ hg rebase -r 3 -d . -n
257 257 starting dry-run rebase; repository will not be changed
258 258 rebasing 3:844a7de3e617 "c"
259 259 abort: error: file 'c' cannot be written because 'c/' is a directory in e147e6e3c490 (containing 1 entries: c/subdir/file.txt)
260 260 [255]
261 261
262 262 $ cd ..
263 263
264 264 Test path auditing (issue5818)
265 265
266 266 $ mkdir lib_
267 267 $ ln -s lib_ lib
268 268 $ hg init repo
269 269 $ cd repo
270 270 $ mkdir -p ".$TESTTMP/lib"
271 271 $ touch ".$TESTTMP/lib/a"
272 272 $ hg add ".$TESTTMP/lib/a"
273 273 $ hg ci -m 'a'
274 274
275 275 $ touch ".$TESTTMP/lib/b"
276 276 $ hg add ".$TESTTMP/lib/b"
277 277 $ hg ci -m 'b'
278 278
279 279 $ hg up -q '.^'
280 280 $ touch ".$TESTTMP/lib/c"
281 281 $ hg add ".$TESTTMP/lib/c"
282 282 $ hg ci -m 'c'
283 283 created new head
284 284 $ hg rebase -s 1 -d .
285 285 rebasing 1:* "b" (glob)
286 286 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-rebase.hg (glob)
287 287 $ cd ..
288 288
289 289 Test dry-run rebasing
290 290
291 291 $ hg init repo3
292 292 $ cd repo3
293 293 $ echo a>a
294 294 $ hg ci -Aqma
295 295 $ echo b>b
296 296 $ hg ci -Aqmb
297 297 $ echo c>c
298 298 $ hg ci -Aqmc
299 299 $ echo d>d
300 300 $ hg ci -Aqmd
301 301 $ echo e>e
302 302 $ hg ci -Aqme
303 303
304 304 $ hg up 1 -q
305 305 $ echo f>f
306 306 $ hg ci -Amf
307 307 adding f
308 308 created new head
309 309 $ echo g>g
310 310 $ hg ci -Aqmg
311 311 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
312 312 @ 6:baf10c5166d4 test
313 313 | g
314 314 |
315 315 o 5:6343ca3eff20 test
316 316 | f
317 317 |
318 318 | o 4:e860deea161a test
319 319 | | e
320 320 | |
321 321 | o 3:055a42cdd887 test
322 322 | | d
323 323 | |
324 324 | o 2:177f92b77385 test
325 325 |/ c
326 326 |
327 327 o 1:d2ae7f538514 test
328 328 | b
329 329 |
330 330 o 0:cb9a9f314b8b test
331 331 a
332 332
333 333 Make sure it throws error while passing --continue or --abort with --dry-run
334 334 $ hg rebase -s 2 -d 6 -n --continue
335 abort: cannot specify both --dry-run and --continue
335 abort: cannot specify both --continue and --dry-run
336 336 [255]
337 337 $ hg rebase -s 2 -d 6 -n --abort
338 abort: cannot specify both --dry-run and --abort
338 abort: cannot specify both --abort and --dry-run
339 339 [255]
340 340
341 341 Check dryrun gives correct results when there is no conflict in rebasing
342 342 $ hg rebase -s 2 -d 6 -n
343 343 starting dry-run rebase; repository will not be changed
344 344 rebasing 2:177f92b77385 "c"
345 345 rebasing 3:055a42cdd887 "d"
346 346 rebasing 4:e860deea161a "e"
347 347 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
348 348
349 349 $ hg diff
350 350 $ hg status
351 351
352 352 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
353 353 @ 6:baf10c5166d4 test
354 354 | g
355 355 |
356 356 o 5:6343ca3eff20 test
357 357 | f
358 358 |
359 359 | o 4:e860deea161a test
360 360 | | e
361 361 | |
362 362 | o 3:055a42cdd887 test
363 363 | | d
364 364 | |
365 365 | o 2:177f92b77385 test
366 366 |/ c
367 367 |
368 368 o 1:d2ae7f538514 test
369 369 | b
370 370 |
371 371 o 0:cb9a9f314b8b test
372 372 a
373 373
374 374 Check dryrun working with --collapse when there is no conflict
375 375 $ hg rebase -s 2 -d 6 -n --collapse
376 376 starting dry-run rebase; repository will not be changed
377 377 rebasing 2:177f92b77385 "c"
378 378 rebasing 3:055a42cdd887 "d"
379 379 rebasing 4:e860deea161a "e"
380 380 dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase
381 381
382 382 Check dryrun gives correct results when there is conflict in rebasing
383 383 Make a conflict:
384 384 $ hg up 6 -q
385 385 $ echo conflict>e
386 386 $ hg ci -Aqm "conflict with e"
387 387 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
388 388 @ 7:d2c195b28050 test
389 389 | conflict with e
390 390 |
391 391 o 6:baf10c5166d4 test
392 392 | g
393 393 |
394 394 o 5:6343ca3eff20 test
395 395 | f
396 396 |
397 397 | o 4:e860deea161a test
398 398 | | e
399 399 | |
400 400 | o 3:055a42cdd887 test
401 401 | | d
402 402 | |
403 403 | o 2:177f92b77385 test
404 404 |/ c
405 405 |
406 406 o 1:d2ae7f538514 test
407 407 | b
408 408 |
409 409 o 0:cb9a9f314b8b test
410 410 a
411 411
412 412 $ hg rebase -s 2 -d 7 -n
413 413 starting dry-run rebase; repository will not be changed
414 414 rebasing 2:177f92b77385 "c"
415 415 rebasing 3:055a42cdd887 "d"
416 416 rebasing 4:e860deea161a "e"
417 417 merging e
418 418 transaction abort!
419 419 rollback completed
420 420 hit a merge conflict
421 421 [1]
422 422 $ hg diff
423 423 $ hg status
424 424 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
425 425 @ 7:d2c195b28050 test
426 426 | conflict with e
427 427 |
428 428 o 6:baf10c5166d4 test
429 429 | g
430 430 |
431 431 o 5:6343ca3eff20 test
432 432 | f
433 433 |
434 434 | o 4:e860deea161a test
435 435 | | e
436 436 | |
437 437 | o 3:055a42cdd887 test
438 438 | | d
439 439 | |
440 440 | o 2:177f92b77385 test
441 441 |/ c
442 442 |
443 443 o 1:d2ae7f538514 test
444 444 | b
445 445 |
446 446 o 0:cb9a9f314b8b test
447 447 a
448 448
449 449 Check dryrun working with --collapse when there is conflicts
450 450 $ hg rebase -s 2 -d 7 -n --collapse
451 451 starting dry-run rebase; repository will not be changed
452 452 rebasing 2:177f92b77385 "c"
453 453 rebasing 3:055a42cdd887 "d"
454 454 rebasing 4:e860deea161a "e"
455 455 merging e
456 456 hit a merge conflict
457 457 [1]
458 458
459 459 In-memory rebase that fails due to merge conflicts
460 460
461 461 $ hg rebase -s 2 -d 7
462 462 rebasing 2:177f92b77385 "c"
463 463 rebasing 3:055a42cdd887 "d"
464 464 rebasing 4:e860deea161a "e"
465 465 merging e
466 466 transaction abort!
467 467 rollback completed
468 468 hit merge conflicts; re-running rebase without in-memory merge
469 469 rebasing 2:177f92b77385 "c"
470 470 rebasing 3:055a42cdd887 "d"
471 471 rebasing 4:e860deea161a "e"
472 472 merging e
473 473 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
474 474 unresolved conflicts (see hg resolve, then hg rebase --continue)
475 475 [1]
476 476 $ hg rebase --abort
477 477 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/c1e524d4287c-f91f82e1-backup.hg
478 478 rebase aborted
479 479
480 480 Retrying without in-memory merge won't lose working copy changes
481 481 $ cd ..
482 482 $ hg clone repo3 repo3-dirty -q
483 483 $ cd repo3-dirty
484 484 $ echo dirty > a
485 485 $ hg rebase -s 2 -d 7
486 486 rebasing 2:177f92b77385 "c"
487 487 rebasing 3:055a42cdd887 "d"
488 488 rebasing 4:e860deea161a "e"
489 489 merging e
490 490 transaction abort!
491 491 rollback completed
492 492 hit merge conflicts; re-running rebase without in-memory merge
493 493 abort: uncommitted changes
494 494 [255]
495 495 $ cat a
496 496 dirty
497 497
498 498 Retrying without in-memory merge won't lose merge state
499 499 $ cd ..
500 500 $ hg clone repo3 repo3-merge-state -q
501 501 $ cd repo3-merge-state
502 502 $ hg merge 4
503 503 merging e
504 504 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
505 505 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
506 506 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
507 507 [1]
508 508 $ hg resolve -l
509 509 U e
510 510 $ hg rebase -s 2 -d 7
511 511 abort: outstanding uncommitted merge
512 512 (use 'hg commit' or 'hg merge --abort')
513 513 [255]
514 514 $ hg resolve -l
515 515 U e
516 516
517 517 ==========================
518 518 Test for --confirm option|
519 519 ==========================
520 520 $ cd ..
521 521 $ hg clone repo3 repo4 -q
522 522 $ cd repo4
523 523 $ hg strip 7 -q
524 524 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
525 525 @ 6:baf10c5166d4 test
526 526 | g
527 527 |
528 528 o 5:6343ca3eff20 test
529 529 | f
530 530 |
531 531 | o 4:e860deea161a test
532 532 | | e
533 533 | |
534 534 | o 3:055a42cdd887 test
535 535 | | d
536 536 | |
537 537 | o 2:177f92b77385 test
538 538 |/ c
539 539 |
540 540 o 1:d2ae7f538514 test
541 541 | b
542 542 |
543 543 o 0:cb9a9f314b8b test
544 544 a
545 545
546 546 Check it gives error when both --dryrun and --confirm is used:
547 547 $ hg rebase -s 2 -d . --confirm --dry-run
548 548 abort: cannot specify both --confirm and --dry-run
549 549 [255]
550 550 $ hg rebase -s 2 -d . --confirm --abort
551 abort: cannot specify both --confirm and --abort
551 abort: cannot specify both --abort and --confirm
552 552 [255]
553 553 $ hg rebase -s 2 -d . --confirm --continue
554 abort: cannot specify both --confirm and --continue
554 abort: cannot specify both --continue and --confirm
555 555 [255]
556 556
557 557 Test --confirm option when there are no conflicts:
558 558 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
559 559 > n
560 560 > EOF
561 561 starting in-memory rebase
562 562 rebasing 2:177f92b77385 "c"
563 563 rebasing 3:055a42cdd887 "d"
564 564 rebasing 4:e860deea161a "e"
565 565 rebase completed successfully
566 566 apply changes (yn)? n
567 567 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
568 568 @ 6:baf10c5166d4 test
569 569 | g
570 570 |
571 571 o 5:6343ca3eff20 test
572 572 | f
573 573 |
574 574 | o 4:e860deea161a test
575 575 | | e
576 576 | |
577 577 | o 3:055a42cdd887 test
578 578 | | d
579 579 | |
580 580 | o 2:177f92b77385 test
581 581 |/ c
582 582 |
583 583 o 1:d2ae7f538514 test
584 584 | b
585 585 |
586 586 o 0:cb9a9f314b8b test
587 587 a
588 588
589 589 $ hg rebase -s 2 -d . --keep --config ui.interactive=True --confirm << EOF
590 590 > y
591 591 > EOF
592 592 starting in-memory rebase
593 593 rebasing 2:177f92b77385 "c"
594 594 rebasing 3:055a42cdd887 "d"
595 595 rebasing 4:e860deea161a "e"
596 596 rebase completed successfully
597 597 apply changes (yn)? y
598 598 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
599 599 o 9:9fd28f55f6dc test
600 600 | e
601 601 |
602 602 o 8:12cbf031f469 test
603 603 | d
604 604 |
605 605 o 7:c83b1da5b1ae test
606 606 | c
607 607 |
608 608 @ 6:baf10c5166d4 test
609 609 | g
610 610 |
611 611 o 5:6343ca3eff20 test
612 612 | f
613 613 |
614 614 | o 4:e860deea161a test
615 615 | | e
616 616 | |
617 617 | o 3:055a42cdd887 test
618 618 | | d
619 619 | |
620 620 | o 2:177f92b77385 test
621 621 |/ c
622 622 |
623 623 o 1:d2ae7f538514 test
624 624 | b
625 625 |
626 626 o 0:cb9a9f314b8b test
627 627 a
628 628
629 629 Test --confirm option when there is a conflict
630 630 $ hg up tip -q
631 631 $ echo ee>e
632 632 $ hg ci --amend -m "conflict with e" -q
633 633 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
634 634 @ 9:906d72f66a59 test
635 635 | conflict with e
636 636 |
637 637 o 8:12cbf031f469 test
638 638 | d
639 639 |
640 640 o 7:c83b1da5b1ae test
641 641 | c
642 642 |
643 643 o 6:baf10c5166d4 test
644 644 | g
645 645 |
646 646 o 5:6343ca3eff20 test
647 647 | f
648 648 |
649 649 | o 4:e860deea161a test
650 650 | | e
651 651 | |
652 652 | o 3:055a42cdd887 test
653 653 | | d
654 654 | |
655 655 | o 2:177f92b77385 test
656 656 |/ c
657 657 |
658 658 o 1:d2ae7f538514 test
659 659 | b
660 660 |
661 661 o 0:cb9a9f314b8b test
662 662 a
663 663
664 664 $ hg rebase -s 4 -d . --keep --confirm
665 665 starting in-memory rebase
666 666 rebasing 4:e860deea161a "e"
667 667 merging e
668 668 hit a merge conflict
669 669 [1]
670 670 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
671 671 @ 9:906d72f66a59 test
672 672 | conflict with e
673 673 |
674 674 o 8:12cbf031f469 test
675 675 | d
676 676 |
677 677 o 7:c83b1da5b1ae test
678 678 | c
679 679 |
680 680 o 6:baf10c5166d4 test
681 681 | g
682 682 |
683 683 o 5:6343ca3eff20 test
684 684 | f
685 685 |
686 686 | o 4:e860deea161a test
687 687 | | e
688 688 | |
689 689 | o 3:055a42cdd887 test
690 690 | | d
691 691 | |
692 692 | o 2:177f92b77385 test
693 693 |/ c
694 694 |
695 695 o 1:d2ae7f538514 test
696 696 | b
697 697 |
698 698 o 0:cb9a9f314b8b test
699 699 a
700 700
701 701 Test a metadata-only in-memory merge
702 702 $ cd $TESTTMP
703 703 $ hg init no_exception
704 704 $ cd no_exception
705 705 # Produce the following graph:
706 706 # o 'add +x to foo.txt'
707 707 # | o r1 (adds bar.txt, just for something to rebase to)
708 708 # |/
709 709 # o r0 (adds foo.txt, no +x)
710 710 $ echo hi > foo.txt
711 711 $ hg ci -qAm r0
712 712 $ echo hi > bar.txt
713 713 $ hg ci -qAm r1
714 714 $ hg co -qr ".^"
715 715 $ chmod +x foo.txt
716 716 $ hg ci -qAm 'add +x to foo.txt'
717 717 issue5960: this was raising an AttributeError exception
718 718 $ hg rebase -r . -d 1
719 719 rebasing 2:539b93e77479 "add +x to foo.txt" (tip)
720 720 saved backup bundle to $TESTTMP/no_exception/.hg/strip-backup/*.hg (glob)
721 721 $ hg diff -c tip
722 722 diff --git a/foo.txt b/foo.txt
723 723 old mode 100644
724 724 new mode 100755
725 725
726 726 Test rebasing a commit with copy information, but no content changes
727 727
728 728 $ cd ..
729 729 $ hg clone -q repo1 merge-and-rename
730 730 $ cd merge-and-rename
731 731 $ cat << EOF >> .hg/hgrc
732 732 > [experimental]
733 733 > evolution.createmarkers=True
734 734 > evolution.allowunstable=True
735 735 > EOF
736 736 $ hg co -q 1
737 737 $ hg mv d e
738 738 $ hg ci -qm 'rename d to e'
739 739 $ hg co -q 3
740 740 $ hg merge -q 4
741 741 $ hg ci -m 'merge'
742 742 $ hg co -q 2
743 743 $ mv d e
744 744 $ hg addremove -qs 0
745 745 $ hg ci -qm 'untracked rename of d to e'
746 746 $ hg debugobsolete -q `hg log -T '{node}' -r 4` `hg log -T '{node}' -r .`
747 747 1 new orphan changesets
748 748 $ hg tglog
749 749 @ 6: 676538af172d 'untracked rename of d to e'
750 750 |
751 751 | * 5: 574d92ad16fc 'merge'
752 752 | |\
753 753 | | x 4: 2c8b5dad7956 'rename d to e'
754 754 | | |
755 755 | o | 3: ca58782ad1e4 'b'
756 756 |/ /
757 757 o / 2: 814f6bd05178 'c'
758 758 |/
759 759 o 1: 02952614a83d 'd'
760 760 |
761 761 o 0: b173517d0057 'a'
762 762
763 763 $ hg rebase -b 5 -d tip
764 764 rebasing 3:ca58782ad1e4 "b"
765 765 rebasing 5:574d92ad16fc "merge"
766 766 note: not rebasing 5:574d92ad16fc "merge", its destination already has all its changes
767 767
768 768 $ cd ..
769 769
770 770 Test rebasing a commit with copy information
771 771
772 772 $ hg init rebase-rename
773 773 $ cd rebase-rename
774 774 $ echo a > a
775 775 $ hg ci -Aqm 'add a'
776 776 $ echo a2 > a
777 777 $ hg ci -m 'modify a'
778 778 $ hg co -q 0
779 779 $ hg mv a b
780 780 $ hg ci -qm 'rename a to b'
781 781 $ hg rebase -d 1
782 782 rebasing 2:b977edf6f839 "rename a to b" (tip)
783 783 merging a and b to b
784 784 saved backup bundle to $TESTTMP/rebase-rename/.hg/strip-backup/b977edf6f839-0864f570-rebase.hg
785 785 $ hg st --copies --change .
786 786 A b
787 787 a
788 788 R a
789 789 $ cd ..
790 790
791 791 Test rebasing a commit with copy information, where the target is empty
792 792
793 793 $ hg init rebase-rename-empty
794 794 $ cd rebase-rename-empty
795 795 $ echo a > a
796 796 $ hg ci -Aqm 'add a'
797 797 $ cat > a
798 798 $ hg ci -m 'make a empty'
799 799 $ hg co -q 0
800 800 $ hg mv a b
801 801 $ hg ci -qm 'rename a to b'
802 802 $ hg rebase -d 1
803 803 rebasing 2:b977edf6f839 "rename a to b" (tip)
804 804 merging a and b to b
805 805 saved backup bundle to $TESTTMP/rebase-rename-empty/.hg/strip-backup/b977edf6f839-0864f570-rebase.hg
806 806 $ hg st --copies --change .
807 807 A b
808 808 a
809 809 R a
810 810 $ cd ..
811 811 Rebase across a copy with --collapse
812 812
813 813 $ hg init rebase-rename-collapse
814 814 $ cd rebase-rename-collapse
815 815 $ echo a > a
816 816 $ hg ci -Aqm 'add a'
817 817 $ hg mv a b
818 818 $ hg ci -m 'rename a to b'
819 819 $ hg co -q 0
820 820 $ echo a2 > a
821 821 $ hg ci -qm 'modify a'
822 822 $ hg rebase -r . -d 1 --collapse
823 823 rebasing 2:41c4ea50d4cf "modify a" (tip)
824 824 merging b and a to b
825 825 saved backup bundle to $TESTTMP/rebase-rename-collapse/.hg/strip-backup/41c4ea50d4cf-b90b7994-rebase.hg
826 826 $ cd ..
827 827
828 828 Test rebasing when the file we are merging in destination is empty
829 829
830 830 $ hg init test
831 831 $ cd test
832 832 $ echo a > foo
833 833 $ hg ci -Aqm 'added a to foo'
834 834
835 835 $ rm foo
836 836 $ touch foo
837 837 $ hg di
838 838 diff --git a/foo b/foo
839 839 --- a/foo
840 840 +++ b/foo
841 841 @@ -1,1 +0,0 @@
842 842 -a
843 843
844 844 $ hg ci -m "make foo an empty file"
845 845
846 846 $ hg up '.^'
847 847 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
848 848 $ echo b > foo
849 849 $ hg di
850 850 diff --git a/foo b/foo
851 851 --- a/foo
852 852 +++ b/foo
853 853 @@ -1,1 +1,1 @@
854 854 -a
855 855 +b
856 856 $ hg ci -m "add b to foo"
857 857 created new head
858 858
859 859 $ hg rebase -r . -d 1 --config ui.merge=internal:merge3
860 860 rebasing 2:fb62b706688e "add b to foo" (tip)
861 861 merging foo
862 862 hit merge conflicts; re-running rebase without in-memory merge
863 863 rebasing 2:fb62b706688e "add b to foo" (tip)
864 864 merging foo
865 865 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
866 866 unresolved conflicts (see hg resolve, then hg rebase --continue)
867 867 [1]
868 868
869 869 $ cd $TESTTMP
870 870
871 871 Test rebasing when we're in the middle of a rebase already
872 872 $ hg init test_issue6214
873 873 $ cd test_issue6214
874 874 $ echo r0 > r0
875 875 $ hg ci -qAm 'r0'
876 876 $ echo hi > foo
877 877 $ hg ci -qAm 'hi from foo'
878 878 $ hg co -q '.^'
879 879 $ echo bye > foo
880 880 $ hg ci -qAm 'bye from foo'
881 881 $ hg co -q '.^'
882 882 $ echo unrelated > some_other_file
883 883 $ hg ci -qAm 'some unrelated changes'
884 884 $ hg log -G -T'{rev}: {desc}\n{files%"{file}\n"}'
885 885 @ 3: some unrelated changes
886 886 | some_other_file
887 887 | o 2: bye from foo
888 888 |/ foo
889 889 | o 1: hi from foo
890 890 |/ foo
891 891 o 0: r0
892 892 r0
893 893 $ hg rebase -r 2 -d 1 -t:merge3
894 894 rebasing 2:b4d249fbf8dd "bye from foo"
895 895 merging foo
896 896 hit merge conflicts; re-running rebase without in-memory merge
897 897 rebasing 2:b4d249fbf8dd "bye from foo"
898 898 merging foo
899 899 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
900 900 unresolved conflicts (see hg resolve, then hg rebase --continue)
901 901 [1]
902 902 $ hg rebase -r 3 -d 1 -t:merge3
903 903 abort: rebase in progress
904 904 (use 'hg rebase --continue' or 'hg rebase --abort')
905 905 [255]
906 906 $ hg resolve --list
907 907 U foo
908 908 $ hg resolve --all --re-merge -t:other
909 909 (no more unresolved files)
910 910 continue: hg rebase --continue
911 911 $ hg rebase --continue
912 912 rebasing 2:b4d249fbf8dd "bye from foo"
913 913 saved backup bundle to $TESTTMP/test_issue6214/.hg/strip-backup/b4d249fbf8dd-299ec25c-rebase.hg
914 914 $ hg log -G -T'{rev}: {desc}\n{files%"{file}\n"}'
915 915 o 3: bye from foo
916 916 | foo
917 917 | @ 2: some unrelated changes
918 918 | | some_other_file
919 919 o | 1: hi from foo
920 920 |/ foo
921 921 o 0: r0
922 922 r0
@@ -1,2142 +1,2142 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}{if(obsolete,' ({obsfate})')}
10 10 > [experimental]
11 11 > evolution.createmarkers=True
12 12 > evolution.allowunstable=True
13 13 > [phases]
14 14 > publish=False
15 15 > [extensions]
16 16 > rebase=
17 17 > drawdag=$TESTDIR/drawdag.py
18 18 > strip=
19 19 > EOF
20 20
21 21 Setup rebase canonical repo
22 22
23 23 $ hg init base
24 24 $ cd base
25 25 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
26 26 adding changesets
27 27 adding manifests
28 28 adding file changes
29 29 added 8 changesets with 7 changes to 7 files (+2 heads)
30 30 new changesets cd010b8cd998:02de42196ebe (8 drafts)
31 31 (run 'hg heads' to see heads, 'hg merge' to merge)
32 32 $ hg up tip
33 33 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 34 $ hg log -G
35 35 @ 7:02de42196ebe H
36 36 |
37 37 | o 6:eea13746799a G
38 38 |/|
39 39 o | 5:24b6387c8c8c F
40 40 | |
41 41 | o 4:9520eea781bc E
42 42 |/
43 43 | o 3:32af7686d403 D
44 44 | |
45 45 | o 2:5fddd98957c8 C
46 46 | |
47 47 | o 1:42ccdea3bb16 B
48 48 |/
49 49 o 0:cd010b8cd998 A
50 50
51 51 $ cd ..
52 52
53 53 simple rebase
54 54 ---------------------------------
55 55
56 56 $ hg clone base simple
57 57 updating to branch default
58 58 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 59 $ cd simple
60 60 $ hg up 32af7686d403
61 61 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
62 62 $ hg rebase -d eea13746799a
63 63 rebasing 1:42ccdea3bb16 "B"
64 64 rebasing 2:5fddd98957c8 "C"
65 65 rebasing 3:32af7686d403 "D"
66 66 $ hg log -G
67 67 @ 10:8eeb3c33ad33 D
68 68 |
69 69 o 9:2327fea05063 C
70 70 |
71 71 o 8:e4e5be0395b2 B
72 72 |
73 73 | o 7:02de42196ebe H
74 74 | |
75 75 o | 6:eea13746799a G
76 76 |\|
77 77 | o 5:24b6387c8c8c F
78 78 | |
79 79 o | 4:9520eea781bc E
80 80 |/
81 81 o 0:cd010b8cd998 A
82 82
83 83 $ hg log --hidden -G
84 84 @ 10:8eeb3c33ad33 D
85 85 |
86 86 o 9:2327fea05063 C
87 87 |
88 88 o 8:e4e5be0395b2 B
89 89 |
90 90 | o 7:02de42196ebe H
91 91 | |
92 92 o | 6:eea13746799a G
93 93 |\|
94 94 | o 5:24b6387c8c8c F
95 95 | |
96 96 o | 4:9520eea781bc E
97 97 |/
98 98 | x 3:32af7686d403 D (rewritten using rebase as 10:8eeb3c33ad33)
99 99 | |
100 100 | x 2:5fddd98957c8 C (rewritten using rebase as 9:2327fea05063)
101 101 | |
102 102 | x 1:42ccdea3bb16 B (rewritten using rebase as 8:e4e5be0395b2)
103 103 |/
104 104 o 0:cd010b8cd998 A
105 105
106 106 $ hg debugobsolete
107 107 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
108 108 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
109 109 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
110 110
111 111
112 112 $ cd ..
113 113
114 114 empty changeset
115 115 ---------------------------------
116 116
117 117 $ hg clone base empty
118 118 updating to branch default
119 119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 120 $ cd empty
121 121 $ hg up eea13746799a
122 122 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
123 123
124 124 We make a copy of both the first changeset in the rebased and some other in the
125 125 set.
126 126
127 127 $ hg graft 42ccdea3bb16 32af7686d403
128 128 grafting 1:42ccdea3bb16 "B"
129 129 grafting 3:32af7686d403 "D"
130 130 $ hg rebase -s 42ccdea3bb16 -d .
131 131 rebasing 1:42ccdea3bb16 "B"
132 132 note: not rebasing 1:42ccdea3bb16 "B", its destination already has all its changes
133 133 rebasing 2:5fddd98957c8 "C"
134 134 rebasing 3:32af7686d403 "D"
135 135 note: not rebasing 3:32af7686d403 "D", its destination already has all its changes
136 136 $ hg log -G
137 137 o 10:5ae4c968c6ac C
138 138 |
139 139 @ 9:08483444fef9 D
140 140 |
141 141 o 8:8877864f1edb B
142 142 |
143 143 | o 7:02de42196ebe H
144 144 | |
145 145 o | 6:eea13746799a G
146 146 |\|
147 147 | o 5:24b6387c8c8c F
148 148 | |
149 149 o | 4:9520eea781bc E
150 150 |/
151 151 o 0:cd010b8cd998 A
152 152
153 153 $ hg log --hidden -G
154 154 o 10:5ae4c968c6ac C
155 155 |
156 156 @ 9:08483444fef9 D
157 157 |
158 158 o 8:8877864f1edb B
159 159 |
160 160 | o 7:02de42196ebe H
161 161 | |
162 162 o | 6:eea13746799a G
163 163 |\|
164 164 | o 5:24b6387c8c8c F
165 165 | |
166 166 o | 4:9520eea781bc E
167 167 |/
168 168 | x 3:32af7686d403 D (pruned using rebase)
169 169 | |
170 170 | x 2:5fddd98957c8 C (rewritten using rebase as 10:5ae4c968c6ac)
171 171 | |
172 172 | x 1:42ccdea3bb16 B (pruned using rebase)
173 173 |/
174 174 o 0:cd010b8cd998 A
175 175
176 176 $ hg debugobsolete
177 177 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
178 178 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
179 179 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
180 180
181 181
182 182 More complex case where part of the rebase set were already rebased
183 183
184 184 $ hg rebase --rev 'desc(D)' --dest 'desc(H)'
185 185 rebasing 9:08483444fef9 "D"
186 186 1 new orphan changesets
187 187 $ hg debugobsolete
188 188 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
189 189 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
190 190 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
191 191 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
192 192 $ hg log -G
193 193 @ 11:4596109a6a43 D
194 194 |
195 195 | * 10:5ae4c968c6ac C
196 196 | |
197 197 | x 9:08483444fef9 D (rewritten using rebase as 11:4596109a6a43)
198 198 | |
199 199 | o 8:8877864f1edb B
200 200 | |
201 201 o | 7:02de42196ebe H
202 202 | |
203 203 | o 6:eea13746799a G
204 204 |/|
205 205 o | 5:24b6387c8c8c F
206 206 | |
207 207 | o 4:9520eea781bc E
208 208 |/
209 209 o 0:cd010b8cd998 A
210 210
211 211 $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
212 212 rebasing 8:8877864f1edb "B"
213 213 note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D" (tip)
214 214 rebasing 10:5ae4c968c6ac "C"
215 215 $ hg debugobsolete
216 216 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
217 217 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
218 218 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '0', 'operation': 'rebase', 'user': 'test'}
219 219 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
220 220 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
221 221 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
222 222 $ hg log --rev 'contentdivergent()'
223 223 $ hg log -G
224 224 o 13:98f6af4ee953 C
225 225 |
226 226 o 12:462a34d07e59 B
227 227 |
228 228 @ 11:4596109a6a43 D
229 229 |
230 230 o 7:02de42196ebe H
231 231 |
232 232 | o 6:eea13746799a G
233 233 |/|
234 234 o | 5:24b6387c8c8c F
235 235 | |
236 236 | o 4:9520eea781bc E
237 237 |/
238 238 o 0:cd010b8cd998 A
239 239
240 240 $ hg log --style default --debug -r 4596109a6a4328c398bde3a4a3b6737cfade3003
241 241 changeset: 11:4596109a6a4328c398bde3a4a3b6737cfade3003
242 242 phase: draft
243 243 parent: 7:02de42196ebee42ef284b6780a87cdc96e8eaab6
244 244 parent: -1:0000000000000000000000000000000000000000
245 245 manifest: 11:a91006e3a02f1edf631f7018e6e5684cf27dd905
246 246 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
247 247 date: Sat Apr 30 15:24:48 2011 +0200
248 248 files+: D
249 249 extra: branch=default
250 250 extra: rebase_source=08483444fef91d6224f6655ee586a65d263ad34c
251 251 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
252 252 description:
253 253 D
254 254
255 255
256 256 $ hg up -qr 'desc(G)'
257 257 $ hg graft 4596109a6a4328c398bde3a4a3b6737cfade3003
258 258 grafting 11:4596109a6a43 "D"
259 259 $ hg up -qr 'desc(E)'
260 260 $ hg rebase -s tip -d .
261 261 rebasing 14:9e36056a46e3 "D" (tip)
262 262 $ hg log --style default --debug -r tip
263 263 changeset: 15:627d4614809036ba22b9e7cb31638ddc06ab99ab
264 264 tag: tip
265 265 phase: draft
266 266 parent: 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba
267 267 parent: -1:0000000000000000000000000000000000000000
268 268 manifest: 15:648e8ede73ae3e497d093d3a4c8fcc2daa864f42
269 269 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
270 270 date: Sat Apr 30 15:24:48 2011 +0200
271 271 files+: D
272 272 extra: branch=default
273 273 extra: intermediate-source=4596109a6a4328c398bde3a4a3b6737cfade3003
274 274 extra: rebase_source=9e36056a46e37c9776168c7375734eebc70e294f
275 275 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
276 276 description:
277 277 D
278 278
279 279
280 280 Start rebase from a commit that is obsolete but not hidden only because it's
281 281 a working copy parent. We should be moved back to the starting commit as usual
282 282 even though it is hidden (until we're moved there).
283 283
284 284 $ hg --hidden up -qr 'first(hidden())'
285 285 updated to hidden changeset 42ccdea3bb16
286 286 (hidden revision '42ccdea3bb16' is pruned)
287 287 $ hg rebase --rev 13 --dest 15
288 288 rebasing 13:98f6af4ee953 "C"
289 289 $ hg log -G
290 290 o 16:294a2b93eb4d C
291 291 |
292 292 o 15:627d46148090 D
293 293 |
294 294 | o 12:462a34d07e59 B
295 295 | |
296 296 | o 11:4596109a6a43 D
297 297 | |
298 298 | o 7:02de42196ebe H
299 299 | |
300 300 +---o 6:eea13746799a G
301 301 | |/
302 302 | o 5:24b6387c8c8c F
303 303 | |
304 304 o | 4:9520eea781bc E
305 305 |/
306 306 | @ 1:42ccdea3bb16 B (pruned using rebase)
307 307 |/
308 308 o 0:cd010b8cd998 A
309 309
310 310
311 311 $ cd ..
312 312
313 313 collapse rebase
314 314 ---------------------------------
315 315
316 316 $ hg clone base collapse
317 317 updating to branch default
318 318 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
319 319 $ cd collapse
320 320 $ hg rebase -s 42ccdea3bb16 -d eea13746799a --collapse
321 321 rebasing 1:42ccdea3bb16 "B"
322 322 rebasing 2:5fddd98957c8 "C"
323 323 rebasing 3:32af7686d403 "D"
324 324 $ hg log -G
325 325 o 8:4dc2197e807b Collapsed revision
326 326 |
327 327 | @ 7:02de42196ebe H
328 328 | |
329 329 o | 6:eea13746799a G
330 330 |\|
331 331 | o 5:24b6387c8c8c F
332 332 | |
333 333 o | 4:9520eea781bc E
334 334 |/
335 335 o 0:cd010b8cd998 A
336 336
337 337 $ hg log --hidden -G
338 338 o 8:4dc2197e807b Collapsed revision
339 339 |
340 340 | @ 7:02de42196ebe H
341 341 | |
342 342 o | 6:eea13746799a G
343 343 |\|
344 344 | o 5:24b6387c8c8c F
345 345 | |
346 346 o | 4:9520eea781bc E
347 347 |/
348 348 | x 3:32af7686d403 D (rewritten using rebase as 8:4dc2197e807b)
349 349 | |
350 350 | x 2:5fddd98957c8 C (rewritten using rebase as 8:4dc2197e807b)
351 351 | |
352 352 | x 1:42ccdea3bb16 B (rewritten using rebase as 8:4dc2197e807b)
353 353 |/
354 354 o 0:cd010b8cd998 A
355 355
356 356 $ hg id --debug -r tip
357 357 4dc2197e807bae9817f09905b50ab288be2dbbcf tip
358 358 $ hg debugobsolete
359 359 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'fold-id': '6fb65cdc', 'fold-idx': '1', 'fold-size': '3', 'operation': 'rebase', 'user': 'test'}
360 360 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'fold-id': '6fb65cdc', 'fold-idx': '2', 'fold-size': '3', 'operation': 'rebase', 'user': 'test'}
361 361 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'fold-id': '6fb65cdc', 'fold-idx': '3', 'fold-size': '3', 'operation': 'rebase', 'user': 'test'}
362 362
363 363 $ cd ..
364 364
365 365 Rebase set has hidden descendants
366 366 ---------------------------------
367 367
368 368 We rebase a changeset which has hidden descendants. Hidden changesets must not
369 369 be rebased.
370 370
371 371 $ hg clone base hidden
372 372 updating to branch default
373 373 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 374 $ cd hidden
375 375 $ hg log -G
376 376 @ 7:02de42196ebe H
377 377 |
378 378 | o 6:eea13746799a G
379 379 |/|
380 380 o | 5:24b6387c8c8c F
381 381 | |
382 382 | o 4:9520eea781bc E
383 383 |/
384 384 | o 3:32af7686d403 D
385 385 | |
386 386 | o 2:5fddd98957c8 C
387 387 | |
388 388 | o 1:42ccdea3bb16 B
389 389 |/
390 390 o 0:cd010b8cd998 A
391 391
392 392 $ hg rebase -s 5fddd98957c8 -d eea13746799a
393 393 rebasing 2:5fddd98957c8 "C"
394 394 rebasing 3:32af7686d403 "D"
395 395 $ hg log -G
396 396 o 9:cf44d2f5a9f4 D
397 397 |
398 398 o 8:e273c5e7d2d2 C
399 399 |
400 400 | @ 7:02de42196ebe H
401 401 | |
402 402 o | 6:eea13746799a G
403 403 |\|
404 404 | o 5:24b6387c8c8c F
405 405 | |
406 406 o | 4:9520eea781bc E
407 407 |/
408 408 | o 1:42ccdea3bb16 B
409 409 |/
410 410 o 0:cd010b8cd998 A
411 411
412 412 $ hg rebase -s 42ccdea3bb16 -d 02de42196ebe
413 413 rebasing 1:42ccdea3bb16 "B"
414 414 $ hg log -G
415 415 o 10:7c6027df6a99 B
416 416 |
417 417 | o 9:cf44d2f5a9f4 D
418 418 | |
419 419 | o 8:e273c5e7d2d2 C
420 420 | |
421 421 @ | 7:02de42196ebe H
422 422 | |
423 423 | o 6:eea13746799a G
424 424 |/|
425 425 o | 5:24b6387c8c8c F
426 426 | |
427 427 | o 4:9520eea781bc E
428 428 |/
429 429 o 0:cd010b8cd998 A
430 430
431 431 $ hg log --hidden -G
432 432 o 10:7c6027df6a99 B
433 433 |
434 434 | o 9:cf44d2f5a9f4 D
435 435 | |
436 436 | o 8:e273c5e7d2d2 C
437 437 | |
438 438 @ | 7:02de42196ebe H
439 439 | |
440 440 | o 6:eea13746799a G
441 441 |/|
442 442 o | 5:24b6387c8c8c F
443 443 | |
444 444 | o 4:9520eea781bc E
445 445 |/
446 446 | x 3:32af7686d403 D (rewritten using rebase as 9:cf44d2f5a9f4)
447 447 | |
448 448 | x 2:5fddd98957c8 C (rewritten using rebase as 8:e273c5e7d2d2)
449 449 | |
450 450 | x 1:42ccdea3bb16 B (rewritten using rebase as 10:7c6027df6a99)
451 451 |/
452 452 o 0:cd010b8cd998 A
453 453
454 454 $ hg debugobsolete
455 455 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
456 456 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
457 457 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
458 458
459 459 Test that rewriting leaving instability behind is allowed
460 460 ---------------------------------------------------------------------
461 461
462 462 $ hg log -r 'children(8)'
463 463 9:cf44d2f5a9f4 D (no-eol)
464 464 $ hg rebase -r 8
465 465 rebasing 8:e273c5e7d2d2 "C"
466 466 1 new orphan changesets
467 467 $ hg log -G
468 468 o 11:0d8f238b634c C
469 469 |
470 470 o 10:7c6027df6a99 B
471 471 |
472 472 | * 9:cf44d2f5a9f4 D
473 473 | |
474 474 | x 8:e273c5e7d2d2 C (rewritten using rebase as 11:0d8f238b634c)
475 475 | |
476 476 @ | 7:02de42196ebe H
477 477 | |
478 478 | o 6:eea13746799a G
479 479 |/|
480 480 o | 5:24b6387c8c8c F
481 481 | |
482 482 | o 4:9520eea781bc E
483 483 |/
484 484 o 0:cd010b8cd998 A
485 485
486 486 $ cd ..
487 487 $ cp -R hidden stabilize
488 488 $ cd stabilize
489 489 $ hg rebase --auto-orphans '0::' -d 10
490 490 abort: --auto-orphans is incompatible with --dest
491 491 [255]
492 492 $ hg rebase --auto-orphans '0::'
493 493 rebasing 9:cf44d2f5a9f4 "D"
494 494 $ hg log -G
495 495 o 12:7e3935feaa68 D
496 496 |
497 497 o 11:0d8f238b634c C
498 498 |
499 499 o 10:7c6027df6a99 B
500 500 |
501 501 @ 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 0:cd010b8cd998 A
510 510
511 511
512 512 $ cd ../hidden
513 513 $ rm -r ../stabilize
514 514
515 515 Test multiple root handling
516 516 ------------------------------------
517 517
518 518 $ hg rebase --dest 4 --rev '7+11+9'
519 519 rebasing 9:cf44d2f5a9f4 "D"
520 520 rebasing 7:02de42196ebe "H"
521 521 rebasing 11:0d8f238b634c "C" (tip)
522 522 $ hg log -G
523 523 o 14:1e8370e38cca C
524 524 |
525 525 @ 13:bfe264faf697 H
526 526 |
527 527 | o 12:102b4c1d889b D
528 528 |/
529 529 | * 10:7c6027df6a99 B
530 530 | |
531 531 | x 7:02de42196ebe H (rewritten using rebase as 13:bfe264faf697)
532 532 | |
533 533 +---o 6:eea13746799a G
534 534 | |/
535 535 | o 5:24b6387c8c8c F
536 536 | |
537 537 o | 4:9520eea781bc E
538 538 |/
539 539 o 0:cd010b8cd998 A
540 540
541 541 $ cd ..
542 542
543 543 Detach both parents
544 544
545 545 $ hg init double-detach
546 546 $ cd double-detach
547 547
548 548 $ hg debugdrawdag <<EOF
549 549 > F
550 550 > /|
551 551 > C E
552 552 > | |
553 553 > B D G
554 554 > \|/
555 555 > A
556 556 > EOF
557 557
558 558 $ hg rebase -d G -r 'B + D + F'
559 559 rebasing 1:112478962961 "B" (B)
560 560 rebasing 2:b18e25de2cf5 "D" (D)
561 561 rebasing 6:f15c3adaf214 "F" (F tip)
562 562 abort: cannot rebase 6:f15c3adaf214 without moving at least one of its parents
563 563 [255]
564 564
565 565 $ cd ..
566 566
567 567 test on rebase dropping a merge
568 568
569 569 (setup)
570 570
571 571 $ hg init dropmerge
572 572 $ cd dropmerge
573 573 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
574 574 adding changesets
575 575 adding manifests
576 576 adding file changes
577 577 added 8 changesets with 7 changes to 7 files (+2 heads)
578 578 new changesets cd010b8cd998:02de42196ebe (8 drafts)
579 579 (run 'hg heads' to see heads, 'hg merge' to merge)
580 580 $ hg up 3
581 581 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 582 $ hg merge 7
583 583 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 584 (branch merge, don't forget to commit)
585 585 $ hg ci -m 'M'
586 586 $ echo I > I
587 587 $ hg add I
588 588 $ hg ci -m I
589 589 $ hg log -G
590 590 @ 9:4bde274eefcf I
591 591 |
592 592 o 8:53a6a128b2b7 M
593 593 |\
594 594 | o 7:02de42196ebe H
595 595 | |
596 596 | | o 6:eea13746799a G
597 597 | |/|
598 598 | o | 5:24b6387c8c8c F
599 599 | | |
600 600 | | o 4:9520eea781bc E
601 601 | |/
602 602 o | 3:32af7686d403 D
603 603 | |
604 604 o | 2:5fddd98957c8 C
605 605 | |
606 606 o | 1:42ccdea3bb16 B
607 607 |/
608 608 o 0:cd010b8cd998 A
609 609
610 610 (actual test)
611 611
612 612 $ hg rebase --dest 6 --rev '((desc(H) + desc(D))::) - desc(M)'
613 613 rebasing 3:32af7686d403 "D"
614 614 rebasing 7:02de42196ebe "H"
615 615 rebasing 9:4bde274eefcf "I" (tip)
616 616 1 new orphan changesets
617 617 $ hg log -G
618 618 @ 12:acd174b7ab39 I
619 619 |
620 620 o 11:6c11a6218c97 H
621 621 |
622 622 | o 10:b5313c85b22e D
623 623 |/
624 624 | * 8:53a6a128b2b7 M
625 625 | |\
626 626 | | x 7:02de42196ebe H (rewritten using rebase as 11:6c11a6218c97)
627 627 | | |
628 628 o---+ 6:eea13746799a G
629 629 | | |
630 630 | | o 5:24b6387c8c8c F
631 631 | | |
632 632 o---+ 4:9520eea781bc E
633 633 / /
634 634 x | 3:32af7686d403 D (rewritten using rebase as 10:b5313c85b22e)
635 635 | |
636 636 o | 2:5fddd98957c8 C
637 637 | |
638 638 o | 1:42ccdea3bb16 B
639 639 |/
640 640 o 0:cd010b8cd998 A
641 641
642 642
643 643 Test hidden changesets in the rebase set (issue4504)
644 644
645 645 $ hg up --hidden 9
646 646 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
647 647 updated to hidden changeset 4bde274eefcf
648 648 (hidden revision '4bde274eefcf' was rewritten as: acd174b7ab39)
649 649 $ echo J > J
650 650 $ hg add J
651 651 $ hg commit -m J
652 652 1 new orphan changesets
653 653 $ hg debugobsolete `hg log --rev . -T '{node}'`
654 654 1 new obsolescence markers
655 655 obsoleted 1 changesets
656 656
657 657 $ hg rebase --rev .~1::. --dest 'max(desc(D))' --traceback --config experimental.rebaseskipobsolete=off
658 658 rebasing 9:4bde274eefcf "I"
659 659 rebasing 13:06edfc82198f "J" (tip)
660 660 2 new content-divergent changesets
661 661 $ hg log -G
662 662 @ 15:5ae8a643467b J
663 663 |
664 664 * 14:9ad579b4a5de I
665 665 |
666 666 | * 12:acd174b7ab39 I
667 667 | |
668 668 | o 11:6c11a6218c97 H
669 669 | |
670 670 o | 10:b5313c85b22e D
671 671 |/
672 672 | * 8:53a6a128b2b7 M
673 673 | |\
674 674 | | x 7:02de42196ebe H (rewritten using rebase as 11:6c11a6218c97)
675 675 | | |
676 676 o---+ 6:eea13746799a G
677 677 | | |
678 678 | | o 5:24b6387c8c8c F
679 679 | | |
680 680 o---+ 4:9520eea781bc E
681 681 / /
682 682 x | 3:32af7686d403 D (rewritten using rebase as 10:b5313c85b22e)
683 683 | |
684 684 o | 2:5fddd98957c8 C
685 685 | |
686 686 o | 1:42ccdea3bb16 B
687 687 |/
688 688 o 0:cd010b8cd998 A
689 689
690 690 $ hg up 14 -C
691 691 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
692 692 $ echo "K" > K
693 693 $ hg add K
694 694 $ hg commit --amend -m "K"
695 695 1 new orphan changesets
696 696 $ echo "L" > L
697 697 $ hg add L
698 698 $ hg commit -m "L"
699 699 $ hg up '.^'
700 700 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
701 701 $ echo "M" > M
702 702 $ hg add M
703 703 $ hg commit --amend -m "M"
704 704 1 new orphan changesets
705 705 $ hg log -G
706 706 @ 18:bfaedf8eb73b M
707 707 |
708 708 | * 17:97219452e4bd L
709 709 | |
710 710 | x 16:fc37a630c901 K (rewritten using amend as 18:bfaedf8eb73b)
711 711 |/
712 712 | * 15:5ae8a643467b J
713 713 | |
714 714 | x 14:9ad579b4a5de I (rewritten using amend as 16:fc37a630c901)
715 715 |/
716 716 | * 12:acd174b7ab39 I
717 717 | |
718 718 | o 11:6c11a6218c97 H
719 719 | |
720 720 o | 10:b5313c85b22e D
721 721 |/
722 722 | * 8:53a6a128b2b7 M
723 723 | |\
724 724 | | x 7:02de42196ebe H (rewritten using rebase as 11:6c11a6218c97)
725 725 | | |
726 726 o---+ 6:eea13746799a G
727 727 | | |
728 728 | | o 5:24b6387c8c8c F
729 729 | | |
730 730 o---+ 4:9520eea781bc E
731 731 / /
732 732 x | 3:32af7686d403 D (rewritten using rebase as 10:b5313c85b22e)
733 733 | |
734 734 o | 2:5fddd98957c8 C
735 735 | |
736 736 o | 1:42ccdea3bb16 B
737 737 |/
738 738 o 0:cd010b8cd998 A
739 739
740 740 $ hg rebase -s 14 -d 17 --config experimental.rebaseskipobsolete=True
741 741 note: not rebasing 14:9ad579b4a5de "I", already in destination as 16:fc37a630c901 "K"
742 742 rebasing 15:5ae8a643467b "J"
743 743 1 new orphan changesets
744 744
745 745 $ cd ..
746 746
747 747 Skip obsolete changeset even with multiple hops
748 748 -----------------------------------------------
749 749
750 750 setup
751 751
752 752 $ hg init obsskip
753 753 $ cd obsskip
754 754 $ cat << EOF >> .hg/hgrc
755 755 > [experimental]
756 756 > rebaseskipobsolete = True
757 757 > [extensions]
758 758 > strip =
759 759 > EOF
760 760 $ echo A > A
761 761 $ hg add A
762 762 $ hg commit -m A
763 763 $ echo B > B
764 764 $ hg add B
765 765 $ hg commit -m B0
766 766 $ hg commit --amend -m B1
767 767 $ hg commit --amend -m B2
768 768 $ hg up --hidden 'desc(B0)'
769 769 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
770 770 updated to hidden changeset a8b11f55fb19
771 771 (hidden revision 'a8b11f55fb19' was rewritten as: 261e70097290)
772 772 $ echo C > C
773 773 $ hg add C
774 774 $ hg commit -m C
775 775 1 new orphan changesets
776 776 $ hg log -G
777 777 @ 4:212cb178bcbb C
778 778 |
779 779 | o 3:261e70097290 B2
780 780 | |
781 781 x | 1:a8b11f55fb19 B0 (rewritten using amend as 3:261e70097290)
782 782 |/
783 783 o 0:4a2df7238c3b A
784 784
785 785
786 786 Rebase finds its way in a chain of marker
787 787
788 788 $ hg rebase -d 'desc(B2)'
789 789 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 3:261e70097290 "B2"
790 790 rebasing 4:212cb178bcbb "C" (tip)
791 791
792 792 Even when the chain include missing node
793 793
794 794 $ hg up --hidden 'desc(B0)'
795 795 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
796 796 updated to hidden changeset a8b11f55fb19
797 797 (hidden revision 'a8b11f55fb19' was rewritten as: 261e70097290)
798 798 $ echo D > D
799 799 $ hg add D
800 800 $ hg commit -m D
801 801 1 new orphan changesets
802 802 $ hg --hidden strip -r 'desc(B1)'
803 803 saved backup bundle to $TESTTMP/obsskip/.hg/strip-backup/86f6414ccda7-b1c452ee-backup.hg
804 804 1 new orphan changesets
805 805 $ hg log -G
806 806 @ 5:1a79b7535141 D
807 807 |
808 808 | o 4:ff2c4d47b71d C
809 809 | |
810 810 | o 2:261e70097290 B2
811 811 | |
812 812 x | 1:a8b11f55fb19 B0 (rewritten using amend as 2:261e70097290)
813 813 |/
814 814 o 0:4a2df7238c3b A
815 815
816 816
817 817 $ hg rebase -d 'desc(B2)'
818 818 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 2:261e70097290 "B2"
819 819 rebasing 5:1a79b7535141 "D" (tip)
820 820 $ hg up 4
821 821 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
822 822 $ echo "O" > O
823 823 $ hg add O
824 824 $ hg commit -m O
825 825 $ echo "P" > P
826 826 $ hg add P
827 827 $ hg commit -m P
828 828 $ hg log -G
829 829 @ 8:8d47583e023f P
830 830 |
831 831 o 7:360bbaa7d3ce O
832 832 |
833 833 | o 6:9c48361117de D
834 834 | |
835 835 o | 4:ff2c4d47b71d C
836 836 |/
837 837 o 2:261e70097290 B2
838 838 |
839 839 o 0:4a2df7238c3b A
840 840
841 841 $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.evolution=true
842 842 1 new obsolescence markers
843 843 obsoleted 1 changesets
844 844 1 new orphan changesets
845 845 $ hg rebase -d 6 -r "4::"
846 846 rebasing 4:ff2c4d47b71d "C"
847 847 note: not rebasing 7:360bbaa7d3ce "O", it has no successor
848 848 rebasing 8:8d47583e023f "P" (tip)
849 849
850 850 If all the changeset to be rebased are obsolete and present in the destination, we
851 851 should display a friendly error message
852 852
853 853 $ hg log -G
854 854 @ 10:121d9e3bc4c6 P
855 855 |
856 856 o 9:4be60e099a77 C
857 857 |
858 858 o 6:9c48361117de D
859 859 |
860 860 o 2:261e70097290 B2
861 861 |
862 862 o 0:4a2df7238c3b A
863 863
864 864
865 865 $ hg up 9
866 866 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
867 867 $ echo "non-relevant change" > nonrelevant
868 868 $ hg add nonrelevant
869 869 $ hg commit -m nonrelevant
870 870 created new head
871 871 $ hg debugobsolete `hg log -r 11 -T '{node}\n'` --config experimental.evolution=true
872 872 1 new obsolescence markers
873 873 obsoleted 1 changesets
874 874 $ hg log -G
875 875 @ 11:f44da1f4954c nonrelevant (pruned)
876 876 |
877 877 | o 10:121d9e3bc4c6 P
878 878 |/
879 879 o 9:4be60e099a77 C
880 880 |
881 881 o 6:9c48361117de D
882 882 |
883 883 o 2:261e70097290 B2
884 884 |
885 885 o 0:4a2df7238c3b A
886 886
887 887 $ hg rebase -r . -d 10
888 888 note: not rebasing 11:f44da1f4954c "nonrelevant" (tip), it has no successor
889 889
890 890 If a rebase is going to create divergence, it should abort
891 891
892 892 $ hg log -G
893 893 @ 10:121d9e3bc4c6 P
894 894 |
895 895 o 9:4be60e099a77 C
896 896 |
897 897 o 6:9c48361117de D
898 898 |
899 899 o 2:261e70097290 B2
900 900 |
901 901 o 0:4a2df7238c3b A
902 902
903 903
904 904 $ hg up 9
905 905 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
906 906 $ echo "john" > doe
907 907 $ hg add doe
908 908 $ hg commit -m "john doe"
909 909 created new head
910 910 $ hg up 10
911 911 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
912 912 $ echo "foo" > bar
913 913 $ hg add bar
914 914 $ hg commit --amend -m "10'"
915 915 $ hg up 10 --hidden
916 916 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
917 917 updated to hidden changeset 121d9e3bc4c6
918 918 (hidden revision '121d9e3bc4c6' was rewritten as: 77d874d096a2)
919 919 $ echo "bar" > foo
920 920 $ hg add foo
921 921 $ hg commit -m "bar foo"
922 922 1 new orphan changesets
923 923 $ hg log -G
924 924 @ 14:73568ab6879d bar foo
925 925 |
926 926 | o 13:77d874d096a2 10'
927 927 | |
928 928 | | o 12:3eb461388009 john doe
929 929 | |/
930 930 x | 10:121d9e3bc4c6 P (rewritten using amend as 13:77d874d096a2)
931 931 |/
932 932 o 9:4be60e099a77 C
933 933 |
934 934 o 6:9c48361117de D
935 935 |
936 936 o 2:261e70097290 B2
937 937 |
938 938 o 0:4a2df7238c3b A
939 939
940 940 $ hg summary
941 941 parent: 14:73568ab6879d tip (orphan)
942 942 bar foo
943 943 branch: default
944 944 commit: (clean)
945 945 update: 2 new changesets, 3 branch heads (merge)
946 946 phases: 8 draft
947 947 orphan: 1 changesets
948 948 $ hg rebase -s 10 -d 12
949 949 abort: this rebase will cause divergences from: 121d9e3bc4c6
950 950 (to force the rebase please set experimental.evolution.allowdivergence=True)
951 951 [255]
952 952 $ hg log -G
953 953 @ 14:73568ab6879d bar foo
954 954 |
955 955 | o 13:77d874d096a2 10'
956 956 | |
957 957 | | o 12:3eb461388009 john doe
958 958 | |/
959 959 x | 10:121d9e3bc4c6 P (rewritten using amend as 13:77d874d096a2)
960 960 |/
961 961 o 9:4be60e099a77 C
962 962 |
963 963 o 6:9c48361117de D
964 964 |
965 965 o 2:261e70097290 B2
966 966 |
967 967 o 0:4a2df7238c3b A
968 968
969 969 With experimental.evolution.allowdivergence=True, rebase can create divergence
970 970
971 971 $ hg rebase -s 10 -d 12 --config experimental.evolution.allowdivergence=True
972 972 rebasing 10:121d9e3bc4c6 "P"
973 973 rebasing 14:73568ab6879d "bar foo" (tip)
974 974 2 new content-divergent changesets
975 975 $ hg summary
976 976 parent: 16:61bd55f69bc4 tip
977 977 bar foo
978 978 branch: default
979 979 commit: (clean)
980 980 update: 1 new changesets, 2 branch heads (merge)
981 981 phases: 8 draft
982 982 content-divergent: 2 changesets
983 983
984 984 rebase --continue + skipped rev because their successors are in destination
985 985 we make a change in trunk and work on conflicting changes to make rebase abort.
986 986
987 987 $ hg log -G -r 16::
988 988 @ 16:61bd55f69bc4 bar foo
989 989 |
990 990 ~
991 991
992 992 Create the two changes in trunk
993 993 $ printf "a" > willconflict
994 994 $ hg add willconflict
995 995 $ hg commit -m "willconflict first version"
996 996
997 997 $ printf "dummy" > C
998 998 $ hg commit -m "dummy change successor"
999 999
1000 1000 Create the changes that we will rebase
1001 1001 $ hg update -C 16 -q
1002 1002 $ printf "b" > willconflict
1003 1003 $ hg add willconflict
1004 1004 $ hg commit -m "willconflict second version"
1005 1005 created new head
1006 1006 $ printf "dummy" > K
1007 1007 $ hg add K
1008 1008 $ hg commit -m "dummy change"
1009 1009 $ printf "dummy" > L
1010 1010 $ hg add L
1011 1011 $ hg commit -m "dummy change"
1012 1012 $ hg debugobsolete `hg log -r ".^" -T '{node}'` `hg log -r 18 -T '{node}'` --config experimental.evolution=true
1013 1013 1 new obsolescence markers
1014 1014 obsoleted 1 changesets
1015 1015 1 new orphan changesets
1016 1016
1017 1017 $ hg log -G -r 16::
1018 1018 @ 21:7bdc8a87673d dummy change
1019 1019 |
1020 1020 x 20:8b31da3c4919 dummy change (rewritten as 18:601db7a18f51)
1021 1021 |
1022 1022 o 19:b82fb57ea638 willconflict second version
1023 1023 |
1024 1024 | o 18:601db7a18f51 dummy change successor
1025 1025 | |
1026 1026 | o 17:357ddf1602d5 willconflict first version
1027 1027 |/
1028 1028 o 16:61bd55f69bc4 bar foo
1029 1029 |
1030 1030 ~
1031 1031 $ hg rebase -r ".^^ + .^ + ." -d 18
1032 1032 rebasing 19:b82fb57ea638 "willconflict second version"
1033 1033 merging willconflict
1034 1034 warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark')
1035 1035 unresolved conflicts (see hg resolve, then hg rebase --continue)
1036 1036 [1]
1037 1037
1038 1038 $ hg resolve --mark willconflict
1039 1039 (no more unresolved files)
1040 1040 continue: hg rebase --continue
1041 1041 $ hg rebase --continue
1042 1042 rebasing 19:b82fb57ea638 "willconflict second version"
1043 1043 note: not rebasing 20:8b31da3c4919 "dummy change", already in destination as 18:601db7a18f51 "dummy change successor"
1044 1044 rebasing 21:7bdc8a87673d "dummy change" (tip)
1045 1045 $ cd ..
1046 1046
1047 1047 Divergence cases due to obsolete changesets
1048 1048 -------------------------------------------
1049 1049
1050 1050 We should ignore branches with unstable changesets when they are based on an
1051 1051 obsolete changeset which successor is in rebase set.
1052 1052
1053 1053 $ hg init divergence
1054 1054 $ cd divergence
1055 1055 $ cat >> .hg/hgrc << EOF
1056 1056 > [extensions]
1057 1057 > strip =
1058 1058 > [alias]
1059 1059 > strip = strip --no-backup --quiet
1060 1060 > [templates]
1061 1061 > instabilities = '{rev}:{node|short} {desc|firstline}{if(instabilities," ({instabilities})")}\n'
1062 1062 > EOF
1063 1063
1064 1064 $ hg debugdrawdag <<EOF
1065 1065 > e f
1066 1066 > | |
1067 1067 > d' d # replace: d -> d'
1068 1068 > \ /
1069 1069 > c
1070 1070 > |
1071 1071 > x b
1072 1072 > \|
1073 1073 > a
1074 1074 > EOF
1075 1075 1 new orphan changesets
1076 1076 $ hg log -G -r 'a'::
1077 1077 * 7:1143e9adc121 f
1078 1078 |
1079 1079 | o 6:d60ebfa0f1cb e
1080 1080 | |
1081 1081 | o 5:027ad6c5830d d'
1082 1082 | |
1083 1083 x | 4:76be324c128b d (rewritten using replace as 5:027ad6c5830d)
1084 1084 |/
1085 1085 o 3:a82ac2b38757 c
1086 1086 |
1087 1087 | o 2:630d7c95eff7 x
1088 1088 | |
1089 1089 o | 1:488e1b7e7341 b
1090 1090 |/
1091 1091 o 0:b173517d0057 a
1092 1092
1093 1093
1094 1094 Changeset d and its descendants are excluded to avoid divergence of d, which
1095 1095 would occur because the successor of d (d') is also in rebaseset. As a
1096 1096 consequence f (descendant of d) is left behind.
1097 1097
1098 1098 $ hg rebase -b 'e' -d 'x'
1099 1099 rebasing 1:488e1b7e7341 "b" (b)
1100 1100 rebasing 3:a82ac2b38757 "c" (c)
1101 1101 rebasing 5:027ad6c5830d "d'" (d')
1102 1102 rebasing 6:d60ebfa0f1cb "e" (e)
1103 1103 note: not rebasing 4:76be324c128b "d" (d) and its descendants as this would cause divergence
1104 1104 $ hg log -G -r 'a'::
1105 1105 o 11:eb6d63fc4ed5 e
1106 1106 |
1107 1107 o 10:44d8c724a70c d'
1108 1108 |
1109 1109 o 9:d008e6b4d3fd c
1110 1110 |
1111 1111 o 8:67e8f4a16c49 b
1112 1112 |
1113 1113 | * 7:1143e9adc121 f
1114 1114 | |
1115 1115 | | x 6:d60ebfa0f1cb e (rewritten using rebase as 11:eb6d63fc4ed5)
1116 1116 | | |
1117 1117 | | x 5:027ad6c5830d d' (rewritten using rebase as 10:44d8c724a70c)
1118 1118 | | |
1119 1119 | x | 4:76be324c128b d (rewritten using replace as 5:027ad6c5830d)
1120 1120 | |/
1121 1121 | x 3:a82ac2b38757 c (rewritten using rebase as 9:d008e6b4d3fd)
1122 1122 | |
1123 1123 o | 2:630d7c95eff7 x
1124 1124 | |
1125 1125 | x 1:488e1b7e7341 b (rewritten using rebase as 8:67e8f4a16c49)
1126 1126 |/
1127 1127 o 0:b173517d0057 a
1128 1128
1129 1129 $ hg strip -r 8:
1130 1130 $ hg log -G -r 'a'::
1131 1131 * 7:1143e9adc121 f
1132 1132 |
1133 1133 | o 6:d60ebfa0f1cb e
1134 1134 | |
1135 1135 | o 5:027ad6c5830d d'
1136 1136 | |
1137 1137 x | 4:76be324c128b d (rewritten using replace as 5:027ad6c5830d)
1138 1138 |/
1139 1139 o 3:a82ac2b38757 c
1140 1140 |
1141 1141 | o 2:630d7c95eff7 x
1142 1142 | |
1143 1143 o | 1:488e1b7e7341 b
1144 1144 |/
1145 1145 o 0:b173517d0057 a
1146 1146
1147 1147
1148 1148 If the rebase set has an obsolete (d) with a successor (d') outside the rebase
1149 1149 set and none in destination, we still get the divergence warning.
1150 1150 By allowing divergence, we can perform the rebase.
1151 1151
1152 1152 $ hg rebase -r 'c'::'f' -d 'x'
1153 1153 abort: this rebase will cause divergences from: 76be324c128b
1154 1154 (to force the rebase please set experimental.evolution.allowdivergence=True)
1155 1155 [255]
1156 1156 $ hg rebase --config experimental.evolution.allowdivergence=true -r 'c'::'f' -d 'x'
1157 1157 rebasing 3:a82ac2b38757 "c" (c)
1158 1158 rebasing 4:76be324c128b "d" (d)
1159 1159 rebasing 7:1143e9adc121 "f" (f tip)
1160 1160 1 new orphan changesets
1161 1161 2 new content-divergent changesets
1162 1162 $ hg log -G -r 'a':: -T instabilities
1163 1163 o 10:e1744ea07510 f
1164 1164 |
1165 1165 * 9:e2b36ea9a0a0 d (content-divergent)
1166 1166 |
1167 1167 o 8:6a0376de376e c
1168 1168 |
1169 1169 | x 7:1143e9adc121 f
1170 1170 | |
1171 1171 | | * 6:d60ebfa0f1cb e (orphan)
1172 1172 | | |
1173 1173 | | * 5:027ad6c5830d d' (orphan content-divergent)
1174 1174 | | |
1175 1175 | x | 4:76be324c128b d
1176 1176 | |/
1177 1177 | x 3:a82ac2b38757 c
1178 1178 | |
1179 1179 o | 2:630d7c95eff7 x
1180 1180 | |
1181 1181 | o 1:488e1b7e7341 b
1182 1182 |/
1183 1183 o 0:b173517d0057 a
1184 1184
1185 1185 $ hg strip -r 8:
1186 1186
1187 1187 (Not skipping obsoletes means that divergence is allowed.)
1188 1188
1189 1189 $ hg rebase --config experimental.rebaseskipobsolete=false -r 'c'::'f' -d 'x'
1190 1190 rebasing 3:a82ac2b38757 "c" (c)
1191 1191 rebasing 4:76be324c128b "d" (d)
1192 1192 rebasing 7:1143e9adc121 "f" (f tip)
1193 1193 1 new orphan changesets
1194 1194 2 new content-divergent changesets
1195 1195
1196 1196 $ hg strip -r 0:
1197 1197
1198 1198 Similar test on a more complex graph
1199 1199
1200 1200 $ hg debugdrawdag <<EOF
1201 1201 > g
1202 1202 > |
1203 1203 > f e
1204 1204 > | |
1205 1205 > e' d # replace: e -> e'
1206 1206 > \ /
1207 1207 > c
1208 1208 > |
1209 1209 > x b
1210 1210 > \|
1211 1211 > a
1212 1212 > EOF
1213 1213 1 new orphan changesets
1214 1214 $ hg log -G -r 'a':
1215 1215 * 8:2876ce66c6eb g
1216 1216 |
1217 1217 | o 7:3ffec603ab53 f
1218 1218 | |
1219 1219 x | 6:e36fae928aec e (rewritten using replace as 5:63324dc512ea)
1220 1220 | |
1221 1221 | o 5:63324dc512ea e'
1222 1222 | |
1223 1223 o | 4:76be324c128b d
1224 1224 |/
1225 1225 o 3:a82ac2b38757 c
1226 1226 |
1227 1227 | o 2:630d7c95eff7 x
1228 1228 | |
1229 1229 o | 1:488e1b7e7341 b
1230 1230 |/
1231 1231 o 0:b173517d0057 a
1232 1232
1233 1233 $ hg rebase -b 'f' -d 'x'
1234 1234 rebasing 1:488e1b7e7341 "b" (b)
1235 1235 rebasing 3:a82ac2b38757 "c" (c)
1236 1236 rebasing 5:63324dc512ea "e'" (e')
1237 1237 rebasing 7:3ffec603ab53 "f" (f)
1238 1238 rebasing 4:76be324c128b "d" (d)
1239 1239 note: not rebasing 6:e36fae928aec "e" (e) and its descendants as this would cause divergence
1240 1240 $ hg log -G -r 'a':
1241 1241 o 13:a1707a5b7c2c d
1242 1242 |
1243 1243 | o 12:ef6251596616 f
1244 1244 | |
1245 1245 | o 11:b6f172e64af9 e'
1246 1246 |/
1247 1247 o 10:d008e6b4d3fd c
1248 1248 |
1249 1249 o 9:67e8f4a16c49 b
1250 1250 |
1251 1251 | * 8:2876ce66c6eb g
1252 1252 | |
1253 1253 | | x 7:3ffec603ab53 f (rewritten using rebase as 12:ef6251596616)
1254 1254 | | |
1255 1255 | x | 6:e36fae928aec e (rewritten using replace as 5:63324dc512ea)
1256 1256 | | |
1257 1257 | | x 5:63324dc512ea e' (rewritten using rebase as 11:b6f172e64af9)
1258 1258 | | |
1259 1259 | x | 4:76be324c128b d (rewritten using rebase as 13:a1707a5b7c2c)
1260 1260 | |/
1261 1261 | x 3:a82ac2b38757 c (rewritten using rebase as 10:d008e6b4d3fd)
1262 1262 | |
1263 1263 o | 2:630d7c95eff7 x
1264 1264 | |
1265 1265 | x 1:488e1b7e7341 b (rewritten using rebase as 9:67e8f4a16c49)
1266 1266 |/
1267 1267 o 0:b173517d0057 a
1268 1268
1269 1269
1270 1270 issue5782
1271 1271 $ hg strip -r 0:
1272 1272 $ hg debugdrawdag <<EOF
1273 1273 > d
1274 1274 > |
1275 1275 > c1 c # replace: c -> c1
1276 1276 > \ /
1277 1277 > b
1278 1278 > |
1279 1279 > a
1280 1280 > EOF
1281 1281 1 new orphan changesets
1282 1282 $ hg debugobsolete `hg log -T "{node}" --hidden -r 'desc("c1")'`
1283 1283 1 new obsolescence markers
1284 1284 obsoleted 1 changesets
1285 1285 $ hg log -G -r 'a': --hidden
1286 1286 * 4:76be324c128b d
1287 1287 |
1288 1288 | x 3:ef8a456de8fa c1 (pruned)
1289 1289 | |
1290 1290 x | 2:a82ac2b38757 c (rewritten using replace as 3:ef8a456de8fa)
1291 1291 |/
1292 1292 o 1:488e1b7e7341 b
1293 1293 |
1294 1294 o 0:b173517d0057 a
1295 1295
1296 1296 $ hg rebase -d 0 -r 2
1297 1297 rebasing 2:a82ac2b38757 "c" (c)
1298 1298 $ hg log -G -r 'a': --hidden
1299 1299 o 5:69ad416a4a26 c
1300 1300 |
1301 1301 | * 4:76be324c128b d
1302 1302 | |
1303 1303 | | x 3:ef8a456de8fa c1 (pruned)
1304 1304 | | |
1305 1305 | x | 2:a82ac2b38757 c (rewritten using replace as 3:ef8a456de8fa rewritten using rebase as 5:69ad416a4a26)
1306 1306 | |/
1307 1307 | o 1:488e1b7e7341 b
1308 1308 |/
1309 1309 o 0:b173517d0057 a
1310 1310
1311 1311 $ cd ..
1312 1312
1313 1313 Rebase merge where successor of one parent is equal to destination (issue5198)
1314 1314
1315 1315 $ hg init p1-succ-is-dest
1316 1316 $ cd p1-succ-is-dest
1317 1317
1318 1318 $ hg debugdrawdag <<EOF
1319 1319 > F
1320 1320 > /|
1321 1321 > E D B # replace: D -> B
1322 1322 > \|/
1323 1323 > A
1324 1324 > EOF
1325 1325 1 new orphan changesets
1326 1326
1327 1327 $ hg rebase -d B -s D
1328 1328 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B" (B)
1329 1329 rebasing 4:66f1a38021c9 "F" (F tip)
1330 1330 $ hg log -G
1331 1331 o 5:50e9d60b99c6 F
1332 1332 |\
1333 1333 | | x 4:66f1a38021c9 F (rewritten using rebase as 5:50e9d60b99c6)
1334 1334 | |/|
1335 1335 | o | 3:7fb047a69f22 E
1336 1336 | | |
1337 1337 | | x 2:b18e25de2cf5 D (rewritten using replace as 1:112478962961)
1338 1338 | |/
1339 1339 o | 1:112478962961 B
1340 1340 |/
1341 1341 o 0:426bada5c675 A
1342 1342
1343 1343 $ cd ..
1344 1344
1345 1345 Rebase merge where successor of other parent is equal to destination
1346 1346
1347 1347 $ hg init p2-succ-is-dest
1348 1348 $ cd p2-succ-is-dest
1349 1349
1350 1350 $ hg debugdrawdag <<EOF
1351 1351 > F
1352 1352 > /|
1353 1353 > E D B # replace: E -> B
1354 1354 > \|/
1355 1355 > A
1356 1356 > EOF
1357 1357 1 new orphan changesets
1358 1358
1359 1359 $ hg rebase -d B -s E
1360 1360 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B" (B)
1361 1361 rebasing 4:66f1a38021c9 "F" (F tip)
1362 1362 $ hg log -G
1363 1363 o 5:aae1787dacee F
1364 1364 |\
1365 1365 | | x 4:66f1a38021c9 F (rewritten using rebase as 5:aae1787dacee)
1366 1366 | |/|
1367 1367 | | x 3:7fb047a69f22 E (rewritten using replace as 1:112478962961)
1368 1368 | | |
1369 1369 | o | 2:b18e25de2cf5 D
1370 1370 | |/
1371 1371 o / 1:112478962961 B
1372 1372 |/
1373 1373 o 0:426bada5c675 A
1374 1374
1375 1375 $ cd ..
1376 1376
1377 1377 Rebase merge where successor of one parent is ancestor of destination
1378 1378
1379 1379 $ hg init p1-succ-in-dest
1380 1380 $ cd p1-succ-in-dest
1381 1381
1382 1382 $ hg debugdrawdag <<EOF
1383 1383 > F C
1384 1384 > /| |
1385 1385 > E D B # replace: D -> B
1386 1386 > \|/
1387 1387 > A
1388 1388 > EOF
1389 1389 1 new orphan changesets
1390 1390
1391 1391 $ hg rebase -d C -s D
1392 1392 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B" (B)
1393 1393 rebasing 5:66f1a38021c9 "F" (F tip)
1394 1394
1395 1395 $ hg log -G
1396 1396 o 6:0913febf6439 F
1397 1397 |\
1398 1398 +---x 5:66f1a38021c9 F (rewritten using rebase as 6:0913febf6439)
1399 1399 | | |
1400 1400 | o | 4:26805aba1e60 C
1401 1401 | | |
1402 1402 o | | 3:7fb047a69f22 E
1403 1403 | | |
1404 1404 +---x 2:b18e25de2cf5 D (rewritten using replace as 1:112478962961)
1405 1405 | |
1406 1406 | o 1:112478962961 B
1407 1407 |/
1408 1408 o 0:426bada5c675 A
1409 1409
1410 1410 $ cd ..
1411 1411
1412 1412 Rebase merge where successor of other parent is ancestor of destination
1413 1413
1414 1414 $ hg init p2-succ-in-dest
1415 1415 $ cd p2-succ-in-dest
1416 1416
1417 1417 $ hg debugdrawdag <<EOF
1418 1418 > F C
1419 1419 > /| |
1420 1420 > E D B # replace: E -> B
1421 1421 > \|/
1422 1422 > A
1423 1423 > EOF
1424 1424 1 new orphan changesets
1425 1425
1426 1426 $ hg rebase -d C -s E
1427 1427 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B" (B)
1428 1428 rebasing 5:66f1a38021c9 "F" (F tip)
1429 1429 $ hg log -G
1430 1430 o 6:c6ab0cc6d220 F
1431 1431 |\
1432 1432 +---x 5:66f1a38021c9 F (rewritten using rebase as 6:c6ab0cc6d220)
1433 1433 | | |
1434 1434 | o | 4:26805aba1e60 C
1435 1435 | | |
1436 1436 | | x 3:7fb047a69f22 E (rewritten using replace as 1:112478962961)
1437 1437 | | |
1438 1438 o---+ 2:b18e25de2cf5 D
1439 1439 / /
1440 1440 o / 1:112478962961 B
1441 1441 |/
1442 1442 o 0:426bada5c675 A
1443 1443
1444 1444 $ cd ..
1445 1445
1446 1446 Rebase merge where successor of one parent is ancestor of destination
1447 1447
1448 1448 $ hg init p1-succ-in-dest-b
1449 1449 $ cd p1-succ-in-dest-b
1450 1450
1451 1451 $ hg debugdrawdag <<EOF
1452 1452 > F C
1453 1453 > /| |
1454 1454 > E D B # replace: E -> B
1455 1455 > \|/
1456 1456 > A
1457 1457 > EOF
1458 1458 1 new orphan changesets
1459 1459
1460 1460 $ hg rebase -d C -b F
1461 1461 rebasing 2:b18e25de2cf5 "D" (D)
1462 1462 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B" (B)
1463 1463 rebasing 5:66f1a38021c9 "F" (F tip)
1464 1464 note: not rebasing 5:66f1a38021c9 "F" (F tip), its destination already has all its changes
1465 1465 $ hg log -G
1466 1466 o 6:8f47515dda15 D
1467 1467 |
1468 1468 | x 5:66f1a38021c9 F (pruned using rebase)
1469 1469 | |\
1470 1470 o | | 4:26805aba1e60 C
1471 1471 | | |
1472 1472 | | x 3:7fb047a69f22 E (rewritten using replace as 1:112478962961)
1473 1473 | | |
1474 1474 | x | 2:b18e25de2cf5 D (rewritten using rebase as 6:8f47515dda15)
1475 1475 | |/
1476 1476 o / 1:112478962961 B
1477 1477 |/
1478 1478 o 0:426bada5c675 A
1479 1479
1480 1480 $ cd ..
1481 1481
1482 1482 Rebase merge where successor of other parent is ancestor of destination
1483 1483
1484 1484 $ hg init p2-succ-in-dest-b
1485 1485 $ cd p2-succ-in-dest-b
1486 1486
1487 1487 $ hg debugdrawdag <<EOF
1488 1488 > F C
1489 1489 > /| |
1490 1490 > E D B # replace: D -> B
1491 1491 > \|/
1492 1492 > A
1493 1493 > EOF
1494 1494 1 new orphan changesets
1495 1495
1496 1496 $ hg rebase -d C -b F
1497 1497 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B" (B)
1498 1498 rebasing 3:7fb047a69f22 "E" (E)
1499 1499 rebasing 5:66f1a38021c9 "F" (F tip)
1500 1500 note: not rebasing 5:66f1a38021c9 "F" (F tip), its destination already has all its changes
1501 1501
1502 1502 $ hg log -G
1503 1503 o 6:533690786a86 E
1504 1504 |
1505 1505 | x 5:66f1a38021c9 F (pruned using rebase)
1506 1506 | |\
1507 1507 o | | 4:26805aba1e60 C
1508 1508 | | |
1509 1509 | | x 3:7fb047a69f22 E (rewritten using rebase as 6:533690786a86)
1510 1510 | | |
1511 1511 | x | 2:b18e25de2cf5 D (rewritten using replace as 1:112478962961)
1512 1512 | |/
1513 1513 o / 1:112478962961 B
1514 1514 |/
1515 1515 o 0:426bada5c675 A
1516 1516
1517 1517 $ cd ..
1518 1518
1519 1519 Rebase merge where extinct node has successor that is not an ancestor of
1520 1520 destination
1521 1521
1522 1522 $ hg init extinct-with-succ-not-in-dest
1523 1523 $ cd extinct-with-succ-not-in-dest
1524 1524
1525 1525 $ hg debugdrawdag <<EOF
1526 1526 > E C # replace: C -> E
1527 1527 > | |
1528 1528 > D B
1529 1529 > |/
1530 1530 > A
1531 1531 > EOF
1532 1532
1533 1533 $ hg rebase -d D -s B
1534 1534 rebasing 1:112478962961 "B" (B)
1535 1535 note: not rebasing 3:26805aba1e60 "C" (C) and its descendants as this would cause divergence
1536 1536
1537 1537 $ cd ..
1538 1538
1539 1539 $ hg init p2-succ-in-dest-c
1540 1540 $ cd p2-succ-in-dest-c
1541 1541
1542 1542 The scenario here was that B::D were developed on default. B was queued on
1543 1543 stable, but amended before being push to hg-committed. C was queued on default,
1544 1544 along with unrelated J.
1545 1545
1546 1546 $ hg debugdrawdag <<EOF
1547 1547 > J
1548 1548 > |
1549 1549 > F
1550 1550 > |
1551 1551 > E
1552 1552 > | D
1553 1553 > | |
1554 1554 > | C # replace: C -> F
1555 1555 > | | H I # replace: B -> H -> I
1556 1556 > | B |/
1557 1557 > |/ G
1558 1558 > A
1559 1559 > EOF
1560 1560 1 new orphan changesets
1561 1561
1562 1562 This strip seems to be the key to avoid an early divergence warning.
1563 1563 $ hg --config extensions.strip= --hidden strip -qr H
1564 1564 1 new orphan changesets
1565 1565
1566 1566 $ hg rebase -b 'desc("D")' -d 'desc("J")'
1567 1567 abort: this rebase will cause divergences from: 112478962961
1568 1568 (to force the rebase please set experimental.evolution.allowdivergence=True)
1569 1569 [255]
1570 1570
1571 1571 Rebase merge where both parents have successors in destination
1572 1572
1573 1573 $ hg init p12-succ-in-dest
1574 1574 $ cd p12-succ-in-dest
1575 1575 $ hg debugdrawdag <<'EOS'
1576 1576 > E F
1577 1577 > /| /| # replace: A -> C
1578 1578 > A B C D # replace: B -> D
1579 1579 > | |
1580 1580 > X Y
1581 1581 > EOS
1582 1582 1 new orphan changesets
1583 1583 $ hg rebase -r A+B+E -d F
1584 1584 note: not rebasing 4:a3d17304151f "A" (A), already in destination as 0:96cc3511f894 "C" (C)
1585 1585 note: not rebasing 5:b23a2cc00842 "B" (B), already in destination as 1:058c1e1fb10a "D" (D)
1586 1586 rebasing 7:dac5d11c5a7d "E" (E tip)
1587 1587 abort: rebasing 7:dac5d11c5a7d will include unwanted changes from 3:59c792af609c, 5:b23a2cc00842 or 2:ba2b7fa7166d, 4:a3d17304151f
1588 1588 [255]
1589 1589 $ cd ..
1590 1590
1591 1591 Rebase a non-clean merge. One parent has successor in destination, the other
1592 1592 parent moves as requested.
1593 1593
1594 1594 $ hg init p1-succ-p2-move
1595 1595 $ cd p1-succ-p2-move
1596 1596 $ hg debugdrawdag <<'EOS'
1597 1597 > D Z
1598 1598 > /| | # replace: A -> C
1599 1599 > A B C # D/D = D
1600 1600 > EOS
1601 1601 1 new orphan changesets
1602 1602 $ hg rebase -r A+B+D -d Z
1603 1603 note: not rebasing 0:426bada5c675 "A" (A), already in destination as 2:96cc3511f894 "C" (C)
1604 1604 rebasing 1:fc2b737bb2e5 "B" (B)
1605 1605 rebasing 3:b8ed089c80ad "D" (D)
1606 1606
1607 1607 $ rm .hg/localtags
1608 1608 $ hg log -G
1609 1609 o 6:e4f78693cc88 D
1610 1610 |
1611 1611 o 5:76840d832e98 B
1612 1612 |
1613 1613 o 4:50e41c1f3950 Z
1614 1614 |
1615 1615 o 2:96cc3511f894 C
1616 1616
1617 1617 $ hg files -r tip
1618 1618 B
1619 1619 C
1620 1620 D
1621 1621 Z
1622 1622
1623 1623 $ cd ..
1624 1624
1625 1625 $ hg init p1-move-p2-succ
1626 1626 $ cd p1-move-p2-succ
1627 1627 $ hg debugdrawdag <<'EOS'
1628 1628 > D Z
1629 1629 > /| | # replace: B -> C
1630 1630 > A B C # D/D = D
1631 1631 > EOS
1632 1632 1 new orphan changesets
1633 1633 $ hg rebase -r B+A+D -d Z
1634 1634 rebasing 0:426bada5c675 "A" (A)
1635 1635 note: not rebasing 1:fc2b737bb2e5 "B" (B), already in destination as 2:96cc3511f894 "C" (C)
1636 1636 rebasing 3:b8ed089c80ad "D" (D)
1637 1637
1638 1638 $ rm .hg/localtags
1639 1639 $ hg log -G
1640 1640 o 6:1b355ed94d82 D
1641 1641 |
1642 1642 o 5:a81a74d764a6 A
1643 1643 |
1644 1644 o 4:50e41c1f3950 Z
1645 1645 |
1646 1646 o 2:96cc3511f894 C
1647 1647
1648 1648 $ hg files -r tip
1649 1649 A
1650 1650 C
1651 1651 D
1652 1652 Z
1653 1653
1654 1654 $ cd ..
1655 1655
1656 1656 Test that bookmark is moved and working dir is updated when all changesets have
1657 1657 equivalents in destination
1658 1658 $ hg init rbsrepo && cd rbsrepo
1659 1659 $ echo "[experimental]" > .hg/hgrc
1660 1660 $ echo "evolution=true" >> .hg/hgrc
1661 1661 $ echo "rebaseskipobsolete=on" >> .hg/hgrc
1662 1662 $ echo root > root && hg ci -Am root
1663 1663 adding root
1664 1664 $ echo a > a && hg ci -Am a
1665 1665 adding a
1666 1666 $ hg up 0
1667 1667 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1668 1668 $ echo b > b && hg ci -Am b
1669 1669 adding b
1670 1670 created new head
1671 1671 $ hg rebase -r 2 -d 1
1672 1672 rebasing 2:1e9a3c00cbe9 "b" (tip)
1673 1673 $ hg log -r . # working dir is at rev 3 (successor of 2)
1674 1674 3:be1832deae9a b (no-eol)
1675 1675 $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now
1676 1676 bookmarking hidden changeset 1e9a3c00cbe9
1677 1677 (hidden revision '1e9a3c00cbe9' was rewritten as: be1832deae9a)
1678 1678 $ hg up 2 && hg log -r . # working dir is at rev 2 again
1679 1679 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1680 1680 2:1e9a3c00cbe9 b (rewritten using rebase as 3:be1832deae9a) (no-eol)
1681 1681 $ hg rebase -r 2 -d 3 --config experimental.evolution.track-operation=1
1682 1682 note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b" (tip)
1683 1683 Check that working directory and bookmark was updated to rev 3 although rev 2
1684 1684 was skipped
1685 1685 $ hg log -r .
1686 1686 3:be1832deae9a b (no-eol)
1687 1687 $ hg bookmarks
1688 1688 mybook 3:be1832deae9a
1689 1689 $ hg debugobsolete --rev tip
1690 1690 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'}
1691 1691
1692 1692 Obsoleted working parent and bookmark could be moved if an ancestor of working
1693 1693 parent gets moved:
1694 1694
1695 1695 $ hg init $TESTTMP/ancestor-wd-move
1696 1696 $ cd $TESTTMP/ancestor-wd-move
1697 1697 $ hg debugdrawdag <<'EOS'
1698 1698 > E D1 # rebase: D1 -> D2
1699 1699 > | |
1700 1700 > | C
1701 1701 > D2 |
1702 1702 > | B
1703 1703 > |/
1704 1704 > A
1705 1705 > EOS
1706 1706 $ hg update D1 -q
1707 1707 $ hg bookmark book -i
1708 1708 $ hg rebase -r B+D1 -d E
1709 1709 rebasing 1:112478962961 "B" (B)
1710 1710 note: not rebasing 5:15ecf15e0114 "D1" (book D1 tip), already in destination as 2:0807738e0be9 "D2" (D2)
1711 1711 1 new orphan changesets
1712 1712 $ hg log -G -T '{desc} {bookmarks}'
1713 1713 @ B book
1714 1714 |
1715 1715 | x D1
1716 1716 | |
1717 1717 o | E
1718 1718 | |
1719 1719 | * C
1720 1720 | |
1721 1721 o | D2
1722 1722 | |
1723 1723 | x B
1724 1724 |/
1725 1725 o A
1726 1726
1727 1727 Rebasing a merge with one of its parent having a hidden successor
1728 1728
1729 1729 $ hg init $TESTTMP/merge-p1-hidden-successor
1730 1730 $ cd $TESTTMP/merge-p1-hidden-successor
1731 1731
1732 1732 $ hg debugdrawdag <<'EOS'
1733 1733 > E
1734 1734 > |
1735 1735 > B3 B2 # amend: B1 -> B2 -> B3
1736 1736 > |/ # B2 is hidden
1737 1737 > | D
1738 1738 > | |\
1739 1739 > | B1 C
1740 1740 > |/
1741 1741 > A
1742 1742 > EOS
1743 1743 1 new orphan changesets
1744 1744
1745 1745 $ eval `hg tags -T '{tag}={node}\n'`
1746 1746 $ rm .hg/localtags
1747 1747
1748 1748 $ hg rebase -r $D -d $E
1749 1749 rebasing 5:9e62094e4d94 "D"
1750 1750
1751 1751 $ hg log -G
1752 1752 o 7:a699d059adcf D
1753 1753 |\
1754 1754 | o 6:ecc93090a95c E
1755 1755 | |
1756 1756 | o 4:0dc878468a23 B3
1757 1757 | |
1758 1758 o | 1:96cc3511f894 C
1759 1759 /
1760 1760 o 0:426bada5c675 A
1761 1761
1762 1762 For some reasons (--hidden, rebaseskipobsolete=0, directaccess, etc.),
1763 1763 rebasestate may contain hidden hashes. "rebase --abort" should work regardless.
1764 1764
1765 1765 $ hg init $TESTTMP/hidden-state1
1766 1766 $ cd $TESTTMP/hidden-state1
1767 1767 $ cat >> .hg/hgrc <<EOF
1768 1768 > [experimental]
1769 1769 > rebaseskipobsolete=0
1770 1770 > EOF
1771 1771
1772 1772 $ hg debugdrawdag <<'EOS'
1773 1773 > C
1774 1774 > |
1775 1775 > D B # prune: B, C
1776 1776 > |/ # B/D=B
1777 1777 > A
1778 1778 > EOS
1779 1779
1780 1780 $ eval `hg tags -T '{tag}={node}\n'`
1781 1781 $ rm .hg/localtags
1782 1782
1783 1783 $ hg update -q $C --hidden
1784 1784 updated to hidden changeset 7829726be4dc
1785 1785 (hidden revision '7829726be4dc' is pruned)
1786 1786 $ hg rebase -s $B -d $D
1787 1787 rebasing 1:2ec65233581b "B"
1788 1788 merging D
1789 1789 warning: conflicts while merging D! (edit, then use 'hg resolve --mark')
1790 1790 unresolved conflicts (see hg resolve, then hg rebase --continue)
1791 1791 [1]
1792 1792
1793 1793 $ cp -R . $TESTTMP/hidden-state2
1794 1794
1795 1795 $ hg log -G
1796 1796 @ 2:b18e25de2cf5 D
1797 1797 |
1798 1798 | @ 1:2ec65233581b B (pruned using prune)
1799 1799 |/
1800 1800 o 0:426bada5c675 A
1801 1801
1802 1802 $ hg summary
1803 1803 parent: 2:b18e25de2cf5 tip
1804 1804 D
1805 1805 parent: 1:2ec65233581b (obsolete)
1806 1806 B
1807 1807 branch: default
1808 1808 commit: 2 modified, 1 unknown, 1 unresolved (merge)
1809 1809 update: (current)
1810 1810 phases: 3 draft
1811 1811 rebase: 0 rebased, 2 remaining (rebase --continue)
1812 1812
1813 1813 $ hg rebase --abort
1814 1814 rebase aborted
1815 1815
1816 1816 Also test --continue for the above case
1817 1817
1818 1818 $ cd $TESTTMP/hidden-state2
1819 1819 $ hg resolve -m
1820 1820 (no more unresolved files)
1821 1821 continue: hg rebase --continue
1822 1822 $ hg rebase --continue
1823 1823 rebasing 1:2ec65233581b "B"
1824 1824 rebasing 3:7829726be4dc "C" (tip)
1825 1825 $ hg log -G
1826 1826 @ 5:1964d5d5b547 C
1827 1827 |
1828 1828 o 4:68deb90c12a2 B
1829 1829 |
1830 1830 o 2:b18e25de2cf5 D
1831 1831 |
1832 1832 o 0:426bada5c675 A
1833 1833
1834 1834 ====================
1835 1835 Test --stop option |
1836 1836 ====================
1837 1837 $ cd ..
1838 1838 $ hg init rbstop
1839 1839 $ cd rbstop
1840 1840 $ echo a>a
1841 1841 $ hg ci -Aqma
1842 1842 $ echo b>b
1843 1843 $ hg ci -Aqmb
1844 1844 $ echo c>c
1845 1845 $ hg ci -Aqmc
1846 1846 $ echo d>d
1847 1847 $ hg ci -Aqmd
1848 1848 $ hg up 0 -q
1849 1849 $ echo f>f
1850 1850 $ hg ci -Aqmf
1851 1851 $ echo D>d
1852 1852 $ hg ci -Aqm "conflict with d"
1853 1853 $ hg up 3 -q
1854 1854 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
1855 1855 o 5:00bfc9898aeb test
1856 1856 | conflict with d
1857 1857 |
1858 1858 o 4:dafd40200f93 test
1859 1859 | f
1860 1860 |
1861 1861 | @ 3:055a42cdd887 test
1862 1862 | | d
1863 1863 | |
1864 1864 | o 2:177f92b77385 test
1865 1865 | | c
1866 1866 | |
1867 1867 | o 1:d2ae7f538514 test
1868 1868 |/ b
1869 1869 |
1870 1870 o 0:cb9a9f314b8b test
1871 1871 a
1872 1872
1873 1873 $ hg rebase -s 1 -d 5
1874 1874 rebasing 1:d2ae7f538514 "b"
1875 1875 rebasing 2:177f92b77385 "c"
1876 1876 rebasing 3:055a42cdd887 "d"
1877 1877 merging d
1878 1878 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
1879 1879 unresolved conflicts (see hg resolve, then hg rebase --continue)
1880 1880 [1]
1881 1881 $ hg rebase --stop
1882 1882 1 new orphan changesets
1883 1883 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
1884 1884 o 7:7fffad344617 test
1885 1885 | c
1886 1886 |
1887 1887 o 6:b15528633407 test
1888 1888 | b
1889 1889 |
1890 1890 o 5:00bfc9898aeb test
1891 1891 | conflict with d
1892 1892 |
1893 1893 o 4:dafd40200f93 test
1894 1894 | f
1895 1895 |
1896 1896 | @ 3:055a42cdd887 test
1897 1897 | | d
1898 1898 | |
1899 1899 | x 2:177f92b77385 test
1900 1900 | | c
1901 1901 | |
1902 1902 | x 1:d2ae7f538514 test
1903 1903 |/ b
1904 1904 |
1905 1905 o 0:cb9a9f314b8b test
1906 1906 a
1907 1907
1908 1908 Test it aborts if unstable csets is not allowed:
1909 1909 ===============================================
1910 1910 $ cat >> $HGRCPATH << EOF
1911 1911 > [experimental]
1912 1912 > evolution.allowunstable=False
1913 1913 > EOF
1914 1914
1915 1915 $ hg strip 6 --no-backup -q
1916 1916 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
1917 1917 o 5:00bfc9898aeb test
1918 1918 | conflict with d
1919 1919 |
1920 1920 o 4:dafd40200f93 test
1921 1921 | f
1922 1922 |
1923 1923 | @ 3:055a42cdd887 test
1924 1924 | | d
1925 1925 | |
1926 1926 | o 2:177f92b77385 test
1927 1927 | | c
1928 1928 | |
1929 1929 | o 1:d2ae7f538514 test
1930 1930 |/ b
1931 1931 |
1932 1932 o 0:cb9a9f314b8b test
1933 1933 a
1934 1934
1935 1935 $ hg rebase -s 1 -d 5
1936 1936 rebasing 1:d2ae7f538514 "b"
1937 1937 rebasing 2:177f92b77385 "c"
1938 1938 rebasing 3:055a42cdd887 "d"
1939 1939 merging d
1940 1940 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
1941 1941 unresolved conflicts (see hg resolve, then hg rebase --continue)
1942 1942 [1]
1943 1943 $ hg rebase --stop
1944 1944 abort: cannot remove original changesets with unrebased descendants
1945 1945 (either enable obsmarkers to allow unstable revisions or use --keep to keep original changesets)
1946 1946 [255]
1947 1947 $ hg rebase --abort
1948 1948 saved backup bundle to $TESTTMP/rbstop/.hg/strip-backup/b15528633407-6eb72b6f-backup.hg
1949 1949 rebase aborted
1950 1950
1951 1951 Test --stop when --keep is passed:
1952 1952 ==================================
1953 1953 $ hg rebase -s 1 -d 5 --keep
1954 1954 rebasing 1:d2ae7f538514 "b"
1955 1955 rebasing 2:177f92b77385 "c"
1956 1956 rebasing 3:055a42cdd887 "d"
1957 1957 merging d
1958 1958 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
1959 1959 unresolved conflicts (see hg resolve, then hg rebase --continue)
1960 1960 [1]
1961 1961 $ hg rebase --stop
1962 1962 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
1963 1963 o 7:7fffad344617 test
1964 1964 | c
1965 1965 |
1966 1966 o 6:b15528633407 test
1967 1967 | b
1968 1968 |
1969 1969 o 5:00bfc9898aeb test
1970 1970 | conflict with d
1971 1971 |
1972 1972 o 4:dafd40200f93 test
1973 1973 | f
1974 1974 |
1975 1975 | @ 3:055a42cdd887 test
1976 1976 | | d
1977 1977 | |
1978 1978 | o 2:177f92b77385 test
1979 1979 | | c
1980 1980 | |
1981 1981 | o 1:d2ae7f538514 test
1982 1982 |/ b
1983 1983 |
1984 1984 o 0:cb9a9f314b8b test
1985 1985 a
1986 1986
1987 1987 Test --stop aborts when --collapse was passed:
1988 1988 =============================================
1989 1989 $ cat >> $HGRCPATH << EOF
1990 1990 > [experimental]
1991 1991 > evolution.allowunstable=True
1992 1992 > EOF
1993 1993
1994 1994 $ hg strip 6
1995 1995 saved backup bundle to $TESTTMP/rbstop/.hg/strip-backup/b15528633407-6eb72b6f-backup.hg
1996 1996 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
1997 1997 o 5:00bfc9898aeb test
1998 1998 | conflict with d
1999 1999 |
2000 2000 o 4:dafd40200f93 test
2001 2001 | f
2002 2002 |
2003 2003 | @ 3:055a42cdd887 test
2004 2004 | | d
2005 2005 | |
2006 2006 | o 2:177f92b77385 test
2007 2007 | | c
2008 2008 | |
2009 2009 | o 1:d2ae7f538514 test
2010 2010 |/ b
2011 2011 |
2012 2012 o 0:cb9a9f314b8b test
2013 2013 a
2014 2014
2015 2015 $ hg rebase -s 1 -d 5 --collapse -m "collapsed b c d"
2016 2016 rebasing 1:d2ae7f538514 "b"
2017 2017 rebasing 2:177f92b77385 "c"
2018 2018 rebasing 3:055a42cdd887 "d"
2019 2019 merging d
2020 2020 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
2021 2021 unresolved conflicts (see hg resolve, then hg rebase --continue)
2022 2022 [1]
2023 2023 $ hg rebase --stop
2024 2024 abort: cannot stop in --collapse session
2025 2025 [255]
2026 2026 $ hg rebase --abort
2027 2027 rebase aborted
2028 2028 $ hg diff
2029 2029 $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
2030 2030 o 5:00bfc9898aeb test
2031 2031 | conflict with d
2032 2032 |
2033 2033 o 4:dafd40200f93 test
2034 2034 | f
2035 2035 |
2036 2036 | @ 3:055a42cdd887 test
2037 2037 | | d
2038 2038 | |
2039 2039 | o 2:177f92b77385 test
2040 2040 | | c
2041 2041 | |
2042 2042 | o 1:d2ae7f538514 test
2043 2043 |/ b
2044 2044 |
2045 2045 o 0:cb9a9f314b8b test
2046 2046 a
2047 2047
2048 2048 Test --stop raise errors with conflicting options:
2049 2049 =================================================
2050 2050 $ hg rebase -s 3 -d 5
2051 2051 rebasing 3:055a42cdd887 "d"
2052 2052 merging d
2053 2053 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
2054 2054 unresolved conflicts (see hg resolve, then hg rebase --continue)
2055 2055 [1]
2056 2056 $ hg rebase --stop --dry-run
2057 abort: cannot specify both --dry-run and --stop
2057 abort: cannot specify both --stop and --dry-run
2058 2058 [255]
2059 2059
2060 2060 $ hg rebase -s 3 -d 5
2061 2061 abort: rebase in progress
2062 2062 (use 'hg rebase --continue' or 'hg rebase --abort')
2063 2063 [255]
2064 2064 $ hg rebase --stop --continue
2065 2065 abort: cannot specify both --stop and --continue
2066 2066 [255]
2067 2067
2068 2068 Test --stop moves bookmarks of original revisions to new rebased nodes:
2069 2069 ======================================================================
2070 2070 $ cd ..
2071 2071 $ hg init repo
2072 2072 $ cd repo
2073 2073
2074 2074 $ echo a > a
2075 2075 $ hg ci -Am A
2076 2076 adding a
2077 2077
2078 2078 $ echo b > b
2079 2079 $ hg ci -Am B
2080 2080 adding b
2081 2081 $ hg book X
2082 2082 $ hg book Y
2083 2083
2084 2084 $ echo c > c
2085 2085 $ hg ci -Am C
2086 2086 adding c
2087 2087 $ hg book Z
2088 2088
2089 2089 $ echo d > d
2090 2090 $ hg ci -Am D
2091 2091 adding d
2092 2092
2093 2093 $ hg up 0 -q
2094 2094 $ echo e > e
2095 2095 $ hg ci -Am E
2096 2096 adding e
2097 2097 created new head
2098 2098
2099 2099 $ echo doubt > d
2100 2100 $ hg ci -Am "conflict with d"
2101 2101 adding d
2102 2102
2103 2103 $ hg log -GT "{rev}: {node|short} '{desc}' bookmarks: {bookmarks}\n"
2104 2104 @ 5: 39adf30bc1be 'conflict with d' bookmarks:
2105 2105 |
2106 2106 o 4: 9c1e55f411b6 'E' bookmarks:
2107 2107 |
2108 2108 | o 3: 67a385d4e6f2 'D' bookmarks: Z
2109 2109 | |
2110 2110 | o 2: 49cb3485fa0c 'C' bookmarks: Y
2111 2111 | |
2112 2112 | o 1: 6c81ed0049f8 'B' bookmarks: X
2113 2113 |/
2114 2114 o 0: 1994f17a630e 'A' bookmarks:
2115 2115
2116 2116 $ hg rebase -s 1 -d 5
2117 2117 rebasing 1:6c81ed0049f8 "B" (X)
2118 2118 rebasing 2:49cb3485fa0c "C" (Y)
2119 2119 rebasing 3:67a385d4e6f2 "D" (Z)
2120 2120 merging d
2121 2121 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
2122 2122 unresolved conflicts (see hg resolve, then hg rebase --continue)
2123 2123 [1]
2124 2124 $ hg rebase --stop
2125 2125 1 new orphan changesets
2126 2126 $ hg log -GT "{rev}: {node|short} '{desc}' bookmarks: {bookmarks}\n"
2127 2127 o 7: 9c86c650b686 'C' bookmarks: Y
2128 2128 |
2129 2129 o 6: 9b87b54e5fd8 'B' bookmarks: X
2130 2130 |
2131 2131 @ 5: 39adf30bc1be 'conflict with d' bookmarks:
2132 2132 |
2133 2133 o 4: 9c1e55f411b6 'E' bookmarks:
2134 2134 |
2135 2135 | * 3: 67a385d4e6f2 'D' bookmarks: Z
2136 2136 | |
2137 2137 | x 2: 49cb3485fa0c 'C' bookmarks:
2138 2138 | |
2139 2139 | x 1: 6c81ed0049f8 'B' bookmarks:
2140 2140 |/
2141 2141 o 0: 1994f17a630e 'A' bookmarks:
2142 2142
General Comments 0
You need to be logged in to leave comments. Login now