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