##// END OF EJS Templates
rebase: add error codes...
Matt Mackall -
r11205:d26f662b default
parent child Browse files
Show More
@@ -1,558 +1,561 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 http://mercurial.selenic.com/wiki/RebaseExtension
15 15 '''
16 16
17 17 from mercurial import hg, util, repair, merge, cmdutil, commands, error
18 18 from mercurial import extensions, ancestor, copies, patch
19 19 from mercurial.commands import templateopts
20 20 from mercurial.node import nullrev
21 21 from mercurial.lock import release
22 22 from mercurial.i18n import _
23 23 import os, errno
24 24
25 25 nullmerge = -2
26 26
27 27 def rebase(ui, repo, **opts):
28 28 """move changeset (and descendants) to a different branch
29 29
30 30 Rebase uses repeated merging to graft changesets from one part of
31 31 history (the source) onto another (the destination). This can be
32 32 useful for linearizing *local* changes relative to a master
33 33 development tree.
34 34
35 35 You should not rebase changesets that have already been shared
36 36 with others. Doing so will force everybody else to perform the
37 37 same rebase or they will end up with duplicated changesets after
38 38 pulling in your rebased changesets.
39 39
40 40 If you don't specify a destination changeset (``-d/--dest``),
41 41 rebase uses the tipmost head of the current named branch as the
42 42 destination. (The destination changeset is not modified by
43 43 rebasing, but new changesets are added as its descendants.)
44 44
45 45 You can specify which changesets to rebase in two ways: as a
46 46 "source" changeset or as a "base" changeset. Both are shorthand
47 47 for a topologically related set of changesets (the "source
48 48 branch"). If you specify source (``-s/--source``), rebase will
49 49 rebase that changeset and all of its descendants onto dest. If you
50 50 specify base (``-b/--base``), rebase will select ancestors of base
51 51 back to but not including the common ancestor with dest. Thus,
52 52 ``-b`` is less precise but more convenient than ``-s``: you can
53 53 specify any changeset in the source branch, and rebase will select
54 54 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
55 55 uses the parent of the working directory as the base.
56 56
57 57 By default, rebase recreates the changesets in the source branch
58 58 as descendants of dest and then destroys the originals. Use
59 59 ``--keep`` to preserve the original source changesets. Some
60 60 changesets in the source branch (e.g. merges from the destination
61 61 branch) may be dropped if they no longer contribute any change.
62 62
63 63 One result of the rules for selecting the destination changeset
64 64 and source branch is that, unlike ``merge``, rebase will do
65 65 nothing if you are at the latest (tipmost) head of a named branch
66 66 with two heads. You need to explicitly specify source and/or
67 67 destination (or ``update`` to the other head, if it's the head of
68 68 the intended source branch).
69 69
70 70 If a rebase is interrupted to manually resolve a merge, it can be
71 71 continued with --continue/-c or aborted with --abort/-a.
72
73 Returns 0 on success, 1 if nothing to rebase.
72 74 """
73 75 originalwd = target = None
74 76 external = nullrev
75 77 state = {}
76 78 skipped = set()
77 79 targetancestors = set()
78 80
79 81 lock = wlock = None
80 82 try:
81 83 lock = repo.lock()
82 84 wlock = repo.wlock()
83 85
84 86 # Validate input and define rebasing points
85 87 destf = opts.get('dest', None)
86 88 srcf = opts.get('source', None)
87 89 basef = opts.get('base', None)
88 90 contf = opts.get('continue')
89 91 abortf = opts.get('abort')
90 92 collapsef = opts.get('collapse', False)
91 93 extrafn = opts.get('extrafn')
92 94 keepf = opts.get('keep', False)
93 95 keepbranchesf = opts.get('keepbranches', False)
94 96 detachf = opts.get('detach', False)
95 97 # keepopen is not meant for use on the command line, but by
96 98 # other extensions
97 99 keepopen = opts.get('keepopen', False)
98 100
99 101 if contf or abortf:
100 102 if contf and abortf:
101 103 raise error.ParseError('rebase',
102 104 _('cannot use both abort and continue'))
103 105 if collapsef:
104 106 raise error.ParseError(
105 107 'rebase', _('cannot use collapse with continue or abort'))
106 108
107 109 if detachf:
108 110 raise error.ParseError(
109 111 'rebase', _('cannot use detach with continue or abort'))
110 112
111 113 if srcf or basef or destf:
112 114 raise error.ParseError('rebase',
113 115 _('abort and continue do not allow specifying revisions'))
114 116
115 117 (originalwd, target, state, collapsef, keepf,
116 118 keepbranchesf, external) = restorestatus(repo)
117 119 if abortf:
118 abort(repo, originalwd, target, state)
119 return
120 return abort(repo, originalwd, target, state)
120 121 else:
121 122 if srcf and basef:
122 123 raise error.ParseError('rebase', _('cannot specify both a '
123 124 'revision and a base'))
124 125 if detachf:
125 126 if not srcf:
126 127 raise error.ParseError(
127 128 'rebase', _('detach requires a revision to be specified'))
128 129 if basef:
129 130 raise error.ParseError(
130 131 'rebase', _('cannot specify a base with detach'))
131 132
132 133 cmdutil.bail_if_changed(repo)
133 134 result = buildstate(repo, destf, srcf, basef, detachf)
134 135 if not result:
135 136 # Empty state built, nothing to rebase
136 137 ui.status(_('nothing to rebase\n'))
137 return
138 return 1
138 139 else:
139 140 originalwd, target, state = result
140 141 if collapsef:
141 142 targetancestors = set(repo.changelog.ancestors(target))
142 143 external = checkexternal(repo, state, targetancestors)
143 144
144 145 if keepbranchesf:
145 146 if extrafn:
146 147 raise error.ParseError(
147 148 'rebase', _('cannot use both keepbranches and extrafn'))
148 149 def extrafn(ctx, extra):
149 150 extra['branch'] = ctx.branch()
150 151
151 152 # Rebase
152 153 if not targetancestors:
153 154 targetancestors = set(repo.changelog.ancestors(target))
154 155 targetancestors.add(target)
155 156
156 157 for rev in sorted(state):
157 158 if state[rev] == -1:
158 159 ui.debug("rebasing %d:%s\n" % (rev, repo[rev]))
159 160 storestatus(repo, originalwd, target, state, collapsef, keepf,
160 161 keepbranchesf, external)
161 162 p1, p2 = defineparents(repo, rev, target, state,
162 163 targetancestors)
163 164 if len(repo.parents()) == 2:
164 165 repo.ui.debug('resuming interrupted rebase\n')
165 166 else:
166 167 stats = rebasenode(repo, rev, p1, p2, state)
167 168 if stats and stats[3] > 0:
168 169 raise util.Abort(_('fix unresolved conflicts with hg '
169 170 'resolve then run hg rebase --continue'))
170 171 updatedirstate(repo, rev, target, p2)
171 172 if not collapsef:
172 173 newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn)
173 174 else:
174 175 # Skip commit if we are collapsing
175 176 repo.dirstate.setparents(repo[p1].node())
176 177 newrev = None
177 178 # Update the state
178 179 if newrev is not None:
179 180 state[rev] = repo[newrev].rev()
180 181 else:
181 182 if not collapsef:
182 183 ui.note(_('no changes, revision %d skipped\n') % rev)
183 184 ui.debug('next revision set to %s\n' % p1)
184 185 skipped.add(rev)
185 186 state[rev] = p1
186 187
187 188 ui.note(_('rebase merging completed\n'))
188 189
189 190 if collapsef and not keepopen:
190 191 p1, p2 = defineparents(repo, min(state), target,
191 192 state, targetancestors)
192 193 commitmsg = 'Collapsed revision'
193 194 for rebased in state:
194 195 if rebased not in skipped and state[rebased] != nullmerge:
195 196 commitmsg += '\n* %s' % repo[rebased].description()
196 197 commitmsg = ui.edit(commitmsg, repo.ui.username())
197 198 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
198 199 extrafn=extrafn)
199 200
200 201 if 'qtip' in repo.tags():
201 202 updatemq(repo, state, skipped, **opts)
202 203
203 204 if not keepf:
204 205 # Remove no more useful revisions
205 206 rebased = [rev for rev in state if state[rev] != nullmerge]
206 207 if rebased:
207 208 if set(repo.changelog.descendants(min(rebased))) - set(state):
208 209 ui.warn(_("warning: new changesets detected "
209 210 "on source branch, not stripping\n"))
210 211 else:
211 212 # backup the old csets by default
212 213 repair.strip(ui, repo, repo[min(rebased)].node(), "all")
213 214
214 215 clearstatus(repo)
215 216 ui.note(_("rebase completed\n"))
216 217 if os.path.exists(repo.sjoin('undo')):
217 218 util.unlink(repo.sjoin('undo'))
218 219 if skipped:
219 220 ui.note(_("%d revisions have been skipped\n") % len(skipped))
220 221 finally:
221 222 release(lock, wlock)
222 223
223 224 def rebasemerge(repo, rev, first=False):
224 225 'return the correct ancestor'
225 226 oldancestor = ancestor.ancestor
226 227
227 228 def newancestor(a, b, pfunc):
228 229 if b == rev:
229 230 return repo[rev].parents()[0].rev()
230 231 return oldancestor(a, b, pfunc)
231 232
232 233 if not first:
233 234 ancestor.ancestor = newancestor
234 235 else:
235 236 repo.ui.debug("first revision, do not change ancestor\n")
236 237 try:
237 238 stats = merge.update(repo, rev, True, True, False)
238 239 return stats
239 240 finally:
240 241 ancestor.ancestor = oldancestor
241 242
242 243 def checkexternal(repo, state, targetancestors):
243 244 """Check whether one or more external revisions need to be taken in
244 245 consideration. In the latter case, abort.
245 246 """
246 247 external = nullrev
247 248 source = min(state)
248 249 for rev in state:
249 250 if rev == source:
250 251 continue
251 252 # Check externals and fail if there are more than one
252 253 for p in repo[rev].parents():
253 254 if (p.rev() not in state
254 255 and p.rev() not in targetancestors):
255 256 if external != nullrev:
256 257 raise util.Abort(_('unable to collapse, there is more '
257 258 'than one external parent'))
258 259 external = p.rev()
259 260 return external
260 261
261 262 def updatedirstate(repo, rev, p1, p2):
262 263 """Keep track of renamed files in the revision that is going to be rebased
263 264 """
264 265 # Here we simulate the copies and renames in the source changeset
265 266 cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
266 267 m1 = repo[rev].manifest()
267 268 m2 = repo[p1].manifest()
268 269 for k, v in cop.iteritems():
269 270 if k in m1:
270 271 if v in m1 or v in m2:
271 272 repo.dirstate.copy(v, k)
272 273 if v in m2 and v not in m1:
273 274 repo.dirstate.remove(v)
274 275
275 276 def concludenode(repo, rev, p1, p2, commitmsg=None, extrafn=None):
276 277 'Commit the changes and store useful information in extra'
277 278 try:
278 279 repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
279 280 if commitmsg is None:
280 281 commitmsg = repo[rev].description()
281 282 ctx = repo[rev]
282 283 extra = {'rebase_source': ctx.hex()}
283 284 if extrafn:
284 285 extrafn(ctx, extra)
285 286 # Commit might fail if unresolved files exist
286 287 newrev = repo.commit(text=commitmsg, user=ctx.user(),
287 288 date=ctx.date(), extra=extra)
288 289 repo.dirstate.setbranch(repo[newrev].branch())
289 290 return newrev
290 291 except util.Abort:
291 292 # Invalidate the previous setparents
292 293 repo.dirstate.invalidate()
293 294 raise
294 295
295 296 def rebasenode(repo, rev, p1, p2, state):
296 297 'Rebase a single revision'
297 298 # Merge phase
298 299 # Update to target and merge it with local
299 300 if repo['.'].rev() != repo[p1].rev():
300 301 repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
301 302 merge.update(repo, p1, False, True, False)
302 303 else:
303 304 repo.ui.debug(" already in target\n")
304 305 repo.dirstate.write()
305 306 repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
306 307 first = repo[rev].rev() == repo[min(state)].rev()
307 308 stats = rebasemerge(repo, rev, first)
308 309 return stats
309 310
310 311 def defineparents(repo, rev, target, state, targetancestors):
311 312 'Return the new parent relationship of the revision that will be rebased'
312 313 parents = repo[rev].parents()
313 314 p1 = p2 = nullrev
314 315
315 316 P1n = parents[0].rev()
316 317 if P1n in targetancestors:
317 318 p1 = target
318 319 elif P1n in state:
319 320 if state[P1n] == nullmerge:
320 321 p1 = target
321 322 else:
322 323 p1 = state[P1n]
323 324 else: # P1n external
324 325 p1 = target
325 326 p2 = P1n
326 327
327 328 if len(parents) == 2 and parents[1].rev() not in targetancestors:
328 329 P2n = parents[1].rev()
329 330 # interesting second parent
330 331 if P2n in state:
331 332 if p1 == target: # P1n in targetancestors or external
332 333 p1 = state[P2n]
333 334 else:
334 335 p2 = state[P2n]
335 336 else: # P2n external
336 337 if p2 != nullrev: # P1n external too => rev is a merged revision
337 338 raise util.Abort(_('cannot use revision %d as base, result '
338 339 'would have 3 parents') % rev)
339 340 p2 = P2n
340 341 repo.ui.debug(" future parents are %d and %d\n" %
341 342 (repo[p1].rev(), repo[p2].rev()))
342 343 return p1, p2
343 344
344 345 def isagitpatch(repo, patchname):
345 346 'Return true if the given patch is in git format'
346 347 mqpatch = os.path.join(repo.mq.path, patchname)
347 348 for line in patch.linereader(file(mqpatch, 'rb')):
348 349 if line.startswith('diff --git'):
349 350 return True
350 351 return False
351 352
352 353 def updatemq(repo, state, skipped, **opts):
353 354 'Update rebased mq patches - finalize and then import them'
354 355 mqrebase = {}
355 356 for p in repo.mq.applied:
356 357 if repo[p.node].rev() in state:
357 358 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
358 359 (repo[p.node].rev(), p.name))
359 360 mqrebase[repo[p.node].rev()] = (p.name, isagitpatch(repo, p.name))
360 361
361 362 if mqrebase:
362 363 repo.mq.finish(repo, mqrebase.keys())
363 364
364 365 # We must start import from the newest revision
365 366 for rev in sorted(mqrebase, reverse=True):
366 367 if rev not in skipped:
367 368 repo.ui.debug('import mq patch %d (%s)\n'
368 369 % (state[rev], mqrebase[rev][0]))
369 370 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
370 371 git=mqrebase[rev][1],rev=[str(state[rev])])
371 372 repo.mq.save_dirty()
372 373
373 374 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
374 375 external):
375 376 'Store the current status to allow recovery'
376 377 f = repo.opener("rebasestate", "w")
377 378 f.write(repo[originalwd].hex() + '\n')
378 379 f.write(repo[target].hex() + '\n')
379 380 f.write(repo[external].hex() + '\n')
380 381 f.write('%d\n' % int(collapse))
381 382 f.write('%d\n' % int(keep))
382 383 f.write('%d\n' % int(keepbranches))
383 384 for d, v in state.iteritems():
384 385 oldrev = repo[d].hex()
385 386 newrev = repo[v].hex()
386 387 f.write("%s:%s\n" % (oldrev, newrev))
387 388 f.close()
388 389 repo.ui.debug('rebase status stored\n')
389 390
390 391 def clearstatus(repo):
391 392 'Remove the status files'
392 393 if os.path.exists(repo.join("rebasestate")):
393 394 util.unlink(repo.join("rebasestate"))
394 395
395 396 def restorestatus(repo):
396 397 'Restore a previously stored status'
397 398 try:
398 399 target = None
399 400 collapse = False
400 401 external = nullrev
401 402 state = {}
402 403 f = repo.opener("rebasestate")
403 404 for i, l in enumerate(f.read().splitlines()):
404 405 if i == 0:
405 406 originalwd = repo[l].rev()
406 407 elif i == 1:
407 408 target = repo[l].rev()
408 409 elif i == 2:
409 410 external = repo[l].rev()
410 411 elif i == 3:
411 412 collapse = bool(int(l))
412 413 elif i == 4:
413 414 keep = bool(int(l))
414 415 elif i == 5:
415 416 keepbranches = bool(int(l))
416 417 else:
417 418 oldrev, newrev = l.split(':')
418 419 state[repo[oldrev].rev()] = repo[newrev].rev()
419 420 repo.ui.debug('rebase status resumed\n')
420 421 return originalwd, target, state, collapse, keep, keepbranches, external
421 422 except IOError, err:
422 423 if err.errno != errno.ENOENT:
423 424 raise
424 425 raise util.Abort(_('no rebase in progress'))
425 426
426 427 def abort(repo, originalwd, target, state):
427 428 'Restore the repository to its original state'
428 429 if set(repo.changelog.descendants(target)) - set(state.values()):
429 430 repo.ui.warn(_("warning: new changesets detected on target branch, "
430 431 "can't abort\n"))
432 return -1
431 433 else:
432 434 # Strip from the first rebased revision
433 435 merge.update(repo, repo[originalwd].rev(), False, True, False)
434 436 rebased = filter(lambda x: x > -1, state.values())
435 437 if rebased:
436 438 strippoint = min(rebased)
437 439 # no backup of rebased cset versions needed
438 440 repair.strip(repo.ui, repo, repo[strippoint].node())
439 441 clearstatus(repo)
440 442 repo.ui.status(_('rebase aborted\n'))
443 return 0
441 444
442 445 def buildstate(repo, dest, src, base, detach):
443 446 'Define which revisions are going to be rebased and where'
444 447 targetancestors = set()
445 448 detachset = set()
446 449
447 450 if not dest:
448 451 # Destination defaults to the latest revision in the current branch
449 452 branch = repo[None].branch()
450 453 dest = repo[branch].rev()
451 454 else:
452 455 dest = repo[dest].rev()
453 456
454 457 # This check isn't strictly necessary, since mq detects commits over an
455 458 # applied patch. But it prevents messing up the working directory when
456 459 # a partially completed rebase is blocked by mq.
457 460 if 'qtip' in repo.tags() and (repo[dest].node() in
458 461 [s.node for s in repo.mq.applied]):
459 462 raise util.Abort(_('cannot rebase onto an applied mq patch'))
460 463
461 464 if src:
462 465 commonbase = repo[src].ancestor(repo[dest])
463 466 if commonbase == repo[src]:
464 467 raise util.Abort(_('source is ancestor of destination'))
465 468 if commonbase == repo[dest]:
466 469 raise util.Abort(_('source is descendant of destination'))
467 470 source = repo[src].rev()
468 471 if detach:
469 472 # We need to keep track of source's ancestors up to the common base
470 473 srcancestors = set(repo.changelog.ancestors(source))
471 474 baseancestors = set(repo.changelog.ancestors(commonbase.rev()))
472 475 detachset = srcancestors - baseancestors
473 476 detachset.remove(commonbase.rev())
474 477 else:
475 478 if base:
476 479 cwd = repo[base].rev()
477 480 else:
478 481 cwd = repo['.'].rev()
479 482
480 483 if cwd == dest:
481 484 repo.ui.debug('source and destination are the same\n')
482 485 return None
483 486
484 487 targetancestors = set(repo.changelog.ancestors(dest))
485 488 if cwd in targetancestors:
486 489 repo.ui.debug('source is ancestor of destination\n')
487 490 return None
488 491
489 492 cwdancestors = set(repo.changelog.ancestors(cwd))
490 493 if dest in cwdancestors:
491 494 repo.ui.debug('source is descendant of destination\n')
492 495 return None
493 496
494 497 cwdancestors.add(cwd)
495 498 rebasingbranch = cwdancestors - targetancestors
496 499 source = min(rebasingbranch)
497 500
498 501 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
499 502 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
500 503 state.update(dict.fromkeys(detachset, nullmerge))
501 504 state[source] = nullrev
502 505 return repo['.'].rev(), repo[dest].rev(), state
503 506
504 507 def pullrebase(orig, ui, repo, *args, **opts):
505 508 'Call rebase after pull if the latter has been invoked with --rebase'
506 509 if opts.get('rebase'):
507 510 if opts.get('update'):
508 511 del opts['update']
509 512 ui.debug('--update and --rebase are not compatible, ignoring '
510 513 'the update flag\n')
511 514
512 515 cmdutil.bail_if_changed(repo)
513 516 revsprepull = len(repo)
514 517 origpostincoming = commands.postincoming
515 518 def _dummy(*args, **kwargs):
516 519 pass
517 520 commands.postincoming = _dummy
518 521 try:
519 522 orig(ui, repo, *args, **opts)
520 523 finally:
521 524 commands.postincoming = origpostincoming
522 525 revspostpull = len(repo)
523 526 if revspostpull > revsprepull:
524 527 rebase(ui, repo, **opts)
525 528 branch = repo[None].branch()
526 529 dest = repo[branch].rev()
527 530 if dest != repo['.'].rev():
528 531 # there was nothing to rebase we force an update
529 532 hg.update(repo, dest)
530 533 else:
531 534 orig(ui, repo, *args, **opts)
532 535
533 536 def uisetup(ui):
534 537 'Replace pull with a decorator to provide --rebase option'
535 538 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
536 539 entry[1].append(('', 'rebase', None,
537 540 _("rebase working directory to branch head"))
538 541 )
539 542
540 543 cmdtable = {
541 544 "rebase":
542 545 (rebase,
543 546 [
544 547 ('s', 'source', '', _('rebase from the specified changeset')),
545 548 ('b', 'base', '', _('rebase from the base of the specified changeset '
546 549 '(up to greatest common ancestor of base and dest)')),
547 550 ('d', 'dest', '', _('rebase onto the specified changeset')),
548 551 ('', 'collapse', False, _('collapse the rebased changesets')),
549 552 ('', 'keep', False, _('keep original changesets')),
550 553 ('', 'keepbranches', False, _('keep original branch names')),
551 554 ('', 'detach', False, _('force detaching of source from its original '
552 555 'branch')),
553 556 ('c', 'continue', False, _('continue an interrupted rebase')),
554 557 ('a', 'abort', False, _('abort an interrupted rebase'))] +
555 558 templateopts,
556 559 _('hg rebase [-s REV | -b REV] [-d REV] [options]\n'
557 560 'hg rebase {-a|-c}'))
558 561 }
@@ -1,296 +1,304 b''
1 1 % These fail
2 2
3 3 % Use continue and abort
4 4 hg rebase: cannot use both abort and continue
5 5 hg rebase [-s REV | -b REV] [-d REV] [options]
6 6 hg rebase {-a|-c}
7 7
8 8 move changeset (and descendants) to a different branch
9 9
10 10 Rebase uses repeated merging to graft changesets from one part of history
11 11 (the source) onto another (the destination). This can be useful for
12 12 linearizing *local* changes relative to a master development tree.
13 13
14 14 You should not rebase changesets that have already been shared with
15 15 others. Doing so will force everybody else to perform the same rebase or
16 16 they will end up with duplicated changesets after pulling in your rebased
17 17 changesets.
18 18
19 19 If you don't specify a destination changeset ("-d/--dest"), rebase uses
20 20 the tipmost head of the current named branch as the destination. (The
21 21 destination changeset is not modified by rebasing, but new changesets are
22 22 added as its descendants.)
23 23
24 24 You can specify which changesets to rebase in two ways: as a "source"
25 25 changeset or as a "base" changeset. Both are shorthand for a topologically
26 26 related set of changesets (the "source branch"). If you specify source
27 27 ("-s/--source"), rebase will rebase that changeset and all of its
28 28 descendants onto dest. If you specify base ("-b/--base"), rebase will
29 29 select ancestors of base back to but not including the common ancestor
30 30 with dest. Thus, "-b" is less precise but more convenient than "-s": you
31 31 can specify any changeset in the source branch, and rebase will select the
32 32 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
33 33 of the working directory as the base.
34 34
35 35 By default, rebase recreates the changesets in the source branch as
36 36 descendants of dest and then destroys the originals. Use "--keep" to
37 37 preserve the original source changesets. Some changesets in the source
38 38 branch (e.g. merges from the destination branch) may be dropped if they no
39 39 longer contribute any change.
40 40
41 41 One result of the rules for selecting the destination changeset and source
42 42 branch is that, unlike "merge", rebase will do nothing if you are at the
43 43 latest (tipmost) head of a named branch with two heads. You need to
44 44 explicitly specify source and/or destination (or "update" to the other
45 45 head, if it's the head of the intended source branch).
46 46
47 47 If a rebase is interrupted to manually resolve a merge, it can be
48 48 continued with --continue/-c or aborted with --abort/-a.
49 49
50 Returns 0 on success, 1 if nothing to rebase.
51
50 52 options:
51 53
52 54 -s --source rebase from the specified changeset
53 55 -b --base rebase from the base of the specified changeset (up to
54 56 greatest common ancestor of base and dest)
55 57 -d --dest rebase onto the specified changeset
56 58 --collapse collapse the rebased changesets
57 59 --keep keep original changesets
58 60 --keepbranches keep original branch names
59 61 --detach force detaching of source from its original branch
60 62 -c --continue continue an interrupted rebase
61 63 -a --abort abort an interrupted rebase
62 64 --style display using template map file
63 65 --template display with template
64 66
65 67 use "hg -v help rebase" to show global options
66 68
67 69 % Use continue and collapse
68 70 hg rebase: cannot use collapse with continue or abort
69 71 hg rebase [-s REV | -b REV] [-d REV] [options]
70 72 hg rebase {-a|-c}
71 73
72 74 move changeset (and descendants) to a different branch
73 75
74 76 Rebase uses repeated merging to graft changesets from one part of history
75 77 (the source) onto another (the destination). This can be useful for
76 78 linearizing *local* changes relative to a master development tree.
77 79
78 80 You should not rebase changesets that have already been shared with
79 81 others. Doing so will force everybody else to perform the same rebase or
80 82 they will end up with duplicated changesets after pulling in your rebased
81 83 changesets.
82 84
83 85 If you don't specify a destination changeset ("-d/--dest"), rebase uses
84 86 the tipmost head of the current named branch as the destination. (The
85 87 destination changeset is not modified by rebasing, but new changesets are
86 88 added as its descendants.)
87 89
88 90 You can specify which changesets to rebase in two ways: as a "source"
89 91 changeset or as a "base" changeset. Both are shorthand for a topologically
90 92 related set of changesets (the "source branch"). If you specify source
91 93 ("-s/--source"), rebase will rebase that changeset and all of its
92 94 descendants onto dest. If you specify base ("-b/--base"), rebase will
93 95 select ancestors of base back to but not including the common ancestor
94 96 with dest. Thus, "-b" is less precise but more convenient than "-s": you
95 97 can specify any changeset in the source branch, and rebase will select the
96 98 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
97 99 of the working directory as the base.
98 100
99 101 By default, rebase recreates the changesets in the source branch as
100 102 descendants of dest and then destroys the originals. Use "--keep" to
101 103 preserve the original source changesets. Some changesets in the source
102 104 branch (e.g. merges from the destination branch) may be dropped if they no
103 105 longer contribute any change.
104 106
105 107 One result of the rules for selecting the destination changeset and source
106 108 branch is that, unlike "merge", rebase will do nothing if you are at the
107 109 latest (tipmost) head of a named branch with two heads. You need to
108 110 explicitly specify source and/or destination (or "update" to the other
109 111 head, if it's the head of the intended source branch).
110 112
111 113 If a rebase is interrupted to manually resolve a merge, it can be
112 114 continued with --continue/-c or aborted with --abort/-a.
113 115
116 Returns 0 on success, 1 if nothing to rebase.
117
114 118 options:
115 119
116 120 -s --source rebase from the specified changeset
117 121 -b --base rebase from the base of the specified changeset (up to
118 122 greatest common ancestor of base and dest)
119 123 -d --dest rebase onto the specified changeset
120 124 --collapse collapse the rebased changesets
121 125 --keep keep original changesets
122 126 --keepbranches keep original branch names
123 127 --detach force detaching of source from its original branch
124 128 -c --continue continue an interrupted rebase
125 129 -a --abort abort an interrupted rebase
126 130 --style display using template map file
127 131 --template display with template
128 132
129 133 use "hg -v help rebase" to show global options
130 134
131 135 % Use continue/abort and dest/source
132 136 hg rebase: abort and continue do not allow specifying revisions
133 137 hg rebase [-s REV | -b REV] [-d REV] [options]
134 138 hg rebase {-a|-c}
135 139
136 140 move changeset (and descendants) to a different branch
137 141
138 142 Rebase uses repeated merging to graft changesets from one part of history
139 143 (the source) onto another (the destination). This can be useful for
140 144 linearizing *local* changes relative to a master development tree.
141 145
142 146 You should not rebase changesets that have already been shared with
143 147 others. Doing so will force everybody else to perform the same rebase or
144 148 they will end up with duplicated changesets after pulling in your rebased
145 149 changesets.
146 150
147 151 If you don't specify a destination changeset ("-d/--dest"), rebase uses
148 152 the tipmost head of the current named branch as the destination. (The
149 153 destination changeset is not modified by rebasing, but new changesets are
150 154 added as its descendants.)
151 155
152 156 You can specify which changesets to rebase in two ways: as a "source"
153 157 changeset or as a "base" changeset. Both are shorthand for a topologically
154 158 related set of changesets (the "source branch"). If you specify source
155 159 ("-s/--source"), rebase will rebase that changeset and all of its
156 160 descendants onto dest. If you specify base ("-b/--base"), rebase will
157 161 select ancestors of base back to but not including the common ancestor
158 162 with dest. Thus, "-b" is less precise but more convenient than "-s": you
159 163 can specify any changeset in the source branch, and rebase will select the
160 164 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
161 165 of the working directory as the base.
162 166
163 167 By default, rebase recreates the changesets in the source branch as
164 168 descendants of dest and then destroys the originals. Use "--keep" to
165 169 preserve the original source changesets. Some changesets in the source
166 170 branch (e.g. merges from the destination branch) may be dropped if they no
167 171 longer contribute any change.
168 172
169 173 One result of the rules for selecting the destination changeset and source
170 174 branch is that, unlike "merge", rebase will do nothing if you are at the
171 175 latest (tipmost) head of a named branch with two heads. You need to
172 176 explicitly specify source and/or destination (or "update" to the other
173 177 head, if it's the head of the intended source branch).
174 178
175 179 If a rebase is interrupted to manually resolve a merge, it can be
176 180 continued with --continue/-c or aborted with --abort/-a.
177 181
182 Returns 0 on success, 1 if nothing to rebase.
183
178 184 options:
179 185
180 186 -s --source rebase from the specified changeset
181 187 -b --base rebase from the base of the specified changeset (up to
182 188 greatest common ancestor of base and dest)
183 189 -d --dest rebase onto the specified changeset
184 190 --collapse collapse the rebased changesets
185 191 --keep keep original changesets
186 192 --keepbranches keep original branch names
187 193 --detach force detaching of source from its original branch
188 194 -c --continue continue an interrupted rebase
189 195 -a --abort abort an interrupted rebase
190 196 --style display using template map file
191 197 --template display with template
192 198
193 199 use "hg -v help rebase" to show global options
194 200
195 201 % Use source and base
196 202 hg rebase: cannot specify both a revision and a base
197 203 hg rebase [-s REV | -b REV] [-d REV] [options]
198 204 hg rebase {-a|-c}
199 205
200 206 move changeset (and descendants) to a different branch
201 207
202 208 Rebase uses repeated merging to graft changesets from one part of history
203 209 (the source) onto another (the destination). This can be useful for
204 210 linearizing *local* changes relative to a master development tree.
205 211
206 212 You should not rebase changesets that have already been shared with
207 213 others. Doing so will force everybody else to perform the same rebase or
208 214 they will end up with duplicated changesets after pulling in your rebased
209 215 changesets.
210 216
211 217 If you don't specify a destination changeset ("-d/--dest"), rebase uses
212 218 the tipmost head of the current named branch as the destination. (The
213 219 destination changeset is not modified by rebasing, but new changesets are
214 220 added as its descendants.)
215 221
216 222 You can specify which changesets to rebase in two ways: as a "source"
217 223 changeset or as a "base" changeset. Both are shorthand for a topologically
218 224 related set of changesets (the "source branch"). If you specify source
219 225 ("-s/--source"), rebase will rebase that changeset and all of its
220 226 descendants onto dest. If you specify base ("-b/--base"), rebase will
221 227 select ancestors of base back to but not including the common ancestor
222 228 with dest. Thus, "-b" is less precise but more convenient than "-s": you
223 229 can specify any changeset in the source branch, and rebase will select the
224 230 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
225 231 of the working directory as the base.
226 232
227 233 By default, rebase recreates the changesets in the source branch as
228 234 descendants of dest and then destroys the originals. Use "--keep" to
229 235 preserve the original source changesets. Some changesets in the source
230 236 branch (e.g. merges from the destination branch) may be dropped if they no
231 237 longer contribute any change.
232 238
233 239 One result of the rules for selecting the destination changeset and source
234 240 branch is that, unlike "merge", rebase will do nothing if you are at the
235 241 latest (tipmost) head of a named branch with two heads. You need to
236 242 explicitly specify source and/or destination (or "update" to the other
237 243 head, if it's the head of the intended source branch).
238 244
239 245 If a rebase is interrupted to manually resolve a merge, it can be
240 246 continued with --continue/-c or aborted with --abort/-a.
241 247
248 Returns 0 on success, 1 if nothing to rebase.
249
242 250 options:
243 251
244 252 -s --source rebase from the specified changeset
245 253 -b --base rebase from the base of the specified changeset (up to
246 254 greatest common ancestor of base and dest)
247 255 -d --dest rebase onto the specified changeset
248 256 --collapse collapse the rebased changesets
249 257 --keep keep original changesets
250 258 --keepbranches keep original branch names
251 259 --detach force detaching of source from its original branch
252 260 -c --continue continue an interrupted rebase
253 261 -a --abort abort an interrupted rebase
254 262 --style display using template map file
255 263 --template display with template
256 264
257 265 use "hg -v help rebase" to show global options
258 266
259 267 % Rebase with no arguments - from current
260 268 nothing to rebase
261 269
262 270 % Rebase with no arguments - from the current branch
263 271 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
264 272 nothing to rebase
265 273 % ----------
266 274 % These work
267 275
268 276 % Rebase with no arguments (from 3 onto 7)
269 277 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
270 278 saved backup bundle to
271 279 % Try to rollback after a rebase (fail)
272 280 no rollback information available
273 281
274 282 % Rebase with base == '.' => same as no arguments (from 3 onto 7)
275 283 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
276 284 saved backup bundle to
277 285
278 286 % Rebase with dest == default => same as no arguments (from 3 onto 7)
279 287 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
280 288 saved backup bundle to
281 289
282 290 % Specify only source (from 4 onto 7)
283 291 saved backup bundle to
284 292
285 293 % Specify only dest (from 3 onto 6)
286 294 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
287 295 saved backup bundle to
288 296
289 297 % Specify only base (from 3 onto 7)
290 298 saved backup bundle to
291 299
292 300 % Specify source and dest (from 4 onto 6)
293 301 saved backup bundle to
294 302
295 303 % Specify base and dest (from 3 onto 6)
296 304 saved backup bundle to
General Comments 0
You need to be logged in to leave comments. Login now