##// END OF EJS Templates
phases: prevent rebase to rebase immutable changeset.
Pierre-Yves David -
r15742:65df60a3 default
parent child Browse files
Show More
@@ -1,634 +1,643 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, bookmarks
18 18 from mercurial import extensions, 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 cmdtable = {}
28 28 command = cmdutil.command(cmdtable)
29 29
30 30 @command('rebase',
31 31 [('s', 'source', '',
32 32 _('rebase from the specified changeset'), _('REV')),
33 33 ('b', 'base', '',
34 34 _('rebase from the base of the specified changeset '
35 35 '(up to greatest common ancestor of base and dest)'),
36 36 _('REV')),
37 37 ('r', 'rev', [],
38 38 _('rebase these revisions'),
39 39 _('REV')),
40 40 ('d', 'dest', '',
41 41 _('rebase onto the specified changeset'), _('REV')),
42 42 ('', 'collapse', False, _('collapse the rebased changesets')),
43 43 ('m', 'message', '',
44 44 _('use text as collapse commit message'), _('TEXT')),
45 45 ('e', 'edit', False, _('invoke editor on commit messages')),
46 46 ('l', 'logfile', '',
47 47 _('read collapse commit message from file'), _('FILE')),
48 48 ('', 'keep', False, _('keep original changesets')),
49 49 ('', 'keepbranches', False, _('keep original branch names')),
50 50 ('D', 'detach', False, _('force detaching of source from its original '
51 51 'branch')),
52 52 ('t', 'tool', '', _('specify merge tool')),
53 53 ('c', 'continue', False, _('continue an interrupted rebase')),
54 54 ('a', 'abort', False, _('abort an interrupted rebase'))] +
55 55 templateopts,
56 56 _('hg rebase [-s REV | -b REV] [-d REV] [options]\n'
57 57 'hg rebase {-a|-c}'))
58 58 def rebase(ui, repo, **opts):
59 59 """move changeset (and descendants) to a different branch
60 60
61 61 Rebase uses repeated merging to graft changesets from one part of
62 62 history (the source) onto another (the destination). This can be
63 63 useful for linearizing *local* changes relative to a master
64 64 development tree.
65 65
66 66 You should not rebase changesets that have already been shared
67 67 with others. Doing so will force everybody else to perform the
68 68 same rebase or they will end up with duplicated changesets after
69 69 pulling in your rebased changesets.
70 70
71 71 If you don't specify a destination changeset (``-d/--dest``),
72 72 rebase uses the tipmost head of the current named branch as the
73 73 destination. (The destination changeset is not modified by
74 74 rebasing, but new changesets are added as its descendants.)
75 75
76 76 You can specify which changesets to rebase in two ways: as a
77 77 "source" changeset or as a "base" changeset. Both are shorthand
78 78 for a topologically related set of changesets (the "source
79 79 branch"). If you specify source (``-s/--source``), rebase will
80 80 rebase that changeset and all of its descendants onto dest. If you
81 81 specify base (``-b/--base``), rebase will select ancestors of base
82 82 back to but not including the common ancestor with dest. Thus,
83 83 ``-b`` is less precise but more convenient than ``-s``: you can
84 84 specify any changeset in the source branch, and rebase will select
85 85 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
86 86 uses the parent of the working directory as the base.
87 87
88 88 By default, rebase recreates the changesets in the source branch
89 89 as descendants of dest and then destroys the originals. Use
90 90 ``--keep`` to preserve the original source changesets. Some
91 91 changesets in the source branch (e.g. merges from the destination
92 92 branch) may be dropped if they no longer contribute any change.
93 93
94 94 One result of the rules for selecting the destination changeset
95 95 and source branch is that, unlike ``merge``, rebase will do
96 96 nothing if you are at the latest (tipmost) head of a named branch
97 97 with two heads. You need to explicitly specify source and/or
98 98 destination (or ``update`` to the other head, if it's the head of
99 99 the intended source branch).
100 100
101 101 If a rebase is interrupted to manually resolve a merge, it can be
102 102 continued with --continue/-c or aborted with --abort/-a.
103 103
104 104 Returns 0 on success, 1 if nothing to rebase.
105 105 """
106 106 originalwd = target = None
107 107 external = nullrev
108 108 state = {}
109 109 skipped = set()
110 110 targetancestors = set()
111 111
112 112 editor = None
113 113 if opts.get('edit'):
114 114 editor = cmdutil.commitforceeditor
115 115
116 116 lock = wlock = None
117 117 try:
118 118 lock = repo.lock()
119 119 wlock = repo.wlock()
120 120
121 121 # Validate input and define rebasing points
122 122 destf = opts.get('dest', None)
123 123 srcf = opts.get('source', None)
124 124 basef = opts.get('base', None)
125 125 revf = opts.get('rev', [])
126 126 contf = opts.get('continue')
127 127 abortf = opts.get('abort')
128 128 collapsef = opts.get('collapse', False)
129 129 collapsemsg = cmdutil.logmessage(ui, opts)
130 130 extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion
131 131 keepf = opts.get('keep', False)
132 132 keepbranchesf = opts.get('keepbranches', False)
133 133 detachf = opts.get('detach', False)
134 134 # keepopen is not meant for use on the command line, but by
135 135 # other extensions
136 136 keepopen = opts.get('keepopen', False)
137 137
138 138 if collapsemsg and not collapsef:
139 139 raise util.Abort(
140 140 _('message can only be specified with collapse'))
141 141
142 142 if contf or abortf:
143 143 if contf and abortf:
144 144 raise util.Abort(_('cannot use both abort and continue'))
145 145 if collapsef:
146 146 raise util.Abort(
147 147 _('cannot use collapse with continue or abort'))
148 148 if detachf:
149 149 raise util.Abort(_('cannot use detach with continue or abort'))
150 150 if srcf or basef or destf:
151 151 raise util.Abort(
152 152 _('abort and continue do not allow specifying revisions'))
153 153 if opts.get('tool', False):
154 154 ui.warn(_('tool option will be ignored\n'))
155 155
156 156 (originalwd, target, state, skipped, collapsef, keepf,
157 157 keepbranchesf, external) = restorestatus(repo)
158 158 if abortf:
159 159 return abort(repo, originalwd, target, state)
160 160 else:
161 161 if srcf and basef:
162 162 raise util.Abort(_('cannot specify both a '
163 163 'source and a base'))
164 164 if revf and basef:
165 165 raise util.Abort(_('cannot specify both a '
166 166 'revision and a base'))
167 167 if revf and srcf:
168 168 raise util.Abort(_('cannot specify both a '
169 169 'revision and a source'))
170 170 if detachf:
171 171 if not (srcf or revf):
172 172 raise util.Abort(
173 173 _('detach requires a revision to be specified'))
174 174 if basef:
175 175 raise util.Abort(_('cannot specify a base with detach'))
176 176
177 177 cmdutil.bailifchanged(repo)
178 178
179 179 if not destf:
180 180 # Destination defaults to the latest revision in the
181 181 # current branch
182 182 branch = repo[None].branch()
183 183 dest = repo[branch]
184 184 else:
185 185 dest = repo[destf]
186 186
187 187 if revf:
188 188 rebaseset = repo.revs('%lr', revf)
189 189 elif srcf:
190 190 rebaseset = repo.revs('(%r)::', srcf)
191 191 else:
192 192 base = basef or '.'
193 193 rebaseset = repo.revs('(children(ancestor(%r, %d)) & ::%r)::',
194 194 base, dest, base)
195 195
196 if rebaseset:
197 root = min(rebaseset)
198 else:
199 root = None
200
196 201 if not rebaseset:
197 202 repo.ui.debug('base is ancestor of destination')
198 203 result = None
199 204 elif not keepf and list(repo.revs('first(children(%ld) - %ld)',
200 205 rebaseset, rebaseset)):
201 206 raise util.Abort(
202 207 _("can't remove original changesets with"
203 208 " unrebased descendants"),
204 209 hint=_('use --keep to keep original changesets'))
210 elif not keepf and not repo[root].mutable():
211 raise util.Abort(_("Can't rebase immutable changeset %s")
212 % repo[root],
213 hint=_('see hg help phases for details'))
205 214 else:
206 215 result = buildstate(repo, dest, rebaseset, detachf)
207 216
208 217 if not result:
209 218 # Empty state built, nothing to rebase
210 219 ui.status(_('nothing to rebase\n'))
211 220 return 1
212 221 else:
213 222 originalwd, target, state = result
214 223 if collapsef:
215 224 targetancestors = set(repo.changelog.ancestors(target))
216 225 targetancestors.add(target)
217 226 external = checkexternal(repo, state, targetancestors)
218 227
219 228 if keepbranchesf:
220 229 assert not extrafn, 'cannot use both keepbranches and extrafn'
221 230 def extrafn(ctx, extra):
222 231 extra['branch'] = ctx.branch()
223 232 if collapsef:
224 233 branches = set()
225 234 for rev in state:
226 235 branches.add(repo[rev].branch())
227 236 if len(branches) > 1:
228 237 raise util.Abort(_('cannot collapse multiple named '
229 238 'branches'))
230 239
231 240
232 241 # Rebase
233 242 if not targetancestors:
234 243 targetancestors = set(repo.changelog.ancestors(target))
235 244 targetancestors.add(target)
236 245
237 246 # Keep track of the current bookmarks in order to reset them later
238 247 currentbookmarks = repo._bookmarks.copy()
239 248
240 249 sortedstate = sorted(state)
241 250 total = len(sortedstate)
242 251 pos = 0
243 252 for rev in sortedstate:
244 253 pos += 1
245 254 if state[rev] == -1:
246 255 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])),
247 256 _('changesets'), total)
248 257 storestatus(repo, originalwd, target, state, collapsef, keepf,
249 258 keepbranchesf, external)
250 259 p1, p2 = defineparents(repo, rev, target, state,
251 260 targetancestors)
252 261 if len(repo.parents()) == 2:
253 262 repo.ui.debug('resuming interrupted rebase\n')
254 263 else:
255 264 try:
256 265 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
257 266 stats = rebasenode(repo, rev, p1, state)
258 267 if stats and stats[3] > 0:
259 268 raise util.Abort(_('unresolved conflicts (see hg '
260 269 'resolve, then hg rebase --continue)'))
261 270 finally:
262 271 ui.setconfig('ui', 'forcemerge', '')
263 272 cmdutil.duplicatecopies(repo, rev, target, p2)
264 273 if not collapsef:
265 274 newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn,
266 275 editor=editor)
267 276 else:
268 277 # Skip commit if we are collapsing
269 278 repo.dirstate.setparents(repo[p1].node())
270 279 newrev = None
271 280 # Update the state
272 281 if newrev is not None:
273 282 state[rev] = repo[newrev].rev()
274 283 else:
275 284 if not collapsef:
276 285 ui.note(_('no changes, revision %d skipped\n') % rev)
277 286 ui.debug('next revision set to %s\n' % p1)
278 287 skipped.add(rev)
279 288 state[rev] = p1
280 289
281 290 ui.progress(_('rebasing'), None)
282 291 ui.note(_('rebase merging completed\n'))
283 292
284 293 if collapsef and not keepopen:
285 294 p1, p2 = defineparents(repo, min(state), target,
286 295 state, targetancestors)
287 296 if collapsemsg:
288 297 commitmsg = collapsemsg
289 298 else:
290 299 commitmsg = 'Collapsed revision'
291 300 for rebased in state:
292 301 if rebased not in skipped and state[rebased] != nullmerge:
293 302 commitmsg += '\n* %s' % repo[rebased].description()
294 303 commitmsg = ui.edit(commitmsg, repo.ui.username())
295 304 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
296 305 extrafn=extrafn, editor=editor)
297 306
298 307 if 'qtip' in repo.tags():
299 308 updatemq(repo, state, skipped, **opts)
300 309
301 310 if currentbookmarks:
302 311 # Nodeids are needed to reset bookmarks
303 312 nstate = {}
304 313 for k, v in state.iteritems():
305 314 if v != nullmerge:
306 315 nstate[repo[k].node()] = repo[v].node()
307 316
308 317 if not keepf:
309 318 # Remove no more useful revisions
310 319 rebased = [rev for rev in state if state[rev] != nullmerge]
311 320 if rebased:
312 321 if set(repo.changelog.descendants(min(rebased))) - set(state):
313 322 ui.warn(_("warning: new changesets detected "
314 323 "on source branch, not stripping\n"))
315 324 else:
316 325 # backup the old csets by default
317 326 repair.strip(ui, repo, repo[min(rebased)].node(), "all")
318 327
319 328 if currentbookmarks:
320 329 updatebookmarks(repo, nstate, currentbookmarks, **opts)
321 330
322 331 clearstatus(repo)
323 332 ui.note(_("rebase completed\n"))
324 333 if os.path.exists(repo.sjoin('undo')):
325 334 util.unlinkpath(repo.sjoin('undo'))
326 335 if skipped:
327 336 ui.note(_("%d revisions have been skipped\n") % len(skipped))
328 337 finally:
329 338 release(lock, wlock)
330 339
331 340 def checkexternal(repo, state, targetancestors):
332 341 """Check whether one or more external revisions need to be taken in
333 342 consideration. In the latter case, abort.
334 343 """
335 344 external = nullrev
336 345 source = min(state)
337 346 for rev in state:
338 347 if rev == source:
339 348 continue
340 349 # Check externals and fail if there are more than one
341 350 for p in repo[rev].parents():
342 351 if (p.rev() not in state
343 352 and p.rev() not in targetancestors):
344 353 if external != nullrev:
345 354 raise util.Abort(_('unable to collapse, there is more '
346 355 'than one external parent'))
347 356 external = p.rev()
348 357 return external
349 358
350 359 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
351 360 'Commit the changes and store useful information in extra'
352 361 try:
353 362 repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
354 363 ctx = repo[rev]
355 364 if commitmsg is None:
356 365 commitmsg = ctx.description()
357 366 extra = {'rebase_source': ctx.hex()}
358 367 if extrafn:
359 368 extrafn(ctx, extra)
360 369 # Commit might fail if unresolved files exist
361 370 newrev = repo.commit(text=commitmsg, user=ctx.user(),
362 371 date=ctx.date(), extra=extra, editor=editor)
363 372 repo.dirstate.setbranch(repo[newrev].branch())
364 373 return newrev
365 374 except util.Abort:
366 375 # Invalidate the previous setparents
367 376 repo.dirstate.invalidate()
368 377 raise
369 378
370 379 def rebasenode(repo, rev, p1, state):
371 380 'Rebase a single revision'
372 381 # Merge phase
373 382 # Update to target and merge it with local
374 383 if repo['.'].rev() != repo[p1].rev():
375 384 repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
376 385 merge.update(repo, p1, False, True, False)
377 386 else:
378 387 repo.ui.debug(" already in target\n")
379 388 repo.dirstate.write()
380 389 repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
381 390 base = None
382 391 if repo[rev].rev() != repo[min(state)].rev():
383 392 base = repo[rev].p1().node()
384 393 return merge.update(repo, rev, True, True, False, base)
385 394
386 395 def defineparents(repo, rev, target, state, targetancestors):
387 396 'Return the new parent relationship of the revision that will be rebased'
388 397 parents = repo[rev].parents()
389 398 p1 = p2 = nullrev
390 399
391 400 P1n = parents[0].rev()
392 401 if P1n in targetancestors:
393 402 p1 = target
394 403 elif P1n in state:
395 404 if state[P1n] == nullmerge:
396 405 p1 = target
397 406 else:
398 407 p1 = state[P1n]
399 408 else: # P1n external
400 409 p1 = target
401 410 p2 = P1n
402 411
403 412 if len(parents) == 2 and parents[1].rev() not in targetancestors:
404 413 P2n = parents[1].rev()
405 414 # interesting second parent
406 415 if P2n in state:
407 416 if p1 == target: # P1n in targetancestors or external
408 417 p1 = state[P2n]
409 418 else:
410 419 p2 = state[P2n]
411 420 else: # P2n external
412 421 if p2 != nullrev: # P1n external too => rev is a merged revision
413 422 raise util.Abort(_('cannot use revision %d as base, result '
414 423 'would have 3 parents') % rev)
415 424 p2 = P2n
416 425 repo.ui.debug(" future parents are %d and %d\n" %
417 426 (repo[p1].rev(), repo[p2].rev()))
418 427 return p1, p2
419 428
420 429 def isagitpatch(repo, patchname):
421 430 'Return true if the given patch is in git format'
422 431 mqpatch = os.path.join(repo.mq.path, patchname)
423 432 for line in patch.linereader(file(mqpatch, 'rb')):
424 433 if line.startswith('diff --git'):
425 434 return True
426 435 return False
427 436
428 437 def updatemq(repo, state, skipped, **opts):
429 438 'Update rebased mq patches - finalize and then import them'
430 439 mqrebase = {}
431 440 mq = repo.mq
432 441 original_series = mq.fullseries[:]
433 442
434 443 for p in mq.applied:
435 444 rev = repo[p.node].rev()
436 445 if rev in state:
437 446 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
438 447 (rev, p.name))
439 448 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
440 449
441 450 if mqrebase:
442 451 mq.finish(repo, mqrebase.keys())
443 452
444 453 # We must start import from the newest revision
445 454 for rev in sorted(mqrebase, reverse=True):
446 455 if rev not in skipped:
447 456 name, isgit = mqrebase[rev]
448 457 repo.ui.debug('import mq patch %d (%s)\n' % (state[rev], name))
449 458 mq.qimport(repo, (), patchname=name, git=isgit,
450 459 rev=[str(state[rev])])
451 460
452 461 # restore old series to preserve guards
453 462 mq.fullseries = original_series
454 463 mq.series_dirty = True
455 464 mq.savedirty()
456 465
457 466 def updatebookmarks(repo, nstate, originalbookmarks, **opts):
458 467 'Move bookmarks to their correct changesets'
459 468 current = repo._bookmarkcurrent
460 469 for k, v in originalbookmarks.iteritems():
461 470 if v in nstate:
462 471 if nstate[v] != nullmerge:
463 472 # reset the pointer if the bookmark was moved incorrectly
464 473 if k != current:
465 474 repo._bookmarks[k] = nstate[v]
466 475
467 476 bookmarks.write(repo)
468 477
469 478 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
470 479 external):
471 480 'Store the current status to allow recovery'
472 481 f = repo.opener("rebasestate", "w")
473 482 f.write(repo[originalwd].hex() + '\n')
474 483 f.write(repo[target].hex() + '\n')
475 484 f.write(repo[external].hex() + '\n')
476 485 f.write('%d\n' % int(collapse))
477 486 f.write('%d\n' % int(keep))
478 487 f.write('%d\n' % int(keepbranches))
479 488 for d, v in state.iteritems():
480 489 oldrev = repo[d].hex()
481 490 if v != nullmerge:
482 491 newrev = repo[v].hex()
483 492 else:
484 493 newrev = v
485 494 f.write("%s:%s\n" % (oldrev, newrev))
486 495 f.close()
487 496 repo.ui.debug('rebase status stored\n')
488 497
489 498 def clearstatus(repo):
490 499 'Remove the status files'
491 500 if os.path.exists(repo.join("rebasestate")):
492 501 util.unlinkpath(repo.join("rebasestate"))
493 502
494 503 def restorestatus(repo):
495 504 'Restore a previously stored status'
496 505 try:
497 506 target = None
498 507 collapse = False
499 508 external = nullrev
500 509 state = {}
501 510 f = repo.opener("rebasestate")
502 511 for i, l in enumerate(f.read().splitlines()):
503 512 if i == 0:
504 513 originalwd = repo[l].rev()
505 514 elif i == 1:
506 515 target = repo[l].rev()
507 516 elif i == 2:
508 517 external = repo[l].rev()
509 518 elif i == 3:
510 519 collapse = bool(int(l))
511 520 elif i == 4:
512 521 keep = bool(int(l))
513 522 elif i == 5:
514 523 keepbranches = bool(int(l))
515 524 else:
516 525 oldrev, newrev = l.split(':')
517 526 if newrev != str(nullmerge):
518 527 state[repo[oldrev].rev()] = repo[newrev].rev()
519 528 else:
520 529 state[repo[oldrev].rev()] = int(newrev)
521 530 skipped = set()
522 531 # recompute the set of skipped revs
523 532 if not collapse:
524 533 seen = set([target])
525 534 for old, new in sorted(state.items()):
526 535 if new != nullrev and new in seen:
527 536 skipped.add(old)
528 537 seen.add(new)
529 538 repo.ui.debug('computed skipped revs: %s\n' % skipped)
530 539 repo.ui.debug('rebase status resumed\n')
531 540 return (originalwd, target, state, skipped,
532 541 collapse, keep, keepbranches, external)
533 542 except IOError, err:
534 543 if err.errno != errno.ENOENT:
535 544 raise
536 545 raise util.Abort(_('no rebase in progress'))
537 546
538 547 def abort(repo, originalwd, target, state):
539 548 'Restore the repository to its original state'
540 549 if set(repo.changelog.descendants(target)) - set(state.values()):
541 550 repo.ui.warn(_("warning: new changesets detected on target branch, "
542 551 "can't abort\n"))
543 552 return -1
544 553 else:
545 554 # Strip from the first rebased revision
546 555 merge.update(repo, repo[originalwd].rev(), False, True, False)
547 556 rebased = filter(lambda x: x > -1 and x != target, state.values())
548 557 if rebased:
549 558 strippoint = min(rebased)
550 559 # no backup of rebased cset versions needed
551 560 repair.strip(repo.ui, repo, repo[strippoint].node())
552 561 clearstatus(repo)
553 562 repo.ui.warn(_('rebase aborted\n'))
554 563 return 0
555 564
556 565 def buildstate(repo, dest, rebaseset, detach):
557 566 '''Define which revisions are going to be rebased and where
558 567
559 568 repo: repo
560 569 dest: context
561 570 rebaseset: set of rev
562 571 detach: boolean'''
563 572
564 573 # This check isn't strictly necessary, since mq detects commits over an
565 574 # applied patch. But it prevents messing up the working directory when
566 575 # a partially completed rebase is blocked by mq.
567 576 if 'qtip' in repo.tags() and (dest.node() in
568 577 [s.node for s in repo.mq.applied]):
569 578 raise util.Abort(_('cannot rebase onto an applied mq patch'))
570 579
571 580 detachset = set()
572 581 roots = list(repo.set('roots(%ld)', rebaseset))
573 582 if not roots:
574 583 raise util.Abort(_('no matching revisions'))
575 584 if len(roots) > 1:
576 585 raise util.Abort(_("can't rebase multiple roots"))
577 586 root = roots[0]
578 587
579 588 commonbase = root.ancestor(dest)
580 589 if commonbase == root:
581 590 raise util.Abort(_('source is ancestor of destination'))
582 591 if commonbase == dest:
583 592 samebranch = root.branch() == dest.branch()
584 593 if samebranch and root in dest.children():
585 594 repo.ui.debug('source is a child of destination')
586 595 return None
587 596 # rebase on ancestor, force detach
588 597 detach = True
589 598 if detach:
590 599 detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root)
591 600
592 601 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root))
593 602 state = dict.fromkeys(rebaseset, nullrev)
594 603 state.update(dict.fromkeys(detachset, nullmerge))
595 604 return repo['.'].rev(), dest.rev(), state
596 605
597 606 def pullrebase(orig, ui, repo, *args, **opts):
598 607 'Call rebase after pull if the latter has been invoked with --rebase'
599 608 if opts.get('rebase'):
600 609 if opts.get('update'):
601 610 del opts['update']
602 611 ui.debug('--update and --rebase are not compatible, ignoring '
603 612 'the update flag\n')
604 613
605 614 cmdutil.bailifchanged(repo)
606 615 revsprepull = len(repo)
607 616 origpostincoming = commands.postincoming
608 617 def _dummy(*args, **kwargs):
609 618 pass
610 619 commands.postincoming = _dummy
611 620 try:
612 621 orig(ui, repo, *args, **opts)
613 622 finally:
614 623 commands.postincoming = origpostincoming
615 624 revspostpull = len(repo)
616 625 if revspostpull > revsprepull:
617 626 rebase(ui, repo, **opts)
618 627 branch = repo[None].branch()
619 628 dest = repo[branch].rev()
620 629 if dest != repo['.'].rev():
621 630 # there was nothing to rebase we force an update
622 631 hg.update(repo, dest)
623 632 else:
624 633 if opts.get('tool'):
625 634 raise util.Abort(_('--tool can only be used with --rebase'))
626 635 orig(ui, repo, *args, **opts)
627 636
628 637 def uisetup(ui):
629 638 'Replace pull with a decorator to provide --rebase option'
630 639 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
631 640 entry[1].append(('', 'rebase', None,
632 641 _("rebase working directory to branch head")))
633 642 entry[1].append(('t', 'tool', '',
634 643 _("specify merge tool for rebase")))
@@ -1,427 +1,427 b''
1 1 # store.py - repository store handling for Mercurial
2 2 #
3 3 # Copyright 2008 Matt Mackall <mpm@selenic.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 from i18n import _
9 9 import osutil, scmutil, util
10 10 import os, stat
11 11
12 12 _sha = util.sha1
13 13
14 14 # This avoids a collision between a file named foo and a dir named
15 15 # foo.i or foo.d
16 16 def encodedir(path):
17 17 '''
18 18 >>> encodedir('data/foo.i')
19 19 'data/foo.i'
20 20 >>> encodedir('data/foo.i/bla.i')
21 21 'data/foo.i.hg/bla.i'
22 22 >>> encodedir('data/foo.i.hg/bla.i')
23 23 'data/foo.i.hg.hg/bla.i'
24 24 '''
25 25 if not path.startswith('data/'):
26 26 return path
27 27 return (path
28 28 .replace(".hg/", ".hg.hg/")
29 29 .replace(".i/", ".i.hg/")
30 30 .replace(".d/", ".d.hg/"))
31 31
32 32 def decodedir(path):
33 33 '''
34 34 >>> decodedir('data/foo.i')
35 35 'data/foo.i'
36 36 >>> decodedir('data/foo.i.hg/bla.i')
37 37 'data/foo.i/bla.i'
38 38 >>> decodedir('data/foo.i.hg.hg/bla.i')
39 39 'data/foo.i.hg/bla.i'
40 40 '''
41 41 if not path.startswith('data/') or ".hg/" not in path:
42 42 return path
43 43 return (path
44 44 .replace(".d.hg/", ".d/")
45 45 .replace(".i.hg/", ".i/")
46 46 .replace(".hg.hg/", ".hg/"))
47 47
48 48 def _buildencodefun():
49 49 '''
50 50 >>> enc, dec = _buildencodefun()
51 51
52 52 >>> enc('nothing/special.txt')
53 53 'nothing/special.txt'
54 54 >>> dec('nothing/special.txt')
55 55 'nothing/special.txt'
56 56
57 57 >>> enc('HELLO')
58 58 '_h_e_l_l_o'
59 59 >>> dec('_h_e_l_l_o')
60 60 'HELLO'
61 61
62 62 >>> enc('hello:world?')
63 63 'hello~3aworld~3f'
64 64 >>> dec('hello~3aworld~3f')
65 65 'hello:world?'
66 66
67 67 >>> enc('the\x07quick\xADshot')
68 68 'the~07quick~adshot'
69 69 >>> dec('the~07quick~adshot')
70 70 'the\\x07quick\\xadshot'
71 71 '''
72 72 e = '_'
73 73 winreserved = [ord(x) for x in '\\:*?"<>|']
74 74 cmap = dict([(chr(x), chr(x)) for x in xrange(127)])
75 75 for x in (range(32) + range(126, 256) + winreserved):
76 76 cmap[chr(x)] = "~%02x" % x
77 77 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
78 78 cmap[chr(x)] = e + chr(x).lower()
79 79 dmap = {}
80 80 for k, v in cmap.iteritems():
81 81 dmap[v] = k
82 82 def decode(s):
83 83 i = 0
84 84 while i < len(s):
85 85 for l in xrange(1, 4):
86 86 try:
87 87 yield dmap[s[i:i + l]]
88 88 i += l
89 89 break
90 90 except KeyError:
91 91 pass
92 92 else:
93 93 raise KeyError
94 94 return (lambda s: "".join([cmap[c] for c in encodedir(s)]),
95 95 lambda s: decodedir("".join(list(decode(s)))))
96 96
97 97 encodefilename, decodefilename = _buildencodefun()
98 98
99 99 def _buildlowerencodefun():
100 100 '''
101 101 >>> f = _buildlowerencodefun()
102 102 >>> f('nothing/special.txt')
103 103 'nothing/special.txt'
104 104 >>> f('HELLO')
105 105 'hello'
106 106 >>> f('hello:world?')
107 107 'hello~3aworld~3f'
108 108 >>> f('the\x07quick\xADshot')
109 109 'the~07quick~adshot'
110 110 '''
111 111 winreserved = [ord(x) for x in '\\:*?"<>|']
112 112 cmap = dict([(chr(x), chr(x)) for x in xrange(127)])
113 113 for x in (range(32) + range(126, 256) + winreserved):
114 114 cmap[chr(x)] = "~%02x" % x
115 115 for x in range(ord("A"), ord("Z")+1):
116 116 cmap[chr(x)] = chr(x).lower()
117 117 return lambda s: "".join([cmap[c] for c in s])
118 118
119 119 lowerencode = _buildlowerencodefun()
120 120
121 121 _winreservednames = '''con prn aux nul
122 122 com1 com2 com3 com4 com5 com6 com7 com8 com9
123 123 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
124 124 def _auxencode(path, dotencode):
125 125 '''
126 126 Encodes filenames containing names reserved by Windows or which end in
127 127 period or space. Does not touch other single reserved characters c.
128 128 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
129 129 Additionally encodes space or period at the beginning, if dotencode is
130 130 True.
131 131 path is assumed to be all lowercase.
132 132
133 133 >>> _auxencode('.foo/aux.txt/txt.aux/con/prn/nul/foo.', True)
134 134 '~2efoo/au~78.txt/txt.aux/co~6e/pr~6e/nu~6c/foo~2e'
135 135 >>> _auxencode('.com1com2/lpt9.lpt4.lpt1/conprn/foo.', False)
136 136 '.com1com2/lp~749.lpt4.lpt1/conprn/foo~2e'
137 137 >>> _auxencode('foo. ', True)
138 138 'foo.~20'
139 139 >>> _auxencode(' .foo', True)
140 140 '~20.foo'
141 141 '''
142 142 res = []
143 143 for n in path.split('/'):
144 144 if n:
145 145 base = n.split('.')[0]
146 146 if base and (base in _winreservednames):
147 147 # encode third letter ('aux' -> 'au~78')
148 148 ec = "~%02x" % ord(n[2])
149 149 n = n[0:2] + ec + n[3:]
150 150 if n[-1] in '. ':
151 151 # encode last period or space ('foo...' -> 'foo..~2e')
152 152 n = n[:-1] + "~%02x" % ord(n[-1])
153 153 if dotencode and n[0] in '. ':
154 154 n = "~%02x" % ord(n[0]) + n[1:]
155 155 res.append(n)
156 156 return '/'.join(res)
157 157
158 158 _maxstorepathlen = 120
159 159 _dirprefixlen = 8
160 160 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
161 161 def _hybridencode(path, auxencode):
162 162 '''encodes path with a length limit
163 163
164 164 Encodes all paths that begin with 'data/', according to the following.
165 165
166 166 Default encoding (reversible):
167 167
168 168 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
169 169 characters are encoded as '~xx', where xx is the two digit hex code
170 170 of the character (see encodefilename).
171 171 Relevant path components consisting of Windows reserved filenames are
172 172 masked by encoding the third character ('aux' -> 'au~78', see auxencode).
173 173
174 174 Hashed encoding (not reversible):
175 175
176 176 If the default-encoded path is longer than _maxstorepathlen, a
177 177 non-reversible hybrid hashing of the path is done instead.
178 178 This encoding uses up to _dirprefixlen characters of all directory
179 179 levels of the lowerencoded path, but not more levels than can fit into
180 180 _maxshortdirslen.
181 181 Then follows the filler followed by the sha digest of the full path.
182 182 The filler is the beginning of the basename of the lowerencoded path
183 183 (the basename is everything after the last path separator). The filler
184 184 is as long as possible, filling in characters from the basename until
185 185 the encoded path has _maxstorepathlen characters (or all chars of the
186 186 basename have been taken).
187 187 The extension (e.g. '.i' or '.d') is preserved.
188 188
189 189 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
190 190 encoding was used.
191 191 '''
192 192 if not path.startswith('data/'):
193 193 return path
194 194 # escape directories ending with .i and .d
195 195 path = encodedir(path)
196 196 ndpath = path[len('data/'):]
197 197 res = 'data/' + auxencode(encodefilename(ndpath))
198 198 if len(res) > _maxstorepathlen:
199 199 digest = _sha(path).hexdigest()
200 200 aep = auxencode(lowerencode(ndpath))
201 201 _root, ext = os.path.splitext(aep)
202 202 parts = aep.split('/')
203 203 basename = parts[-1]
204 204 sdirs = []
205 205 for p in parts[:-1]:
206 206 d = p[:_dirprefixlen]
207 207 if d[-1] in '. ':
208 208 # Windows can't access dirs ending in period or space
209 209 d = d[:-1] + '_'
210 210 t = '/'.join(sdirs) + '/' + d
211 211 if len(t) > _maxshortdirslen:
212 212 break
213 213 sdirs.append(d)
214 214 dirs = '/'.join(sdirs)
215 215 if len(dirs) > 0:
216 216 dirs += '/'
217 217 res = 'dh/' + dirs + digest + ext
218 218 spaceleft = _maxstorepathlen - len(res)
219 219 if spaceleft > 0:
220 220 filler = basename[:spaceleft]
221 221 res = 'dh/' + dirs + filler + digest + ext
222 222 return res
223 223
224 224 def _calcmode(path):
225 225 try:
226 226 # files in .hg/ will be created using this mode
227 227 mode = os.stat(path).st_mode
228 228 # avoid some useless chmods
229 229 if (0777 & ~util.umask) == (0777 & mode):
230 230 mode = None
231 231 except OSError:
232 232 mode = None
233 233 return mode
234 234
235 235 _data = 'data 00manifest.d 00manifest.i 00changelog.d 00changelog.i phaseroots'
236 236
237 237 class basicstore(object):
238 238 '''base class for local repository stores'''
239 239 def __init__(self, path, openertype):
240 240 self.path = path
241 241 self.createmode = _calcmode(path)
242 242 op = openertype(self.path)
243 243 op.createmode = self.createmode
244 244 self.opener = scmutil.filteropener(op, encodedir)
245 245
246 246 def join(self, f):
247 247 return self.path + '/' + encodedir(f)
248 248
249 249 def _walk(self, relpath, recurse):
250 250 '''yields (unencoded, encoded, size)'''
251 251 path = self.path
252 252 if relpath:
253 253 path += '/' + relpath
254 254 striplen = len(self.path) + 1
255 255 l = []
256 256 if os.path.isdir(path):
257 257 visit = [path]
258 258 while visit:
259 259 p = visit.pop()
260 260 for f, kind, st in osutil.listdir(p, stat=True):
261 261 fp = p + '/' + f
262 262 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
263 263 n = util.pconvert(fp[striplen:])
264 264 l.append((decodedir(n), n, st.st_size))
265 265 elif kind == stat.S_IFDIR and recurse:
266 266 visit.append(fp)
267 267 return sorted(l)
268 268
269 269 def datafiles(self):
270 270 return self._walk('data', True)
271 271
272 272 def walk(self):
273 273 '''yields (unencoded, encoded, size)'''
274 274 # yield data files first
275 275 for x in self.datafiles():
276 276 yield x
277 277 # yield manifest before changelog
278 278 for x in reversed(self._walk('', False)):
279 279 yield x
280 280
281 281 def copylist(self):
282 282 return ['requires'] + _data.split()
283 283
284 284 def write(self):
285 285 pass
286 286
287 287 class encodedstore(basicstore):
288 288 def __init__(self, path, openertype):
289 289 self.path = path + '/store'
290 290 self.createmode = _calcmode(self.path)
291 291 op = openertype(self.path)
292 292 op.createmode = self.createmode
293 293 self.opener = scmutil.filteropener(op, encodefilename)
294 294
295 295 def datafiles(self):
296 296 for a, b, size in self._walk('data', True):
297 297 try:
298 298 a = decodefilename(a)
299 299 except KeyError:
300 300 a = None
301 301 yield a, b, size
302 302
303 303 def join(self, f):
304 304 return self.path + '/' + encodefilename(f)
305 305
306 306 def copylist(self):
307 307 return (['requires', '00changelog.i'] +
308 308 ['store/' + f for f in _data.split()])
309 309
310 310 class fncache(object):
311 311 # the filename used to be partially encoded
312 312 # hence the encodedir/decodedir dance
313 313 def __init__(self, opener):
314 314 self.opener = opener
315 315 self.entries = None
316 316 self._dirty = False
317 317
318 318 def _load(self):
319 319 '''fill the entries from the fncache file'''
320 320 self.entries = set()
321 321 self._dirty = False
322 322 try:
323 323 fp = self.opener('fncache', mode='rb')
324 324 except IOError:
325 325 # skip nonexistent file
326 326 return
327 327 for n, line in enumerate(fp):
328 328 if (len(line) < 2) or (line[-1] != '\n'):
329 329 t = _('invalid entry in fncache, line %s') % (n + 1)
330 330 raise util.Abort(t)
331 331 self.entries.add(decodedir(line[:-1]))
332 332 fp.close()
333 333
334 334 def rewrite(self, files):
335 335 fp = self.opener('fncache', mode='wb')
336 336 for p in files:
337 337 fp.write(encodedir(p) + '\n')
338 338 fp.close()
339 339 self.entries = set(files)
340 340 self._dirty = False
341 341
342 342 def write(self):
343 343 if not self._dirty:
344 344 return
345 345 fp = self.opener('fncache', mode='wb', atomictemp=True)
346 346 for p in self.entries:
347 347 fp.write(encodedir(p) + '\n')
348 348 fp.close()
349 349 self._dirty = False
350 350
351 351 def add(self, fn):
352 352 if self.entries is None:
353 353 self._load()
354 354 if fn not in self.entries:
355 355 self._dirty = True
356 356 self.entries.add(fn)
357 357
358 358 def __contains__(self, fn):
359 359 if self.entries is None:
360 360 self._load()
361 361 return fn in self.entries
362 362
363 363 def __iter__(self):
364 364 if self.entries is None:
365 365 self._load()
366 366 return iter(self.entries)
367 367
368 368 class _fncacheopener(scmutil.abstractopener):
369 369 def __init__(self, op, fnc, encode):
370 370 self.opener = op
371 371 self.fncache = fnc
372 372 self.encode = encode
373 373
374 374 def __call__(self, path, mode='r', *args, **kw):
375 375 if mode not in ('r', 'rb') and path.startswith('data/'):
376 376 self.fncache.add(path)
377 377 return self.opener(self.encode(path), mode, *args, **kw)
378 378
379 379 class fncachestore(basicstore):
380 380 def __init__(self, path, openertype, encode):
381 381 self.encode = encode
382 382 self.path = path + '/store'
383 383 self.createmode = _calcmode(self.path)
384 384 op = openertype(self.path)
385 385 op.createmode = self.createmode
386 386 fnc = fncache(op)
387 387 self.fncache = fnc
388 388 self.opener = _fncacheopener(op, fnc, encode)
389 389
390 390 def join(self, f):
391 391 return self.path + '/' + self.encode(f)
392 392
393 393 def datafiles(self):
394 394 rewrite = False
395 395 existing = []
396 396 spath = self.path
397 397 for f in self.fncache:
398 398 ef = self.encode(f)
399 399 try:
400 400 st = os.stat(spath + '/' + ef)
401 401 yield f, ef, st.st_size
402 402 existing.append(f)
403 403 except OSError:
404 404 # nonexistent entry
405 405 rewrite = True
406 406 if rewrite:
407 407 # rewrite fncache to remove nonexistent entries
408 408 # (may be caused by rollback / strip)
409 409 self.fncache.rewrite(existing)
410 410
411 411 def copylist(self):
412 d = ('data dh fncache'
413 ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i phaseroots')
412 d = ('data dh fncache phaseroots'
413 ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i')
414 414 return (['requires', '00changelog.i'] +
415 415 ['store/' + f for f in d.split()])
416 416
417 417 def write(self):
418 418 self.fncache.write()
419 419
420 420 def store(requirements, path, openertype):
421 421 if 'store' in requirements:
422 422 if 'fncache' in requirements:
423 423 auxencode = lambda f: _auxencode(f, 'dotencode' in requirements)
424 424 encode = lambda f: _hybridencode(f, auxencode)
425 425 return fncachestore(path, openertype, encode)
426 426 return encodedstore(path, openertype)
427 427 return basicstore(path, openertype)
@@ -1,877 +1,879 b''
1 1 $ "$TESTDIR/hghave" symlink unix-permissions serve || exit 80
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles=
6 6 > purge=
7 7 > rebase=
8 8 > transplant=
9 > [phases]
10 > publish=False
9 11 > [largefiles]
10 12 > minsize=2
11 13 > patterns=glob:**.dat
12 14 > EOF
13 15
14 16 Create the repo with a couple of revisions of both large and normal
15 17 files, testing that status correctly shows largefiles.
16 18
17 19 $ hg init a
18 20 $ cd a
19 21 $ mkdir sub
20 22 $ echo normal1 > normal1
21 23 $ echo normal2 > sub/normal2
22 24 $ echo large1 > large1
23 25 $ echo large2 > sub/large2
24 26 $ hg add normal1 sub/normal2
25 27 $ hg add --large large1 sub/large2
26 28 $ hg commit -m "add files"
27 29 $ echo normal11 > normal1
28 30 $ echo normal22 > sub/normal2
29 31 $ echo large11 > large1
30 32 $ echo large22 > sub/large2
31 33 $ hg st
32 34 M large1
33 35 M normal1
34 36 M sub/large2
35 37 M sub/normal2
36 38 $ hg commit -m "edit files"
37 39
38 40 Commit preserved largefile contents.
39 41
40 42 $ cat normal1
41 43 normal11
42 44 $ cat large1
43 45 large11
44 46 $ cat sub/normal2
45 47 normal22
46 48 $ cat sub/large2
47 49 large22
48 50
49 51 Remove both largefiles and normal files.
50 52
51 53 $ hg remove normal1 large1
52 54 $ hg commit -m "remove files"
53 55 $ ls
54 56 sub
55 57
56 58 Copy both largefiles and normal files (testing that status output is correct).
57 59
58 60 $ hg cp sub/normal2 normal1
59 61 $ hg cp sub/large2 large1
60 62 $ hg st
61 63 A large1
62 64 A normal1
63 65 $ hg commit -m "copy files"
64 66 $ cat normal1
65 67 normal22
66 68 $ cat large1
67 69 large22
68 70
69 71 Test moving largefiles and verify that normal files are also unaffected.
70 72
71 73 $ hg mv normal1 normal3
72 74 $ hg mv large1 large3
73 75 $ hg mv sub/normal2 sub/normal4
74 76 $ hg mv sub/large2 sub/large4
75 77 $ hg commit -m "move files"
76 78 $ cat normal3
77 79 normal22
78 80 $ cat large3
79 81 large22
80 82 $ cat sub/normal4
81 83 normal22
82 84 $ cat sub/large4
83 85 large22
84 86
85 87 Test archiving the various revisions. These hit corner cases known with
86 88 archiving.
87 89
88 90 $ hg archive -r 0 ../archive0
89 91 $ hg archive -r 1 ../archive1
90 92 $ hg archive -r 2 ../archive2
91 93 $ hg archive -r 3 ../archive3
92 94 $ hg archive -r 4 ../archive4
93 95 $ cd ../archive0
94 96 $ cat normal1
95 97 normal1
96 98 $ cat large1
97 99 large1
98 100 $ cat sub/normal2
99 101 normal2
100 102 $ cat sub/large2
101 103 large2
102 104 $ cd ../archive1
103 105 $ cat normal1
104 106 normal11
105 107 $ cat large1
106 108 large11
107 109 $ cat sub/normal2
108 110 normal22
109 111 $ cat sub/large2
110 112 large22
111 113 $ cd ../archive2
112 114 $ ls
113 115 sub
114 116 $ cat sub/normal2
115 117 normal22
116 118 $ cat sub/large2
117 119 large22
118 120 $ cd ../archive3
119 121 $ cat normal1
120 122 normal22
121 123 $ cat large1
122 124 large22
123 125 $ cat sub/normal2
124 126 normal22
125 127 $ cat sub/large2
126 128 large22
127 129 $ cd ../archive4
128 130 $ cat normal3
129 131 normal22
130 132 $ cat large3
131 133 large22
132 134 $ cat sub/normal4
133 135 normal22
134 136 $ cat sub/large4
135 137 large22
136 138
137 139 Commit corner case: specify files to commit.
138 140
139 141 $ cd ../a
140 142 $ echo normal3 > normal3
141 143 $ echo large3 > large3
142 144 $ echo normal4 > sub/normal4
143 145 $ echo large4 > sub/large4
144 146 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
145 147 $ cat normal3
146 148 normal3
147 149 $ cat large3
148 150 large3
149 151 $ cat sub/normal4
150 152 normal4
151 153 $ cat sub/large4
152 154 large4
153 155
154 156 One more commit corner case: commit from a subdirectory.
155 157
156 158 $ cd ../a
157 159 $ echo normal33 > normal3
158 160 $ echo large33 > large3
159 161 $ echo normal44 > sub/normal4
160 162 $ echo large44 > sub/large4
161 163 $ cd sub
162 164 $ hg commit -m "edit files yet again"
163 165 $ cat ../normal3
164 166 normal33
165 167 $ cat ../large3
166 168 large33
167 169 $ cat normal4
168 170 normal44
169 171 $ cat large4
170 172 large44
171 173
172 174 Committing standins is not allowed.
173 175
174 176 $ cd ..
175 177 $ echo large3 > large3
176 178 $ hg commit .hglf/large3 -m "try to commit standin"
177 179 abort: file ".hglf/large3" is a largefile standin
178 180 (commit the largefile itself instead)
179 181 [255]
180 182
181 183 Corner cases for adding largefiles.
182 184
183 185 $ echo large5 > large5
184 186 $ hg add --large large5
185 187 $ hg add --large large5
186 188 large5 already a largefile
187 189 $ mkdir sub2
188 190 $ echo large6 > sub2/large6
189 191 $ echo large7 > sub2/large7
190 192 $ hg add --large sub2
191 193 adding sub2/large6 as a largefile (glob)
192 194 adding sub2/large7 as a largefile (glob)
193 195 $ hg st
194 196 M large3
195 197 A large5
196 198 A sub2/large6
197 199 A sub2/large7
198 200
199 201 Config settings (pattern **.dat, minsize 2 MB) are respected.
200 202
201 203 $ echo testdata > test.dat
202 204 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
203 205 $ hg add
204 206 adding reallylarge as a largefile
205 207 adding test.dat as a largefile
206 208
207 209 Test that minsize and --lfsize handle float values;
208 210 also tests that --lfsize overrides largefiles.minsize.
209 211 (0.250 MB = 256 kB = 262144 B)
210 212
211 213 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
212 214 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
213 215 $ hg --config largefiles.minsize=.25 add
214 216 adding ratherlarge as a largefile
215 217 adding medium
216 218 $ hg forget medium
217 219 $ hg --config largefiles.minsize=.25 add --lfsize=.125
218 220 adding medium as a largefile
219 221 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
220 222 $ hg --config largefiles.minsize=.25 add --lfsize=.125
221 223 adding notlarge
222 224 $ hg forget notlarge
223 225
224 226 Test forget on largefiles.
225 227
226 228 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
227 229 $ hg st
228 230 A sub2/large6
229 231 A sub2/large7
230 232 R large3
231 233 ? large5
232 234 ? medium
233 235 ? notlarge
234 236 ? ratherlarge
235 237 ? reallylarge
236 238 ? test.dat
237 239 $ hg commit -m "add/edit more largefiles"
238 240 $ hg st
239 241 ? large3
240 242 ? large5
241 243 ? medium
242 244 ? notlarge
243 245 ? ratherlarge
244 246 ? reallylarge
245 247 ? test.dat
246 248
247 249 Purge with largefiles: verify that largefiles are still in the working
248 250 dir after a purge.
249 251
250 252 $ hg purge --all
251 253 $ cat sub/large4
252 254 large44
253 255 $ cat sub2/large6
254 256 large6
255 257 $ cat sub2/large7
256 258 large7
257 259
258 260 Clone a largefiles repo.
259 261
260 262 $ hg clone . ../b
261 263 updating to branch default
262 264 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 265 getting changed largefiles
264 266 3 largefiles updated, 0 removed
265 267 $ cd ../b
266 268 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
267 269 7:daea875e9014 add/edit more largefiles
268 270 6:4355d653f84f edit files yet again
269 271 5:9d5af5072dbd edit files again
270 272 4:74c02385b94c move files
271 273 3:9e8fbc4bce62 copy files
272 274 2:51a0ae4d5864 remove files
273 275 1:ce8896473775 edit files
274 276 0:30d30fe6a5be add files
275 277 $ cat normal3
276 278 normal33
277 279 $ cat sub/normal4
278 280 normal44
279 281 $ cat sub/large4
280 282 large44
281 283 $ cat sub2/large6
282 284 large6
283 285 $ cat sub2/large7
284 286 large7
285 287 $ cd ..
286 288 $ hg clone a -r 3 c
287 289 adding changesets
288 290 adding manifests
289 291 adding file changes
290 292 added 4 changesets with 10 changes to 4 files
291 293 updating to branch default
292 294 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 295 getting changed largefiles
294 296 2 largefiles updated, 0 removed
295 297 $ cd c
296 298 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
297 299 3:9e8fbc4bce62 copy files
298 300 2:51a0ae4d5864 remove files
299 301 1:ce8896473775 edit files
300 302 0:30d30fe6a5be add files
301 303 $ cat normal1
302 304 normal22
303 305 $ cat large1
304 306 large22
305 307 $ cat sub/normal2
306 308 normal22
307 309 $ cat sub/large2
308 310 large22
309 311
310 312 Old revisions of a clone have correct largefiles content (this also
311 313 tests update).
312 314
313 315 $ hg update -r 1
314 316 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 317 getting changed largefiles
316 318 1 largefiles updated, 0 removed
317 319 $ cat large1
318 320 large11
319 321 $ cat sub/large2
320 322 large22
321 323
322 324 Rebasing between two repositories does not revert largefiles to old
323 325 revisions (this was a very bad bug that took a lot of work to fix).
324 326
325 327 $ cd ..
326 328 $ hg clone a d
327 329 updating to branch default
328 330 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 331 getting changed largefiles
330 332 3 largefiles updated, 0 removed
331 333 $ cd b
332 334 $ echo large4-modified > sub/large4
333 335 $ echo normal3-modified > normal3
334 336 $ hg commit -m "modify normal file and largefile in repo b"
335 337 $ cd ../d
336 338 $ echo large6-modified > sub2/large6
337 339 $ echo normal4-modified > sub/normal4
338 340 $ hg commit -m "modify normal file largefile in repo d"
339 341 $ cd ..
340 342 $ hg clone d e
341 343 updating to branch default
342 344 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 345 getting changed largefiles
344 346 3 largefiles updated, 0 removed
345 347 $ cd d
346 348 $ hg pull --rebase ../b
347 349 pulling from ../b
348 350 searching for changes
349 351 adding changesets
350 352 adding manifests
351 353 adding file changes
352 354 added 1 changesets with 2 changes to 2 files (+1 heads)
353 355 getting changed largefiles
354 356 1 largefiles updated, 0 removed
355 357 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
356 358 nothing to rebase
357 359 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
358 360 9:598410d3eb9a modify normal file largefile in repo d
359 361 8:a381d2c8c80e modify normal file and largefile in repo b
360 362 7:daea875e9014 add/edit more largefiles
361 363 6:4355d653f84f edit files yet again
362 364 5:9d5af5072dbd edit files again
363 365 4:74c02385b94c move files
364 366 3:9e8fbc4bce62 copy files
365 367 2:51a0ae4d5864 remove files
366 368 1:ce8896473775 edit files
367 369 0:30d30fe6a5be add files
368 370 $ cat normal3
369 371 normal3-modified
370 372 $ cat sub/normal4
371 373 normal4-modified
372 374 $ cat sub/large4
373 375 large4-modified
374 376 $ cat sub2/large6
375 377 large6-modified
376 378 $ cat sub2/large7
377 379 large7
378 380 $ cd ../e
379 381 $ hg pull ../b
380 382 pulling from ../b
381 383 searching for changes
382 384 adding changesets
383 385 adding manifests
384 386 adding file changes
385 387 added 1 changesets with 2 changes to 2 files (+1 heads)
386 388 (run 'hg heads' to see heads, 'hg merge' to merge)
387 389 $ hg rebase
388 390 getting changed largefiles
389 391 1 largefiles updated, 0 removed
390 392 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
391 393 $ hg log
392 394 changeset: 9:598410d3eb9a
393 395 tag: tip
394 396 user: test
395 397 date: Thu Jan 01 00:00:00 1970 +0000
396 398 summary: modify normal file largefile in repo d
397 399
398 400 changeset: 8:a381d2c8c80e
399 401 user: test
400 402 date: Thu Jan 01 00:00:00 1970 +0000
401 403 summary: modify normal file and largefile in repo b
402 404
403 405 changeset: 7:daea875e9014
404 406 user: test
405 407 date: Thu Jan 01 00:00:00 1970 +0000
406 408 summary: add/edit more largefiles
407 409
408 410 changeset: 6:4355d653f84f
409 411 user: test
410 412 date: Thu Jan 01 00:00:00 1970 +0000
411 413 summary: edit files yet again
412 414
413 415 changeset: 5:9d5af5072dbd
414 416 user: test
415 417 date: Thu Jan 01 00:00:00 1970 +0000
416 418 summary: edit files again
417 419
418 420 changeset: 4:74c02385b94c
419 421 user: test
420 422 date: Thu Jan 01 00:00:00 1970 +0000
421 423 summary: move files
422 424
423 425 changeset: 3:9e8fbc4bce62
424 426 user: test
425 427 date: Thu Jan 01 00:00:00 1970 +0000
426 428 summary: copy files
427 429
428 430 changeset: 2:51a0ae4d5864
429 431 user: test
430 432 date: Thu Jan 01 00:00:00 1970 +0000
431 433 summary: remove files
432 434
433 435 changeset: 1:ce8896473775
434 436 user: test
435 437 date: Thu Jan 01 00:00:00 1970 +0000
436 438 summary: edit files
437 439
438 440 changeset: 0:30d30fe6a5be
439 441 user: test
440 442 date: Thu Jan 01 00:00:00 1970 +0000
441 443 summary: add files
442 444
443 445 $ cat normal3
444 446 normal3-modified
445 447 $ cat sub/normal4
446 448 normal4-modified
447 449 $ cat sub/large4
448 450 large4-modified
449 451 $ cat sub2/large6
450 452 large6-modified
451 453 $ cat sub2/large7
452 454 large7
453 455
454 456 Rollback on largefiles.
455 457
456 458 $ echo large4-modified-again > sub/large4
457 459 $ hg commit -m "Modify large4 again"
458 460 $ hg rollback
459 461 repository tip rolled back to revision 9 (undo commit)
460 462 working directory now based on revision 9
461 463 $ hg st
462 464 M sub/large4
463 465 $ hg log
464 466 changeset: 9:598410d3eb9a
465 467 tag: tip
466 468 user: test
467 469 date: Thu Jan 01 00:00:00 1970 +0000
468 470 summary: modify normal file largefile in repo d
469 471
470 472 changeset: 8:a381d2c8c80e
471 473 user: test
472 474 date: Thu Jan 01 00:00:00 1970 +0000
473 475 summary: modify normal file and largefile in repo b
474 476
475 477 changeset: 7:daea875e9014
476 478 user: test
477 479 date: Thu Jan 01 00:00:00 1970 +0000
478 480 summary: add/edit more largefiles
479 481
480 482 changeset: 6:4355d653f84f
481 483 user: test
482 484 date: Thu Jan 01 00:00:00 1970 +0000
483 485 summary: edit files yet again
484 486
485 487 changeset: 5:9d5af5072dbd
486 488 user: test
487 489 date: Thu Jan 01 00:00:00 1970 +0000
488 490 summary: edit files again
489 491
490 492 changeset: 4:74c02385b94c
491 493 user: test
492 494 date: Thu Jan 01 00:00:00 1970 +0000
493 495 summary: move files
494 496
495 497 changeset: 3:9e8fbc4bce62
496 498 user: test
497 499 date: Thu Jan 01 00:00:00 1970 +0000
498 500 summary: copy files
499 501
500 502 changeset: 2:51a0ae4d5864
501 503 user: test
502 504 date: Thu Jan 01 00:00:00 1970 +0000
503 505 summary: remove files
504 506
505 507 changeset: 1:ce8896473775
506 508 user: test
507 509 date: Thu Jan 01 00:00:00 1970 +0000
508 510 summary: edit files
509 511
510 512 changeset: 0:30d30fe6a5be
511 513 user: test
512 514 date: Thu Jan 01 00:00:00 1970 +0000
513 515 summary: add files
514 516
515 517 $ cat sub/large4
516 518 large4-modified-again
517 519
518 520 "update --check" refuses to update with uncommitted changes.
519 521 $ hg update --check 8
520 522 abort: uncommitted local changes
521 523 [255]
522 524
523 525 "update --clean" leaves correct largefiles in working copy.
524 526
525 527 $ hg update --clean
526 528 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
527 529 getting changed largefiles
528 530 1 largefiles updated, 0 removed
529 531 $ cat normal3
530 532 normal3-modified
531 533 $ cat sub/normal4
532 534 normal4-modified
533 535 $ cat sub/large4
534 536 large4-modified
535 537 $ cat sub2/large6
536 538 large6-modified
537 539 $ cat sub2/large7
538 540 large7
539 541
540 542 Now "update check" is happy.
541 543 $ hg update --check 8
542 544 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
543 545 getting changed largefiles
544 546 1 largefiles updated, 0 removed
545 547 $ hg update --check
546 548 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
547 549 getting changed largefiles
548 550 1 largefiles updated, 0 removed
549 551
550 552 "revert" works on largefiles (and normal files too).
551 553 $ echo hack3 >> normal3
552 554 $ echo hack4 >> sub/normal4
553 555 $ echo hack4 >> sub/large4
554 556 $ hg rm sub2/large6
555 557 $ echo new >> sub2/large8
556 558 $ hg add --large sub2/large8
557 559 # XXX we don't really want to report that we're reverting the standin;
558 560 # that's just an implementation detail. But I don't see an obvious fix. ;-(
559 561 $ hg revert sub
560 562 reverting .hglf/sub/large4 (glob)
561 563 reverting sub/normal4 (glob)
562 564 $ hg status
563 565 M normal3
564 566 A sub2/large8
565 567 R sub2/large6
566 568 ? sub/large4.orig
567 569 ? sub/normal4.orig
568 570 $ cat sub/normal4
569 571 normal4-modified
570 572 $ cat sub/large4
571 573 large4-modified
572 574 $ hg revert -a --no-backup
573 575 undeleting .hglf/sub2/large6 (glob)
574 576 forgetting .hglf/sub2/large8 (glob)
575 577 reverting normal3
576 578 $ hg status
577 579 ? sub/large4.orig
578 580 ? sub/normal4.orig
579 581 ? sub2/large8
580 582 $ cat normal3
581 583 normal3-modified
582 584 $ cat sub2/large6
583 585 large6-modified
584 586 $ rm sub/*.orig sub2/large8
585 587
586 588 revert some files to an older revision
587 589 $ hg revert --no-backup -r 8 sub2
588 590 reverting .hglf/sub2/large6 (glob)
589 591 $ cat sub2/large6
590 592 large6
591 593 $ hg revert --no-backup sub2
592 594 reverting .hglf/sub2/large6 (glob)
593 595 $ hg status
594 596
595 597 "verify --large" actually verifies largefiles
596 598
597 599 $ hg verify --large
598 600 checking changesets
599 601 checking manifests
600 602 crosschecking files in changesets and manifests
601 603 checking files
602 604 10 files, 10 changesets, 28 total revisions
603 605 searching 1 changesets for largefiles
604 606 verified existence of 3 revisions of 3 largefiles
605 607
606 608 Merging does not revert to old versions of largefiles (this has also
607 609 been very problematic).
608 610
609 611 $ cd ..
610 612 $ hg clone -r 7 e f
611 613 adding changesets
612 614 adding manifests
613 615 adding file changes
614 616 added 8 changesets with 24 changes to 10 files
615 617 updating to branch default
616 618 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
617 619 getting changed largefiles
618 620 3 largefiles updated, 0 removed
619 621 $ cd f
620 622 $ echo "large4-merge-test" > sub/large4
621 623 $ hg commit -m "Modify large4 to test merge"
622 624 $ hg pull ../e
623 625 pulling from ../e
624 626 searching for changes
625 627 adding changesets
626 628 adding manifests
627 629 adding file changes
628 630 added 2 changesets with 4 changes to 4 files (+1 heads)
629 631 (run 'hg heads' to see heads, 'hg merge' to merge)
630 632 $ hg merge
631 633 merging sub/large4
632 634 largefile sub/large4 has a merge conflict
633 635 keep (l)ocal or take (o)ther? l
634 636 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
635 637 (branch merge, don't forget to commit)
636 638 getting changed largefiles
637 639 1 largefiles updated, 0 removed
638 640 $ hg commit -m "Merge repos e and f"
639 641 $ cat normal3
640 642 normal3-modified
641 643 $ cat sub/normal4
642 644 normal4-modified
643 645 $ cat sub/large4
644 646 large4-merge-test
645 647 $ cat sub2/large6
646 648 large6-modified
647 649 $ cat sub2/large7
648 650 large7
649 651
650 652 Test status after merging with a branch that introduces a new largefile:
651 653
652 654 $ echo large > large
653 655 $ hg add --large large
654 656 $ hg commit -m 'add largefile'
655 657 $ hg update -q ".^"
656 658 $ echo change >> normal3
657 659 $ hg commit -m 'some change'
658 660 created new head
659 661 $ hg merge
660 662 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
661 663 (branch merge, don't forget to commit)
662 664 getting changed largefiles
663 665 1 largefiles updated, 0 removed
664 666 $ hg status
665 667 M large
666 668
667 669 Test that a normal file and a largefile with the same name and path cannot
668 670 coexist.
669 671
670 672 $ rm sub2/large7
671 673 $ echo "largeasnormal" > sub2/large7
672 674 $ hg add sub2/large7
673 675 sub2/large7 already a largefile
674 676
675 677 Test that transplanting a largefile change works correctly.
676 678
677 679 $ cd ..
678 680 $ hg clone -r 8 d g
679 681 adding changesets
680 682 adding manifests
681 683 adding file changes
682 684 added 9 changesets with 26 changes to 10 files
683 685 updating to branch default
684 686 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
685 687 getting changed largefiles
686 688 3 largefiles updated, 0 removed
687 689 $ cd g
688 690 $ hg transplant -s ../d 598410d3eb9a
689 691 searching for changes
690 692 searching for changes
691 693 adding changesets
692 694 adding manifests
693 695 adding file changes
694 696 added 1 changesets with 2 changes to 2 files
695 697 getting changed largefiles
696 698 1 largefiles updated, 0 removed
697 699 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
698 700 9:598410d3eb9a modify normal file largefile in repo d
699 701 8:a381d2c8c80e modify normal file and largefile in repo b
700 702 7:daea875e9014 add/edit more largefiles
701 703 6:4355d653f84f edit files yet again
702 704 5:9d5af5072dbd edit files again
703 705 4:74c02385b94c move files
704 706 3:9e8fbc4bce62 copy files
705 707 2:51a0ae4d5864 remove files
706 708 1:ce8896473775 edit files
707 709 0:30d30fe6a5be add files
708 710 $ cat normal3
709 711 normal3-modified
710 712 $ cat sub/normal4
711 713 normal4-modified
712 714 $ cat sub/large4
713 715 large4-modified
714 716 $ cat sub2/large6
715 717 large6-modified
716 718 $ cat sub2/large7
717 719 large7
718 720
719 721 Test that renaming a largefile results in correct output for status
720 722
721 723 $ hg rename sub/large4 large4-renamed
722 724 $ hg st
723 725 A large4-renamed
724 726 R sub/large4
725 727 $ hg commit -m "test rename output"
726 728 $ cat large4-renamed
727 729 large4-modified
728 730 $ cd sub2
729 731 $ hg rename large6 large6-renamed
730 732 $ hg st
731 733 A sub2/large6-renamed
732 734 R sub2/large6
733 735 $ cd ../..
734 736
735 737 vanilla clients not locked out from largefiles servers on vanilla repos
736 738 $ mkdir r1
737 739 $ cd r1
738 740 $ hg init
739 741 $ echo c1 > f1
740 742 $ hg add f1
741 743 $ hg com -m "m1"
742 744 $ cd ..
743 745 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
744 746 $ cat hg.pid >> $DAEMON_PIDS
745 747 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
746 748 requesting all changes
747 749 adding changesets
748 750 adding manifests
749 751 adding file changes
750 752 added 1 changesets with 1 changes to 1 files
751 753 updating to branch default
752 754 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
753 755
754 756 largefiles clients still work with vanilla servers
755 757 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
756 758 $ cat hg.pid >> $DAEMON_PIDS
757 759 $ hg clone http://localhost:$HGPORT1 r3
758 760 requesting all changes
759 761 adding changesets
760 762 adding manifests
761 763 adding file changes
762 764 added 1 changesets with 1 changes to 1 files
763 765 updating to branch default
764 766 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
765 767
766 768 vanilla clients locked out from largefiles http repos
767 769 $ mkdir r4
768 770 $ cd r4
769 771 $ hg init
770 772 $ echo c1 > f1
771 773 $ hg add --large f1
772 774 $ hg com -m "m1"
773 775 $ cd ..
774 776 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
775 777 $ cat hg.pid >> $DAEMON_PIDS
776 778 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
777 779 abort: remote error:
778 780
779 781 This repository uses the largefiles extension.
780 782
781 783 Please enable it in your Mercurial config file.
782 784 [255]
783 785
784 786 used all HGPORTs, kill all daemons
785 787 $ "$TESTDIR/killdaemons.py"
786 788
787 789 vanilla clients locked out from largefiles ssh repos
788 790 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
789 791 abort: remote error:
790 792
791 793 This repository uses the largefiles extension.
792 794
793 795 Please enable it in your Mercurial config file.
794 796 [255]
795 797
796 798 largefiles clients refuse to push largefiles repos to vanilla servers
797 799 $ mkdir r6
798 800 $ cd r6
799 801 $ hg init
800 802 $ echo c1 > f1
801 803 $ hg add f1
802 804 $ hg com -m "m1"
803 805 $ cat >> .hg/hgrc <<!
804 806 > [web]
805 807 > push_ssl = false
806 808 > allow_push = *
807 809 > !
808 810 $ cd ..
809 811 $ hg clone r6 r7
810 812 updating to branch default
811 813 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
812 814 $ cd r7
813 815 $ echo c2 > f2
814 816 $ hg add --large f2
815 817 $ hg com -m "m2"
816 818 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
817 819 $ cat ../hg.pid >> $DAEMON_PIDS
818 820 $ hg push http://localhost:$HGPORT
819 821 pushing to http://localhost:$HGPORT/
820 822 searching for changes
821 823 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
822 824 [255]
823 825 $ cd ..
824 826
825 827 Clone a local repository owned by another user
826 828 We have to simulate that here by setting $HOME and removing write permissions
827 829 $ ORIGHOME="$HOME"
828 830 $ mkdir alice
829 831 $ HOME="`pwd`/alice"
830 832 $ cd alice
831 833 $ hg init pubrepo
832 834 $ cd pubrepo
833 835 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
834 836 $ hg add --large a-large-file
835 837 $ hg commit -m "Add a large file"
836 838 $ cd ..
837 839 $ chmod -R a-w pubrepo
838 840 $ cd ..
839 841 $ mkdir bob
840 842 $ HOME="`pwd`/bob"
841 843 $ cd bob
842 844 $ hg clone --pull ../alice/pubrepo pubrepo
843 845 requesting all changes
844 846 adding changesets
845 847 adding manifests
846 848 adding file changes
847 849 added 1 changesets with 1 changes to 1 files
848 850 updating to branch default
849 851 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
850 852 getting changed largefiles
851 853 1 largefiles updated, 0 removed
852 854 $ cd ..
853 855 $ chmod -R u+w alice/pubrepo
854 856 $ HOME="$ORIGHOME"
855 857
856 858 Symlink to a large largefile should behave the same as a symlink to a normal file
857 859 $ hg init largesymlink
858 860 $ cd largesymlink
859 861 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
860 862 $ hg add --large largefile
861 863 $ hg commit -m "commit a large file"
862 864 $ ln -s largefile largelink
863 865 $ hg add largelink
864 866 $ hg commit -m "commit a large symlink"
865 867 $ rm -f largelink
866 868 $ hg up >/dev/null
867 869 $ test -f largelink
868 870 [1]
869 871 $ test -L largelink
870 872 [1]
871 873 $ rm -f largelink # make next part of the test independent of the previous
872 874 $ hg up -C >/dev/null
873 875 $ test -f largelink
874 876 $ test -L largelink
875 877 $ cd ..
876 878
877 879
@@ -1,148 +1,151 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo c1 > common
15 18 $ hg add common
16 19 $ hg ci -m C1
17 20
18 21 $ echo c2 >> common
19 22 $ hg ci -m C2
20 23
21 24 $ echo c3 >> common
22 25 $ hg ci -m C3
23 26
24 27 $ hg up -q -C 1
25 28
26 29 $ echo l1 >> extra
27 30 $ hg add extra
28 31 $ hg ci -m L1
29 32 created new head
30 33
31 34 $ sed -e 's/c2/l2/' common > common.new
32 35 $ mv common.new common
33 36 $ hg ci -m L2
34 37
35 38 $ hg tglog
36 39 @ 4: 'L2'
37 40 |
38 41 o 3: 'L1'
39 42 |
40 43 | o 2: 'C3'
41 44 |/
42 45 o 1: 'C2'
43 46 |
44 47 o 0: 'C1'
45 48
46 49
47 50 Conflicting rebase:
48 51
49 52 $ hg rebase -s 3 -d 2
50 53 merging common
51 54 warning: conflicts during merge.
52 55 merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
53 56 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
54 57 [255]
55 58
56 59 Abort:
57 60
58 61 $ hg rebase --abort
59 62 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
60 63 rebase aborted
61 64
62 65 $ hg tglog
63 66 @ 4: 'L2'
64 67 |
65 68 o 3: 'L1'
66 69 |
67 70 | o 2: 'C3'
68 71 |/
69 72 o 1: 'C2'
70 73 |
71 74 o 0: 'C1'
72 75
73 76 $ cd ..
74 77
75 78
76 79 Constrcut new repo:
77 80
78 81 $ hg init b
79 82 $ cd b
80 83
81 84 $ echo a > a
82 85 $ hg ci -Am A
83 86 adding a
84 87
85 88 $ echo b > b
86 89 $ hg ci -Am B
87 90 adding b
88 91
89 92 $ echo c > c
90 93 $ hg ci -Am C
91 94 adding c
92 95
93 96 $ hg up -q 0
94 97
95 98 $ echo b > b
96 99 $ hg ci -Am 'B bis'
97 100 adding b
98 101 created new head
99 102
100 103 $ echo c1 > c
101 104 $ hg ci -Am C1
102 105 adding c
103 106
104 107 Rebase and abort without generating new changesets:
105 108
106 109 $ hg tglog
107 110 @ 4: 'C1'
108 111 |
109 112 o 3: 'B bis'
110 113 |
111 114 | o 2: 'C'
112 115 | |
113 116 | o 1: 'B'
114 117 |/
115 118 o 0: 'A'
116 119
117 120 $ hg rebase -b 4 -d 2
118 121 merging c
119 122 warning: conflicts during merge.
120 123 merging c incomplete! (edit conflicts, then use 'hg resolve --mark')
121 124 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
122 125 [255]
123 126
124 127 $ hg tglog
125 128 @ 4: 'C1'
126 129 |
127 130 o 3: 'B bis'
128 131 |
129 132 | @ 2: 'C'
130 133 | |
131 134 | o 1: 'B'
132 135 |/
133 136 o 0: 'A'
134 137
135 138 $ hg rebase -a
136 139 rebase aborted
137 140
138 141 $ hg tglog
139 142 @ 4: 'C1'
140 143 |
141 144 o 3: 'B bis'
142 145 |
143 146 | o 2: 'C'
144 147 | |
145 148 | o 1: 'B'
146 149 |/
147 150 o 0: 'A'
148 151
@@ -1,85 +1,88 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' bookmarks: {bookmarks}\n"
8 11 > EOF
9 12
10 13 Create a repo with several bookmarks
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo a > a
15 18 $ hg ci -Am A
16 19 adding a
17 20
18 21 $ echo b > b
19 22 $ hg ci -Am B
20 23 adding b
21 24 $ hg book 'X'
22 25 $ hg book 'Y'
23 26
24 27 $ echo c > c
25 28 $ hg ci -Am C
26 29 adding c
27 30 $ hg book 'Z'
28 31
29 32 $ hg up -q 0
30 33
31 34 $ echo d > d
32 35 $ hg ci -Am D
33 36 adding d
34 37 created new head
35 38
36 39 $ hg tglog
37 40 @ 3: 'D' bookmarks:
38 41 |
39 42 | o 2: 'C' bookmarks: Y Z
40 43 | |
41 44 | o 1: 'B' bookmarks: X
42 45 |/
43 46 o 0: 'A' bookmarks:
44 47
45 48
46 49 Move only rebased bookmarks
47 50
48 51 $ cd ..
49 52 $ hg clone -q a a1
50 53
51 54 $ cd a1
52 55 $ hg up -q Z
53 56
54 57 $ hg rebase --detach -s Y -d 3
55 58 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
56 59
57 60 $ hg tglog
58 61 @ 3: 'C' bookmarks: Y Z
59 62 |
60 63 o 2: 'D' bookmarks:
61 64 |
62 65 | o 1: 'B' bookmarks: X
63 66 |/
64 67 o 0: 'A' bookmarks:
65 68
66 69 Keep bookmarks to the correct rebased changeset
67 70
68 71 $ cd ..
69 72 $ hg clone -q a a2
70 73
71 74 $ cd a2
72 75 $ hg up -q Z
73 76
74 77 $ hg rebase -s 1 -d 3
75 78 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
76 79
77 80 $ hg tglog
78 81 @ 3: 'C' bookmarks: Y Z
79 82 |
80 83 o 2: 'B' bookmarks: X
81 84 |
82 85 o 1: 'D' bookmarks:
83 86 |
84 87 o 0: 'A' bookmarks:
85 88
@@ -1,261 +1,264 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > theads = heads --template "{rev}: '{desc}' {branches}\n"
9 12 > EOF
10 13
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo a > a
15 18 $ hg ci -Am A
16 19 adding a
17 20
18 21 $ hg branch branch1
19 22 marked working directory as branch branch1
20 23 (branches are permanent and global, did you want a bookmark?)
21 24 $ hg ci -m 'branch1'
22 25
23 26 $ echo b > b
24 27 $ hg ci -Am B
25 28 adding b
26 29
27 30 $ hg up -q 0
28 31
29 32 $ hg branch branch2
30 33 marked working directory as branch branch2
31 34 (branches are permanent and global, did you want a bookmark?)
32 35 $ hg ci -m 'branch2'
33 36
34 37 $ echo c > C
35 38 $ hg ci -Am C
36 39 adding C
37 40
38 41 $ hg up -q 2
39 42
40 43 $ hg branch -f branch2
41 44 marked working directory as branch branch2
42 45 (branches are permanent and global, did you want a bookmark?)
43 46 $ echo d > d
44 47 $ hg ci -Am D
45 48 adding d
46 49 created new head
47 50
48 51 $ echo e > e
49 52 $ hg ci -Am E
50 53 adding e
51 54
52 55 $ hg update default
53 56 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
54 57
55 58 $ hg branch branch3
56 59 marked working directory as branch branch3
57 60 (branches are permanent and global, did you want a bookmark?)
58 61 $ hg ci -m 'branch3'
59 62
60 63 $ echo f > f
61 64 $ hg ci -Am F
62 65 adding f
63 66
64 67 $ cd ..
65 68
66 69
67 70 Rebase part of branch2 (5-6) onto branch3 (8):
68 71
69 72 $ hg clone -q -u . a a1
70 73 $ cd a1
71 74
72 75 $ hg tglog
73 76 @ 8: 'F' branch3
74 77 |
75 78 o 7: 'branch3' branch3
76 79 |
77 80 | o 6: 'E' branch2
78 81 | |
79 82 | o 5: 'D' branch2
80 83 | |
81 84 | | o 4: 'C' branch2
82 85 | | |
83 86 +---o 3: 'branch2' branch2
84 87 | |
85 88 | o 2: 'B' branch1
86 89 | |
87 90 | o 1: 'branch1' branch1
88 91 |/
89 92 o 0: 'A'
90 93
91 94 $ hg branches
92 95 branch3 8:4666b71e8e32
93 96 branch2 6:5097051d331d
94 97 branch1 2:0a03079c47fd (inactive)
95 98 default 0:1994f17a630e (inactive)
96 99
97 100 $ hg theads
98 101 8: 'F' branch3
99 102 6: 'E' branch2
100 103 4: 'C' branch2
101 104 2: 'B' branch1
102 105 0: 'A'
103 106
104 107 $ hg rebase --detach -s 5 -d 8
105 108 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
106 109
107 110 $ hg branches
108 111 branch3 8:466cdfb14b62
109 112 branch2 4:e4fdb121d036
110 113 branch1 2:0a03079c47fd
111 114 default 0:1994f17a630e (inactive)
112 115
113 116 $ hg theads
114 117 8: 'E' branch3
115 118 4: 'C' branch2
116 119 2: 'B' branch1
117 120 0: 'A'
118 121
119 122 $ hg tglog
120 123 @ 8: 'E' branch3
121 124 |
122 125 o 7: 'D' branch3
123 126 |
124 127 o 6: 'F' branch3
125 128 |
126 129 o 5: 'branch3' branch3
127 130 |
128 131 | o 4: 'C' branch2
129 132 | |
130 133 | o 3: 'branch2' branch2
131 134 |/
132 135 | o 2: 'B' branch1
133 136 | |
134 137 | o 1: 'branch1' branch1
135 138 |/
136 139 o 0: 'A'
137 140
138 141 $ cd ..
139 142
140 143
141 144 Rebase head of branch3 (8) onto branch2 (6):
142 145
143 146 $ hg clone -q -u . a a2
144 147 $ cd a2
145 148
146 149 $ hg tglog
147 150 @ 8: 'F' branch3
148 151 |
149 152 o 7: 'branch3' branch3
150 153 |
151 154 | o 6: 'E' branch2
152 155 | |
153 156 | o 5: 'D' branch2
154 157 | |
155 158 | | o 4: 'C' branch2
156 159 | | |
157 160 +---o 3: 'branch2' branch2
158 161 | |
159 162 | o 2: 'B' branch1
160 163 | |
161 164 | o 1: 'branch1' branch1
162 165 |/
163 166 o 0: 'A'
164 167
165 168 $ hg rebase --detach -s 8 -d 6
166 169 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
167 170
168 171 $ hg branches
169 172 branch2 8:6b4bdc1b5ac0
170 173 branch3 7:653b9feb4616
171 174 branch1 2:0a03079c47fd (inactive)
172 175 default 0:1994f17a630e (inactive)
173 176
174 177 $ hg theads
175 178 8: 'F' branch2
176 179 7: 'branch3' branch3
177 180 4: 'C' branch2
178 181 2: 'B' branch1
179 182 0: 'A'
180 183
181 184 $ hg tglog
182 185 @ 8: 'F' branch2
183 186 |
184 187 | o 7: 'branch3' branch3
185 188 | |
186 189 o | 6: 'E' branch2
187 190 | |
188 191 o | 5: 'D' branch2
189 192 | |
190 193 | | o 4: 'C' branch2
191 194 | | |
192 195 | | o 3: 'branch2' branch2
193 196 | |/
194 197 o | 2: 'B' branch1
195 198 | |
196 199 o | 1: 'branch1' branch1
197 200 |/
198 201 o 0: 'A'
199 202
200 203 $ hg verify -q
201 204
202 205 $ cd ..
203 206
204 207
205 208 Rebase entire branch3 (7-8) onto branch2 (6):
206 209
207 210 $ hg clone -q -u . a a3
208 211 $ cd a3
209 212
210 213 $ hg tglog
211 214 @ 8: 'F' branch3
212 215 |
213 216 o 7: 'branch3' branch3
214 217 |
215 218 | o 6: 'E' branch2
216 219 | |
217 220 | o 5: 'D' branch2
218 221 | |
219 222 | | o 4: 'C' branch2
220 223 | | |
221 224 +---o 3: 'branch2' branch2
222 225 | |
223 226 | o 2: 'B' branch1
224 227 | |
225 228 | o 1: 'branch1' branch1
226 229 |/
227 230 o 0: 'A'
228 231
229 232 $ hg rebase --detach -s 7 -d 6
230 233 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
231 234
232 235 $ hg branches
233 236 branch2 7:6b4bdc1b5ac0
234 237 branch1 2:0a03079c47fd (inactive)
235 238 default 0:1994f17a630e (inactive)
236 239
237 240 $ hg theads
238 241 7: 'F' branch2
239 242 4: 'C' branch2
240 243 2: 'B' branch1
241 244 0: 'A'
242 245
243 246 $ hg tglog
244 247 @ 7: 'F' branch2
245 248 |
246 249 o 6: 'E' branch2
247 250 |
248 251 o 5: 'D' branch2
249 252 |
250 253 | o 4: 'C' branch2
251 254 | |
252 255 | o 3: 'branch2' branch2
253 256 | |
254 257 o | 2: 'B' branch1
255 258 | |
256 259 o | 1: 'branch1' branch1
257 260 |/
258 261 o 0: 'A'
259 262
260 263 $ hg verify -q
261 264
@@ -1,143 +1,146 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo A > A
15 18 $ hg add A
16 19 $ hg ci -m A
17 20
18 21 $ echo 'B' > B
19 22 $ hg add B
20 23 $ hg ci -m B
21 24
22 25 $ echo C >> A
23 26 $ hg ci -m C
24 27
25 28 $ hg up -q -C 0
26 29
27 30 $ echo D >> A
28 31 $ hg ci -m D
29 32 created new head
30 33
31 34 $ echo E > E
32 35 $ hg add E
33 36 $ hg ci -m E
34 37
35 38 $ hg up -q -C 0
36 39
37 40 $ hg branch 'notdefault'
38 41 marked working directory as branch notdefault
39 42 (branches are permanent and global, did you want a bookmark?)
40 43 $ echo F >> A
41 44 $ hg ci -m F
42 45
43 46 $ cd ..
44 47
45 48
46 49 Rebasing B onto E - check keep:
47 50
48 51 $ hg clone -q -u . a a1
49 52 $ cd a1
50 53
51 54 $ hg tglog
52 55 @ 5: 'F' notdefault
53 56 |
54 57 | o 4: 'E'
55 58 | |
56 59 | o 3: 'D'
57 60 |/
58 61 | o 2: 'C'
59 62 | |
60 63 | o 1: 'B'
61 64 |/
62 65 o 0: 'A'
63 66
64 67 $ hg rebase -s 1 -d 4 --keep
65 68 merging A
66 69 warning: conflicts during merge.
67 70 merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
68 71 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
69 72 [255]
70 73
71 74 Solve the conflict and go on:
72 75
73 76 $ echo 'conflict solved' > A
74 77 $ rm A.orig
75 78 $ hg resolve -m A
76 79 $ hg rebase --continue
77 80
78 81 $ hg tglog
79 82 @ 7: 'C'
80 83 |
81 84 o 6: 'B'
82 85 |
83 86 | o 5: 'F' notdefault
84 87 | |
85 88 o | 4: 'E'
86 89 | |
87 90 o | 3: 'D'
88 91 |/
89 92 | o 2: 'C'
90 93 | |
91 94 | o 1: 'B'
92 95 |/
93 96 o 0: 'A'
94 97
95 98 $ cd ..
96 99
97 100
98 101 Rebase F onto E - check keepbranches:
99 102
100 103 $ hg clone -q -u . a a2
101 104 $ cd a2
102 105
103 106 $ hg tglog
104 107 @ 5: 'F' notdefault
105 108 |
106 109 | o 4: 'E'
107 110 | |
108 111 | o 3: 'D'
109 112 |/
110 113 | o 2: 'C'
111 114 | |
112 115 | o 1: 'B'
113 116 |/
114 117 o 0: 'A'
115 118
116 119 $ hg rebase -s 5 -d 4 --keepbranches
117 120 merging A
118 121 warning: conflicts during merge.
119 122 merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
120 123 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
121 124 [255]
122 125
123 126 Solve the conflict and go on:
124 127
125 128 $ echo 'conflict solved' > A
126 129 $ rm A.orig
127 130 $ hg resolve -m A
128 131 $ hg rebase --continue
129 132 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
130 133
131 134 $ hg tglog
132 135 @ 5: 'F' notdefault
133 136 |
134 137 o 4: 'E'
135 138 |
136 139 o 3: 'D'
137 140 |
138 141 | o 2: 'C'
139 142 | |
140 143 | o 1: 'B'
141 144 |/
142 145 o 0: 'A'
143 146
@@ -1,484 +1,487 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13 Create repo a:
11 14
12 15 $ hg init a
13 16 $ cd a
14 17 $ hg unbundle $TESTDIR/bundles/rebase.hg
15 18 adding changesets
16 19 adding manifests
17 20 adding file changes
18 21 added 8 changesets with 7 changes to 7 files (+2 heads)
19 22 (run 'hg heads' to see heads, 'hg merge' to merge)
20 23 $ hg up tip
21 24 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 25
23 26 $ hg tglog
24 27 @ 7: 'H'
25 28 |
26 29 | o 6: 'G'
27 30 |/|
28 31 o | 5: 'F'
29 32 | |
30 33 | o 4: 'E'
31 34 |/
32 35 | o 3: 'D'
33 36 | |
34 37 | o 2: 'C'
35 38 | |
36 39 | o 1: 'B'
37 40 |/
38 41 o 0: 'A'
39 42
40 43 $ cd ..
41 44
42 45
43 46 Rebasing B onto H:
44 47
45 48 $ hg clone -q -u 3 a a1
46 49 $ cd a1
47 50
48 51 $ hg rebase --collapse --keepbranches
49 52 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
50 53
51 54 $ hg tglog
52 55 @ 5: 'Collapsed revision
53 56 | * B
54 57 | * C
55 58 | * D'
56 59 o 4: 'H'
57 60 |
58 61 | o 3: 'G'
59 62 |/|
60 63 o | 2: 'F'
61 64 | |
62 65 | o 1: 'E'
63 66 |/
64 67 o 0: 'A'
65 68
66 69 $ hg manifest
67 70 A
68 71 B
69 72 C
70 73 D
71 74 F
72 75 H
73 76
74 77 $ cd ..
75 78
76 79
77 80 Rebasing E onto H:
78 81
79 82 $ hg clone -q -u . a a2
80 83 $ cd a2
81 84
82 85 $ hg rebase --source 4 --collapse
83 86 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
84 87
85 88 $ hg tglog
86 89 @ 6: 'Collapsed revision
87 90 | * E
88 91 | * G'
89 92 o 5: 'H'
90 93 |
91 94 o 4: 'F'
92 95 |
93 96 | o 3: 'D'
94 97 | |
95 98 | o 2: 'C'
96 99 | |
97 100 | o 1: 'B'
98 101 |/
99 102 o 0: 'A'
100 103
101 104 $ hg manifest
102 105 A
103 106 E
104 107 F
105 108 H
106 109
107 110 $ cd ..
108 111
109 112 Rebasing G onto H with custom message:
110 113
111 114 $ hg clone -q -u . a a3
112 115 $ cd a3
113 116
114 117 $ hg rebase --base 6 -m 'custom message'
115 118 abort: message can only be specified with collapse
116 119 [255]
117 120
118 121 $ hg rebase --source 4 --collapse -m 'custom message'
119 122 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
120 123
121 124 $ hg tglog
122 125 @ 6: 'custom message'
123 126 |
124 127 o 5: 'H'
125 128 |
126 129 o 4: 'F'
127 130 |
128 131 | o 3: 'D'
129 132 | |
130 133 | o 2: 'C'
131 134 | |
132 135 | o 1: 'B'
133 136 |/
134 137 o 0: 'A'
135 138
136 139 $ hg manifest
137 140 A
138 141 E
139 142 F
140 143 H
141 144
142 145 $ cd ..
143 146
144 147 Create repo b:
145 148
146 149 $ hg init b
147 150 $ cd b
148 151
149 152 $ echo A > A
150 153 $ hg ci -Am A
151 154 adding A
152 155 $ echo B > B
153 156 $ hg ci -Am B
154 157 adding B
155 158
156 159 $ hg up -q 0
157 160
158 161 $ echo C > C
159 162 $ hg ci -Am C
160 163 adding C
161 164 created new head
162 165
163 166 $ hg merge
164 167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 168 (branch merge, don't forget to commit)
166 169
167 170 $ echo D > D
168 171 $ hg ci -Am D
169 172 adding D
170 173
171 174 $ hg up -q 1
172 175
173 176 $ echo E > E
174 177 $ hg ci -Am E
175 178 adding E
176 179 created new head
177 180
178 181 $ echo F > F
179 182 $ hg ci -Am F
180 183 adding F
181 184
182 185 $ hg merge
183 186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 187 (branch merge, don't forget to commit)
185 188 $ hg ci -m G
186 189
187 190 $ hg up -q 0
188 191
189 192 $ echo H > H
190 193 $ hg ci -Am H
191 194 adding H
192 195 created new head
193 196
194 197 $ hg tglog
195 198 @ 7: 'H'
196 199 |
197 200 | o 6: 'G'
198 201 | |\
199 202 | | o 5: 'F'
200 203 | | |
201 204 | | o 4: 'E'
202 205 | | |
203 206 | o | 3: 'D'
204 207 | |\|
205 208 | o | 2: 'C'
206 209 |/ /
207 210 | o 1: 'B'
208 211 |/
209 212 o 0: 'A'
210 213
211 214 $ cd ..
212 215
213 216
214 217 Rebase and collapse - more than one external (fail):
215 218
216 219 $ hg clone -q -u . b b1
217 220 $ cd b1
218 221
219 222 $ hg rebase -s 2 --collapse
220 223 abort: unable to collapse, there is more than one external parent
221 224 [255]
222 225
223 226 Rebase and collapse - E onto H:
224 227
225 228 $ hg rebase -s 4 --collapse
226 229 saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
227 230
228 231 $ hg tglog
229 232 @ 5: 'Collapsed revision
230 233 |\ * E
231 234 | | * F
232 235 | | * G'
233 236 | o 4: 'H'
234 237 | |
235 238 o | 3: 'D'
236 239 |\ \
237 240 | o | 2: 'C'
238 241 | |/
239 242 o / 1: 'B'
240 243 |/
241 244 o 0: 'A'
242 245
243 246 $ hg manifest
244 247 A
245 248 B
246 249 C
247 250 D
248 251 E
249 252 F
250 253 H
251 254
252 255 $ cd ..
253 256
254 257
255 258 Create repo c:
256 259
257 260 $ hg init c
258 261 $ cd c
259 262
260 263 $ echo A > A
261 264 $ hg ci -Am A
262 265 adding A
263 266 $ echo B > B
264 267 $ hg ci -Am B
265 268 adding B
266 269
267 270 $ hg up -q 0
268 271
269 272 $ echo C > C
270 273 $ hg ci -Am C
271 274 adding C
272 275 created new head
273 276
274 277 $ hg merge
275 278 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 279 (branch merge, don't forget to commit)
277 280
278 281 $ echo D > D
279 282 $ hg ci -Am D
280 283 adding D
281 284
282 285 $ hg up -q 1
283 286
284 287 $ echo E > E
285 288 $ hg ci -Am E
286 289 adding E
287 290 created new head
288 291 $ echo F > E
289 292 $ hg ci -m 'F'
290 293
291 294 $ echo G > G
292 295 $ hg ci -Am G
293 296 adding G
294 297
295 298 $ hg merge
296 299 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 300 (branch merge, don't forget to commit)
298 301
299 302 $ hg ci -m H
300 303
301 304 $ hg up -q 0
302 305
303 306 $ echo I > I
304 307 $ hg ci -Am I
305 308 adding I
306 309 created new head
307 310
308 311 $ hg tglog
309 312 @ 8: 'I'
310 313 |
311 314 | o 7: 'H'
312 315 | |\
313 316 | | o 6: 'G'
314 317 | | |
315 318 | | o 5: 'F'
316 319 | | |
317 320 | | o 4: 'E'
318 321 | | |
319 322 | o | 3: 'D'
320 323 | |\|
321 324 | o | 2: 'C'
322 325 |/ /
323 326 | o 1: 'B'
324 327 |/
325 328 o 0: 'A'
326 329
327 330 $ cd ..
328 331
329 332
330 333 Rebase and collapse - E onto I:
331 334
332 335 $ hg clone -q -u . c c1
333 336 $ cd c1
334 337
335 338 $ hg rebase -s 4 --collapse
336 339 merging E
337 340 saved backup bundle to $TESTTMP/c1/.hg/strip-backup/*-backup.hg (glob)
338 341
339 342 $ hg tglog
340 343 @ 5: 'Collapsed revision
341 344 |\ * E
342 345 | | * F
343 346 | | * G
344 347 | | * H'
345 348 | o 4: 'I'
346 349 | |
347 350 o | 3: 'D'
348 351 |\ \
349 352 | o | 2: 'C'
350 353 | |/
351 354 o / 1: 'B'
352 355 |/
353 356 o 0: 'A'
354 357
355 358 $ hg manifest
356 359 A
357 360 B
358 361 C
359 362 D
360 363 E
361 364 G
362 365 I
363 366
364 367 $ cat E
365 368 F
366 369
367 370 $ cd ..
368 371
369 372
370 373 Create repo d:
371 374
372 375 $ hg init d
373 376 $ cd d
374 377
375 378 $ echo A > A
376 379 $ hg ci -Am A
377 380 adding A
378 381 $ echo B > B
379 382 $ hg ci -Am B
380 383 adding B
381 384 $ echo C > C
382 385 $ hg ci -Am C
383 386 adding C
384 387
385 388 $ hg up -q 1
386 389
387 390 $ echo D > D
388 391 $ hg ci -Am D
389 392 adding D
390 393 created new head
391 394 $ hg merge
392 395 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 396 (branch merge, don't forget to commit)
394 397
395 398 $ hg ci -m E
396 399
397 400 $ hg up -q 0
398 401
399 402 $ echo F > F
400 403 $ hg ci -Am F
401 404 adding F
402 405 created new head
403 406
404 407 $ hg tglog
405 408 @ 5: 'F'
406 409 |
407 410 | o 4: 'E'
408 411 | |\
409 412 | | o 3: 'D'
410 413 | | |
411 414 | o | 2: 'C'
412 415 | |/
413 416 | o 1: 'B'
414 417 |/
415 418 o 0: 'A'
416 419
417 420 $ cd ..
418 421
419 422
420 423 Rebase and collapse - B onto F:
421 424
422 425 $ hg clone -q -u . d d1
423 426 $ cd d1
424 427
425 428 $ hg rebase -s 1 --collapse
426 429 saved backup bundle to $TESTTMP/d1/.hg/strip-backup/*-backup.hg (glob)
427 430
428 431 $ hg tglog
429 432 @ 2: 'Collapsed revision
430 433 | * B
431 434 | * C
432 435 | * D
433 436 | * E'
434 437 o 1: 'F'
435 438 |
436 439 o 0: 'A'
437 440
438 441 $ hg manifest
439 442 A
440 443 B
441 444 C
442 445 D
443 446 F
444 447
445 448 Interactions between collapse and keepbranches
446 449 $ cd ..
447 450 $ hg init e
448 451 $ cd e
449 452 $ echo 'a' > a
450 453 $ hg ci -Am 'A'
451 454 adding a
452 455
453 456 $ hg branch '1'
454 457 marked working directory as branch 1
455 458 (branches are permanent and global, did you want a bookmark?)
456 459 $ echo 'b' > b
457 460 $ hg ci -Am 'B'
458 461 adding b
459 462
460 463 $ hg branch '2'
461 464 marked working directory as branch 2
462 465 (branches are permanent and global, did you want a bookmark?)
463 466 $ echo 'c' > c
464 467 $ hg ci -Am 'C'
465 468 adding c
466 469
467 470 $ hg up -q 0
468 471 $ echo 'd' > d
469 472 $ hg ci -Am 'D'
470 473 adding d
471 474
472 475 $ hg tglog
473 476 @ 3: 'D'
474 477 |
475 478 | o 2: 'C' 2
476 479 | |
477 480 | o 1: 'B' 1
478 481 |/
479 482 o 0: 'A'
480 483
481 484 $ hg rebase --keepbranches --collapse -s 1 -d 3
482 485 abort: cannot collapse multiple named branches
483 486 [255]
484 487
@@ -1,115 +1,118 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13 $ hg init a
11 14 $ cd a
12 15 $ echo c1 >common
13 16 $ hg add common
14 17 $ hg ci -m C1
15 18
16 19 $ echo c2 >>common
17 20 $ hg ci -m C2
18 21
19 22 $ echo c3 >>common
20 23 $ hg ci -m C3
21 24
22 25 $ hg up -q -C 1
23 26
24 27 $ echo l1 >>extra
25 28 $ hg add extra
26 29 $ hg ci -m L1
27 30 created new head
28 31
29 32 $ sed -e 's/c2/l2/' common > common.new
30 33 $ mv common.new common
31 34 $ hg ci -m L2
32 35
33 36 $ echo l3 >> extra2
34 37 $ hg add extra2
35 38 $ hg ci -m L3
36 39
37 40 $ hg tglog
38 41 @ 5: 'L3'
39 42 |
40 43 o 4: 'L2'
41 44 |
42 45 o 3: 'L1'
43 46 |
44 47 | o 2: 'C3'
45 48 |/
46 49 o 1: 'C2'
47 50 |
48 51 o 0: 'C1'
49 52
50 53 Try to call --continue:
51 54
52 55 $ hg rebase --continue
53 56 abort: no rebase in progress
54 57 [255]
55 58
56 59 Conflicting rebase:
57 60
58 61 $ hg rebase -s 3 -d 2
59 62 merging common
60 63 warning: conflicts during merge.
61 64 merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
62 65 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
63 66 [255]
64 67
65 68 Try to continue without solving the conflict:
66 69
67 70 $ hg rebase --continue
68 71 abort: unresolved merge conflicts (see hg help resolve)
69 72 [255]
70 73
71 74 Conclude rebase:
72 75
73 76 $ echo 'resolved merge' >common
74 77 $ hg resolve -m common
75 78 $ hg rebase --continue
76 79 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
77 80
78 81 $ hg tglog
79 82 @ 5: 'L3'
80 83 |
81 84 o 4: 'L2'
82 85 |
83 86 o 3: 'L1'
84 87 |
85 88 o 2: 'C3'
86 89 |
87 90 o 1: 'C2'
88 91 |
89 92 o 0: 'C1'
90 93
91 94 Check correctness:
92 95
93 96 $ hg cat -r 0 common
94 97 c1
95 98
96 99 $ hg cat -r 1 common
97 100 c1
98 101 c2
99 102
100 103 $ hg cat -r 2 common
101 104 c1
102 105 c2
103 106 c3
104 107
105 108 $ hg cat -r 3 common
106 109 c1
107 110 c2
108 111 c3
109 112
110 113 $ hg cat -r 4 common
111 114 resolved merge
112 115
113 116 $ hg cat -r 5 common
114 117 resolved merge
115 118
@@ -1,395 +1,398 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16 $ hg unbundle $TESTDIR/bundles/rebase.hg
14 17 adding changesets
15 18 adding manifests
16 19 adding file changes
17 20 added 8 changesets with 7 changes to 7 files (+2 heads)
18 21 (run 'hg heads' to see heads, 'hg merge' to merge)
19 22 $ hg up tip
20 23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 24
22 25 $ cd ..
23 26
24 27
25 28 Rebasing D onto H detaching from C:
26 29
27 30 $ hg clone -q -u . a a1
28 31 $ cd a1
29 32
30 33 $ hg tglog
31 34 @ 7: 'H'
32 35 |
33 36 | o 6: 'G'
34 37 |/|
35 38 o | 5: 'F'
36 39 | |
37 40 | o 4: 'E'
38 41 |/
39 42 | o 3: 'D'
40 43 | |
41 44 | o 2: 'C'
42 45 | |
43 46 | o 1: 'B'
44 47 |/
45 48 o 0: 'A'
46 49
47 50 $ hg rebase --detach -s 3 -d 7
48 51 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
49 52
50 53 $ hg tglog
51 54 @ 7: 'D'
52 55 |
53 56 o 6: 'H'
54 57 |
55 58 | o 5: 'G'
56 59 |/|
57 60 o | 4: 'F'
58 61 | |
59 62 | o 3: 'E'
60 63 |/
61 64 | o 2: 'C'
62 65 | |
63 66 | o 1: 'B'
64 67 |/
65 68 o 0: 'A'
66 69
67 70 $ hg manifest
68 71 A
69 72 D
70 73 F
71 74 H
72 75
73 76 $ cd ..
74 77
75 78
76 79 Rebasing C onto H detaching from B:
77 80
78 81 $ hg clone -q -u . a a2
79 82 $ cd a2
80 83
81 84 $ hg tglog
82 85 @ 7: 'H'
83 86 |
84 87 | o 6: 'G'
85 88 |/|
86 89 o | 5: 'F'
87 90 | |
88 91 | o 4: 'E'
89 92 |/
90 93 | o 3: 'D'
91 94 | |
92 95 | o 2: 'C'
93 96 | |
94 97 | o 1: 'B'
95 98 |/
96 99 o 0: 'A'
97 100
98 101 $ hg rebase --detach -s 2 -d 7
99 102 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
100 103
101 104 $ hg tglog
102 105 @ 7: 'D'
103 106 |
104 107 o 6: 'C'
105 108 |
106 109 o 5: 'H'
107 110 |
108 111 | o 4: 'G'
109 112 |/|
110 113 o | 3: 'F'
111 114 | |
112 115 | o 2: 'E'
113 116 |/
114 117 | o 1: 'B'
115 118 |/
116 119 o 0: 'A'
117 120
118 121 $ hg manifest
119 122 A
120 123 C
121 124 D
122 125 F
123 126 H
124 127
125 128 $ cd ..
126 129
127 130
128 131 Rebasing B onto H using detach (same as not using it):
129 132
130 133 $ hg clone -q -u . a a3
131 134 $ cd a3
132 135
133 136 $ hg tglog
134 137 @ 7: 'H'
135 138 |
136 139 | o 6: 'G'
137 140 |/|
138 141 o | 5: 'F'
139 142 | |
140 143 | o 4: 'E'
141 144 |/
142 145 | o 3: 'D'
143 146 | |
144 147 | o 2: 'C'
145 148 | |
146 149 | o 1: 'B'
147 150 |/
148 151 o 0: 'A'
149 152
150 153 $ hg rebase --detach -s 1 -d 7
151 154 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
152 155
153 156 $ hg tglog
154 157 @ 7: 'D'
155 158 |
156 159 o 6: 'C'
157 160 |
158 161 o 5: 'B'
159 162 |
160 163 o 4: 'H'
161 164 |
162 165 | o 3: 'G'
163 166 |/|
164 167 o | 2: 'F'
165 168 | |
166 169 | o 1: 'E'
167 170 |/
168 171 o 0: 'A'
169 172
170 173 $ hg manifest
171 174 A
172 175 B
173 176 C
174 177 D
175 178 F
176 179 H
177 180
178 181 $ cd ..
179 182
180 183
181 184 Rebasing C onto H detaching from B and collapsing:
182 185
183 186 $ hg clone -q -u . a a4
184 187 $ cd a4
185 188
186 189 $ hg tglog
187 190 @ 7: 'H'
188 191 |
189 192 | o 6: 'G'
190 193 |/|
191 194 o | 5: 'F'
192 195 | |
193 196 | o 4: 'E'
194 197 |/
195 198 | o 3: 'D'
196 199 | |
197 200 | o 2: 'C'
198 201 | |
199 202 | o 1: 'B'
200 203 |/
201 204 o 0: 'A'
202 205
203 206 $ hg rebase --detach --collapse -s 2 -d 7
204 207 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
205 208
206 209 $ hg tglog
207 210 @ 6: 'Collapsed revision
208 211 | * C
209 212 | * D'
210 213 o 5: 'H'
211 214 |
212 215 | o 4: 'G'
213 216 |/|
214 217 o | 3: 'F'
215 218 | |
216 219 | o 2: 'E'
217 220 |/
218 221 | o 1: 'B'
219 222 |/
220 223 o 0: 'A'
221 224
222 225 $ hg manifest
223 226 A
224 227 C
225 228 D
226 229 F
227 230 H
228 231
229 232 $ cd ..
230 233
231 234 Rebasing across null as ancestor
232 235 $ hg clone -q -U a a5
233 236
234 237 $ cd a5
235 238
236 239 $ echo x > x
237 240
238 241 $ hg add x
239 242
240 243 $ hg ci -m "extra branch"
241 244 created new head
242 245
243 246 $ hg tglog
244 247 @ 8: 'extra branch'
245 248
246 249 o 7: 'H'
247 250 |
248 251 | o 6: 'G'
249 252 |/|
250 253 o | 5: 'F'
251 254 | |
252 255 | o 4: 'E'
253 256 |/
254 257 | o 3: 'D'
255 258 | |
256 259 | o 2: 'C'
257 260 | |
258 261 | o 1: 'B'
259 262 |/
260 263 o 0: 'A'
261 264
262 265 $ hg rebase --detach -s 1 -d tip
263 266 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
264 267
265 268 $ hg tglog
266 269 @ 8: 'D'
267 270 |
268 271 o 7: 'C'
269 272 |
270 273 o 6: 'B'
271 274 |
272 275 o 5: 'extra branch'
273 276
274 277 o 4: 'H'
275 278 |
276 279 | o 3: 'G'
277 280 |/|
278 281 o | 2: 'F'
279 282 | |
280 283 | o 1: 'E'
281 284 |/
282 285 o 0: 'A'
283 286
284 287
285 288 $ hg rebase -d 5 -s 7
286 289 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/13547172c9c0-backup.hg (glob)
287 290 $ hg tglog
288 291 @ 8: 'D'
289 292 |
290 293 o 7: 'C'
291 294 |
292 295 | o 6: 'B'
293 296 |/
294 297 o 5: 'extra branch'
295 298
296 299 o 4: 'H'
297 300 |
298 301 | o 3: 'G'
299 302 |/|
300 303 o | 2: 'F'
301 304 | |
302 305 | o 1: 'E'
303 306 |/
304 307 o 0: 'A'
305 308
306 309 $ cd ..
307 310
308 311 Verify that target is not selected as external rev (issue3085)
309 312
310 313 $ hg clone -q -U a a6
311 314 $ cd a6
312 315 $ hg up -q 6
313 316
314 317 $ echo "I" >> E
315 318 $ hg ci -m "I"
316 319 $ hg merge 7
317 320 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 321 (branch merge, don't forget to commit)
319 322 $ hg ci -m "Merge"
320 323 $ echo "J" >> F
321 324 $ hg ci -m "J"
322 325
323 326 $ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other
324 327 remote changed E which local deleted
325 328 use (c)hanged version or leave (d)eleted? c
326 329 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
327 330
328 331 $ hg tglog
329 332 @ 8: 'Collapsed revision
330 333 | * I
331 334 | * Merge
332 335 | * J'
333 336 o 7: 'H'
334 337 |
335 338 | o 6: 'G'
336 339 |/|
337 340 o | 5: 'F'
338 341 | |
339 342 | o 4: 'E'
340 343 |/
341 344 | o 3: 'D'
342 345 | |
343 346 | o 2: 'C'
344 347 | |
345 348 | o 1: 'B'
346 349 |/
347 350 o 0: 'A'
348 351
349 352
350 353 $ hg parents
351 354 changeset: 8:9472f4b1d736
352 355 tag: tip
353 356 user: test
354 357 date: Thu Jan 01 00:00:00 1970 +0000
355 358 summary: Collapsed revision
356 359
357 360
358 361 $ cd ..
359 362
360 363 Ensure --continue restores a correct state (issue3046):
361 364 $ hg clone -q a a7
362 365 $ cd a7
363 366 $ hg up -q 3
364 367 $ echo 'H2' > H
365 368 $ hg ci -A -m 'H2'
366 369 adding H
367 370 $ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail
368 371 merging H
369 372 warning: conflicts during merge.
370 373 merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
371 374 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
372 375 [255]
373 376 $ hg resolve --all -t internal:local
374 377 $ hg rebase -c
375 378 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
376 379 $ hg tglog
377 380 @ 8: 'H2'
378 381 |
379 382 o 7: 'H'
380 383 |
381 384 | o 6: 'G'
382 385 |/|
383 386 o | 5: 'F'
384 387 | |
385 388 | o 4: 'E'
386 389 |/
387 390 | o 3: 'D'
388 391 | |
389 392 | o 2: 'C'
390 393 | |
391 394 | o 1: 'B'
392 395 |/
393 396 o 0: 'A'
394 397
395 398
@@ -1,194 +1,197 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo A > A
15 18 $ hg ci -Am A
16 19 adding A
17 20
18 21 $ echo B > B
19 22 $ hg ci -Am B
20 23 adding B
21 24
22 25 $ echo C >> A
23 26 $ hg ci -m C
24 27
25 28 $ hg up -q -C 0
26 29
27 30 $ echo D >> A
28 31 $ hg ci -m D
29 32 created new head
30 33
31 34 $ echo E > E
32 35 $ hg ci -Am E
33 36 adding E
34 37
35 38 $ cd ..
36 39
37 40
38 41 Changes during an interruption - continue:
39 42
40 43 $ hg clone -q -u . a a1
41 44 $ cd a1
42 45
43 46 $ hg tglog
44 47 @ 4: 'E'
45 48 |
46 49 o 3: 'D'
47 50 |
48 51 | o 2: 'C'
49 52 | |
50 53 | o 1: 'B'
51 54 |/
52 55 o 0: 'A'
53 56
54 57 Rebasing B onto E:
55 58
56 59 $ hg rebase -s 1 -d 4
57 60 merging A
58 61 warning: conflicts during merge.
59 62 merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
60 63 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
61 64 [255]
62 65
63 66 Force a commit on C during the interruption:
64 67
65 68 $ hg up -q -C 2
66 69
67 70 $ echo 'Extra' > Extra
68 71 $ hg add Extra
69 72 $ hg ci -m 'Extra'
70 73
71 74 $ hg tglog
72 75 @ 6: 'Extra'
73 76 |
74 77 | o 5: 'B'
75 78 | |
76 79 | o 4: 'E'
77 80 | |
78 81 | o 3: 'D'
79 82 | |
80 83 o | 2: 'C'
81 84 | |
82 85 o | 1: 'B'
83 86 |/
84 87 o 0: 'A'
85 88
86 89 Resume the rebasing:
87 90
88 91 $ hg rebase --continue
89 92 merging A
90 93 warning: conflicts during merge.
91 94 merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
92 95 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
93 96 [255]
94 97
95 98 Solve the conflict and go on:
96 99
97 100 $ echo 'conflict solved' > A
98 101 $ rm A.orig
99 102 $ hg resolve -m A
100 103
101 104 $ hg rebase --continue
102 105 warning: new changesets detected on source branch, not stripping
103 106
104 107 $ hg tglog
105 108 @ 7: 'C'
106 109 |
107 110 | o 6: 'Extra'
108 111 | |
109 112 o | 5: 'B'
110 113 | |
111 114 o | 4: 'E'
112 115 | |
113 116 o | 3: 'D'
114 117 | |
115 118 | o 2: 'C'
116 119 | |
117 120 | o 1: 'B'
118 121 |/
119 122 o 0: 'A'
120 123
121 124 $ cd ..
122 125
123 126
124 127 Changes during an interruption - abort:
125 128
126 129 $ hg clone -q -u . a a2
127 130 $ cd a2
128 131
129 132 $ hg tglog
130 133 @ 4: 'E'
131 134 |
132 135 o 3: 'D'
133 136 |
134 137 | o 2: 'C'
135 138 | |
136 139 | o 1: 'B'
137 140 |/
138 141 o 0: 'A'
139 142
140 143 Rebasing B onto E:
141 144
142 145 $ hg rebase -s 1 -d 4
143 146 merging A
144 147 warning: conflicts during merge.
145 148 merging A incomplete! (edit conflicts, then use 'hg resolve --mark')
146 149 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
147 150 [255]
148 151
149 152 Force a commit on B' during the interruption:
150 153
151 154 $ hg up -q -C 5
152 155
153 156 $ echo 'Extra' > Extra
154 157 $ hg add Extra
155 158 $ hg ci -m 'Extra'
156 159
157 160 $ hg tglog
158 161 @ 6: 'Extra'
159 162 |
160 163 o 5: 'B'
161 164 |
162 165 o 4: 'E'
163 166 |
164 167 o 3: 'D'
165 168 |
166 169 | o 2: 'C'
167 170 | |
168 171 | o 1: 'B'
169 172 |/
170 173 o 0: 'A'
171 174
172 175 Abort the rebasing:
173 176
174 177 $ hg rebase --abort
175 178 warning: new changesets detected on target branch, can't abort
176 179 [255]
177 180
178 181 $ hg tglog
179 182 @ 6: 'Extra'
180 183 |
181 184 o 5: 'B'
182 185 |
183 186 o 4: 'E'
184 187 |
185 188 o 3: 'D'
186 189 |
187 190 | o 2: 'C'
188 191 | |
189 192 | o 1: 'B'
190 193 |/
191 194 o 0: 'A'
192 195
193 196 $ cd ..
194 197
@@ -1,123 +1,126 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16
14 17 $ echo c1 > c1
15 18 $ hg ci -Am c1
16 19 adding c1
17 20
18 21 $ echo c2 > c2
19 22 $ hg ci -Am c2
20 23 adding c2
21 24
22 25 $ echo l1 > l1
23 26 $ hg ci -Am l1
24 27 adding l1
25 28
26 29 $ hg up -q -C 1
27 30
28 31 $ echo r1 > r1
29 32 $ hg ci -Am r1
30 33 adding r1
31 34 created new head
32 35
33 36 $ echo r2 > r2
34 37 $ hg ci -Am r2
35 38 adding r2
36 39
37 40 $ hg tglog
38 41 @ 4: 'r2'
39 42 |
40 43 o 3: 'r1'
41 44 |
42 45 | o 2: 'l1'
43 46 |/
44 47 o 1: 'c2'
45 48 |
46 49 o 0: 'c1'
47 50
48 51 Rebase with no arguments - single revision in source branch:
49 52
50 53 $ hg up -q -C 2
51 54
52 55 $ hg rebase
53 56 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
54 57
55 58 $ hg tglog
56 59 @ 4: 'l1'
57 60 |
58 61 o 3: 'r2'
59 62 |
60 63 o 2: 'r1'
61 64 |
62 65 o 1: 'c2'
63 66 |
64 67 o 0: 'c1'
65 68
66 69 $ cd ..
67 70
68 71
69 72 $ hg init b
70 73 $ cd b
71 74
72 75 $ echo c1 > c1
73 76 $ hg ci -Am c1
74 77 adding c1
75 78
76 79 $ echo c2 > c2
77 80 $ hg ci -Am c2
78 81 adding c2
79 82
80 83 $ echo l1 > l1
81 84 $ hg ci -Am l1
82 85 adding l1
83 86
84 87 $ echo l2 > l2
85 88 $ hg ci -Am l2
86 89 adding l2
87 90
88 91 $ hg up -q -C 1
89 92
90 93 $ echo r1 > r1
91 94 $ hg ci -Am r1
92 95 adding r1
93 96 created new head
94 97
95 98 $ hg tglog
96 99 @ 4: 'r1'
97 100 |
98 101 | o 3: 'l2'
99 102 | |
100 103 | o 2: 'l1'
101 104 |/
102 105 o 1: 'c2'
103 106 |
104 107 o 0: 'c1'
105 108
106 109 Rebase with no arguments - single revision in target branch:
107 110
108 111 $ hg up -q -C 3
109 112
110 113 $ hg rebase
111 114 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
112 115
113 116 $ hg tglog
114 117 @ 4: 'l2'
115 118 |
116 119 o 3: 'l1'
117 120 |
118 121 o 2: 'r1'
119 122 |
120 123 o 1: 'c2'
121 124 |
122 125 o 0: 'c1'
123 126
@@ -1,136 +1,139 b''
1 1 This emulates the effects of an hg pull --rebase in which the remote repo
2 2 already has one local mq patch
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > graphlog=
7 7 > rebase=
8 8 > mq=
9 9 >
10 > [phases]
11 > publish=False
12 >
10 13 > [alias]
11 14 > tglog = log -G --template "{rev}: '{desc}' tags: {tags}\n"
12 15 > EOF
13 16
14 17
15 18 $ hg init a
16 19 $ cd a
17 20 $ hg qinit -c
18 21
19 22 $ echo c1 > c1
20 23 $ hg add c1
21 24 $ hg ci -m C1
22 25
23 26 $ echo r1 > r1
24 27 $ hg add r1
25 28 $ hg ci -m R1
26 29
27 30 $ hg up -q 0
28 31
29 32 $ hg qnew p0.patch
30 33 $ echo p0 > p0
31 34 $ hg add p0
32 35 $ hg qref -m P0
33 36
34 37 $ hg qnew p1.patch
35 38 $ echo p1 > p1
36 39 $ hg add p1
37 40 $ hg qref -m P1
38 41
39 42 $ hg export qtip > p1.patch
40 43
41 44 $ hg up -q -C 1
42 45
43 46 $ hg import p1.patch
44 47 applying p1.patch
45 48
46 49 $ rm p1.patch
47 50
48 51 $ hg up -q -C qtip
49 52
50 53 $ hg rebase
51 54 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
52 55
53 56 $ hg tglog
54 57 @ 3: 'P0' tags: p0.patch qbase qtip tip
55 58 |
56 59 o 2: 'P1' tags: qparent
57 60 |
58 61 o 1: 'R1' tags:
59 62 |
60 63 o 0: 'C1' tags:
61 64
62 65 $ cd ..
63 66
64 67
65 68 $ hg init b
66 69 $ cd b
67 70 $ hg qinit -c
68 71
69 72 $ for i in r0 r1 r2 r3 r4 r5 r6;
70 73 > do
71 74 > echo $i > $i
72 75 > hg ci -Am $i
73 76 > done
74 77 adding r0
75 78 adding r1
76 79 adding r2
77 80 adding r3
78 81 adding r4
79 82 adding r5
80 83 adding r6
81 84
82 85 $ hg qimport -r 1:tip
83 86
84 87 $ hg up -q 0
85 88
86 89 $ for i in r1 r3 r7 r8;
87 90 > do
88 91 > echo $i > $i
89 92 > hg ci -Am branch2-$i
90 93 > done
91 94 adding r1
92 95 created new head
93 96 adding r3
94 97 adding r7
95 98 adding r8
96 99
97 100 $ echo somethingelse > r4
98 101 $ hg ci -Am branch2-r4
99 102 adding r4
100 103
101 104 $ echo r6 > r6
102 105 $ hg ci -Am branch2-r6
103 106 adding r6
104 107
105 108 $ hg up -q qtip
106 109
107 110 $ HGMERGE=internal:fail hg rebase
108 111 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
109 112 [255]
110 113
111 114 $ HGMERGE=internal:local hg resolve --all
112 115
113 116 $ hg rebase --continue
114 117 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
115 118
116 119 $ hg tglog
117 120 @ 9: 'r5' tags: 5.diff qtip tip
118 121 |
119 122 o 8: 'r4' tags: 4.diff
120 123 |
121 124 o 7: 'r2' tags: 2.diff qbase
122 125 |
123 126 o 6: 'branch2-r6' tags: qparent
124 127 |
125 128 o 5: 'branch2-r4' tags:
126 129 |
127 130 o 4: 'branch2-r8' tags:
128 131 |
129 132 o 3: 'branch2-r7' tags:
130 133 |
131 134 o 2: 'branch2-r3' tags:
132 135 |
133 136 o 1: 'branch2-r1' tags:
134 137 |
135 138 o 0: 'r0' tags:
136 139
@@ -1,108 +1,111 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13 $ hg init a
11 14 $ cd a
12 15 $ hg unbundle $TESTDIR/bundles/rebase.hg
13 16 adding changesets
14 17 adding manifests
15 18 adding file changes
16 19 added 8 changesets with 7 changes to 7 files (+2 heads)
17 20 (run 'hg heads' to see heads, 'hg merge' to merge)
18 21 $ hg up tip
19 22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 23 $ cd ..
21 24
22 25
23 26 Rebasing descendant onto ancestor across different named branches
24 27
25 28 $ hg clone -q -u . a a1
26 29
27 30 $ cd a1
28 31
29 32 $ hg branch dev
30 33 marked working directory as branch dev
31 34 (branches are permanent and global, did you want a bookmark?)
32 35
33 36 $ echo x > x
34 37
35 38 $ hg add x
36 39
37 40 $ hg ci -m 'extra named branch'
38 41
39 42 $ hg tglog
40 43 @ 8: 'extra named branch' dev
41 44 |
42 45 o 7: 'H'
43 46 |
44 47 | o 6: 'G'
45 48 |/|
46 49 o | 5: 'F'
47 50 | |
48 51 | o 4: 'E'
49 52 |/
50 53 | o 3: 'D'
51 54 | |
52 55 | o 2: 'C'
53 56 | |
54 57 | o 1: 'B'
55 58 |/
56 59 o 0: 'A'
57 60
58 61
59 62
60 63 $ hg rebase -s 1 -d 8 --keepbranches
61 64 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
62 65
63 66 $ hg tglog
64 67 @ 8: 'D'
65 68 |
66 69 o 7: 'C'
67 70 |
68 71 o 6: 'B'
69 72 |
70 73 o 5: 'extra named branch' dev
71 74 |
72 75 o 4: 'H'
73 76 |
74 77 | o 3: 'G'
75 78 |/|
76 79 o | 2: 'F'
77 80 | |
78 81 | o 1: 'E'
79 82 |/
80 83 o 0: 'A'
81 84
82 85 $ hg rebase -s 4 -d 5
83 86 abort: source is ancestor of destination
84 87 [255]
85 88
86 89 $ hg rebase -s 5 -d 4
87 90 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
88 91
89 92 $ hg tglog
90 93 @ 8: 'D'
91 94 |
92 95 o 7: 'C'
93 96 |
94 97 o 6: 'B'
95 98 |
96 99 o 5: 'extra named branch'
97 100 |
98 101 o 4: 'H'
99 102 |
100 103 | o 3: 'G'
101 104 |/|
102 105 o | 2: 'F'
103 106 | |
104 107 | o 1: 'E'
105 108 |/
106 109 o 0: 'A'
107 110
108 111 $ cd ..
@@ -1,389 +1,392 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16 $ hg unbundle $TESTDIR/bundles/rebase.hg
14 17 adding changesets
15 18 adding manifests
16 19 adding file changes
17 20 added 8 changesets with 7 changes to 7 files (+2 heads)
18 21 (run 'hg heads' to see heads, 'hg merge' to merge)
19 22 $ hg up tip
20 23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 24
22 25 $ echo I > I
23 26 $ hg ci -AmI
24 27 adding I
25 28
26 29 $ hg tglog
27 30 @ 8: 'I'
28 31 |
29 32 o 7: 'H'
30 33 |
31 34 | o 6: 'G'
32 35 |/|
33 36 o | 5: 'F'
34 37 | |
35 38 | o 4: 'E'
36 39 |/
37 40 | o 3: 'D'
38 41 | |
39 42 | o 2: 'C'
40 43 | |
41 44 | o 1: 'B'
42 45 |/
43 46 o 0: 'A'
44 47
45 48 $ cd ..
46 49
47 50
48 51 These fail:
49 52
50 53 $ hg clone -q -u . a a1
51 54 $ cd a1
52 55
53 56 $ hg rebase -s 8 -d 7
54 57 nothing to rebase
55 58 [1]
56 59
57 60 $ hg rebase --continue --abort
58 61 abort: cannot use both abort and continue
59 62 [255]
60 63
61 64 $ hg rebase --continue --collapse
62 65 abort: cannot use collapse with continue or abort
63 66 [255]
64 67
65 68 $ hg rebase --continue --dest 4
66 69 abort: abort and continue do not allow specifying revisions
67 70 [255]
68 71
69 72 $ hg rebase --base 5 --source 4
70 73 abort: cannot specify both a source and a base
71 74 [255]
72 75
73 76 $ hg rebase
74 77 nothing to rebase
75 78 [1]
76 79
77 80 $ hg up -q 7
78 81
79 82 $ hg rebase --traceback
80 83 nothing to rebase
81 84 [1]
82 85
83 86
84 87 These work:
85 88
86 89 Rebase with no arguments (from 3 onto 8):
87 90
88 91 $ hg up -q -C 3
89 92
90 93 $ hg rebase
91 94 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
92 95
93 96 $ hg tglog
94 97 @ 8: 'D'
95 98 |
96 99 o 7: 'C'
97 100 |
98 101 o 6: 'B'
99 102 |
100 103 o 5: 'I'
101 104 |
102 105 o 4: 'H'
103 106 |
104 107 | o 3: 'G'
105 108 |/|
106 109 o | 2: 'F'
107 110 | |
108 111 | o 1: 'E'
109 112 |/
110 113 o 0: 'A'
111 114
112 115 Try to rollback after a rebase (fail):
113 116
114 117 $ hg rollback
115 118 no rollback information available
116 119 [1]
117 120
118 121 $ cd ..
119 122
120 123
121 124 Rebase with base == '.' => same as no arguments (from 3 onto 8):
122 125
123 126 $ hg clone -q -u 3 a a2
124 127 $ cd a2
125 128
126 129 $ hg rebase --base .
127 130 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
128 131
129 132 $ hg tglog
130 133 @ 8: 'D'
131 134 |
132 135 o 7: 'C'
133 136 |
134 137 o 6: 'B'
135 138 |
136 139 o 5: 'I'
137 140 |
138 141 o 4: 'H'
139 142 |
140 143 | o 3: 'G'
141 144 |/|
142 145 o | 2: 'F'
143 146 | |
144 147 | o 1: 'E'
145 148 |/
146 149 o 0: 'A'
147 150
148 151 $ cd ..
149 152
150 153
151 154 Rebase with dest == `hg branch` => same as no arguments (from 3 onto 8):
152 155
153 156 $ hg clone -q -u 3 a a3
154 157 $ cd a3
155 158
156 159 $ hg rebase --dest `hg branch`
157 160 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
158 161
159 162 $ hg tglog
160 163 @ 8: 'D'
161 164 |
162 165 o 7: 'C'
163 166 |
164 167 o 6: 'B'
165 168 |
166 169 o 5: 'I'
167 170 |
168 171 o 4: 'H'
169 172 |
170 173 | o 3: 'G'
171 174 |/|
172 175 o | 2: 'F'
173 176 | |
174 177 | o 1: 'E'
175 178 |/
176 179 o 0: 'A'
177 180
178 181 $ cd ..
179 182
180 183
181 184 Specify only source (from 2 onto 8):
182 185
183 186 $ hg clone -q -u . a a4
184 187 $ cd a4
185 188
186 189 $ hg rebase --source 2
187 190 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
188 191
189 192 $ hg tglog
190 193 @ 8: 'D'
191 194 |
192 195 o 7: 'C'
193 196 |\
194 197 | o 6: 'I'
195 198 | |
196 199 | o 5: 'H'
197 200 | |
198 201 | | o 4: 'G'
199 202 | |/|
200 203 | o | 3: 'F'
201 204 | | |
202 205 | | o 2: 'E'
203 206 | |/
204 207 o | 1: 'B'
205 208 |/
206 209 o 0: 'A'
207 210
208 211 $ cd ..
209 212
210 213
211 214 Specify only dest (from 3 onto 6):
212 215
213 216 $ hg clone -q -u 3 a a5
214 217 $ cd a5
215 218
216 219 $ hg rebase --dest 6
217 220 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
218 221
219 222 $ hg tglog
220 223 @ 8: 'D'
221 224 |
222 225 o 7: 'C'
223 226 |
224 227 o 6: 'B'
225 228 |
226 229 | o 5: 'I'
227 230 | |
228 231 | o 4: 'H'
229 232 | |
230 233 o | 3: 'G'
231 234 |\|
232 235 | o 2: 'F'
233 236 | |
234 237 o | 1: 'E'
235 238 |/
236 239 o 0: 'A'
237 240
238 241 $ cd ..
239 242
240 243
241 244 Specify only base (from 1 onto 8):
242 245
243 246 $ hg clone -q -u . a a6
244 247 $ cd a6
245 248
246 249 $ hg rebase --base 3
247 250 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
248 251
249 252 $ hg tglog
250 253 @ 8: 'D'
251 254 |
252 255 o 7: 'C'
253 256 |
254 257 o 6: 'B'
255 258 |
256 259 o 5: 'I'
257 260 |
258 261 o 4: 'H'
259 262 |
260 263 | o 3: 'G'
261 264 |/|
262 265 o | 2: 'F'
263 266 | |
264 267 | o 1: 'E'
265 268 |/
266 269 o 0: 'A'
267 270
268 271 $ cd ..
269 272
270 273
271 274 Specify source and dest (from 2 onto 7):
272 275
273 276 $ hg clone -q -u . a a7
274 277 $ cd a7
275 278
276 279 $ hg rebase --detach --source 2 --dest 7
277 280 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob)
278 281
279 282 $ hg tglog
280 283 @ 8: 'D'
281 284 |
282 285 o 7: 'C'
283 286 |
284 287 | o 6: 'I'
285 288 |/
286 289 o 5: 'H'
287 290 |
288 291 | o 4: 'G'
289 292 |/|
290 293 o | 3: 'F'
291 294 | |
292 295 | o 2: 'E'
293 296 |/
294 297 | o 1: 'B'
295 298 |/
296 299 o 0: 'A'
297 300
298 301 $ cd ..
299 302
300 303
301 304 Specify base and dest (from 1 onto 7):
302 305
303 306 $ hg clone -q -u . a a8
304 307 $ cd a8
305 308
306 309 $ hg rebase --base 3 --dest 7
307 310 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/*-backup.hg (glob)
308 311
309 312 $ hg tglog
310 313 @ 8: 'D'
311 314 |
312 315 o 7: 'C'
313 316 |
314 317 o 6: 'B'
315 318 |
316 319 | o 5: 'I'
317 320 |/
318 321 o 4: 'H'
319 322 |
320 323 | o 3: 'G'
321 324 |/|
322 325 o | 2: 'F'
323 326 | |
324 327 | o 1: 'E'
325 328 |/
326 329 o 0: 'A'
327 330
328 331 $ cd ..
329 332
330 333 Test --tool parameter:
331 334
332 335 $ hg init b
333 336 $ cd b
334 337
335 338 $ echo c1 > c1
336 339 $ hg ci -Am c1
337 340 adding c1
338 341
339 342 $ echo c2 > c2
340 343 $ hg ci -Am c2
341 344 adding c2
342 345
343 346 $ hg up -q 0
344 347 $ echo c2b > c2
345 348 $ hg ci -Am c2b
346 349 adding c2
347 350 created new head
348 351
349 352 $ cd ..
350 353
351 354 $ hg clone -q -u . b b1
352 355 $ cd b1
353 356
354 357 $ hg rebase -s 2 -d 1 --tool internal:local
355 358 saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
356 359
357 360 $ hg cat c2
358 361 c2
359 362
360 363 $ cd ..
361 364
362 365
363 366 $ hg clone -q -u . b b2
364 367 $ cd b2
365 368
366 369 $ hg rebase -s 2 -d 1 --tool internal:other
367 370 saved backup bundle to $TESTTMP/b2/.hg/strip-backup/*-backup.hg (glob)
368 371
369 372 $ hg cat c2
370 373 c2b
371 374
372 375 $ cd ..
373 376
374 377
375 378 $ hg clone -q -u . b b3
376 379 $ cd b3
377 380
378 381 $ hg rebase -s 2 -d 1 --tool internal:fail
379 382 abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
380 383 [255]
381 384
382 385 $ hg resolve -l
383 386 U c2
384 387
385 388 $ hg resolve -m c2
386 389 $ hg rebase -c --tool internal:fail
387 390 tool option will be ignored
388 391 saved backup bundle to $TESTTMP/b3/.hg/strip-backup/*-backup.hg (glob)
389 392
@@ -1,508 +1,521 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > graphlog=
4 4 > rebase=
5 5 >
6 > [phases]
7 > publish=False
8 >
6 9 > [alias]
7 10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
8 11 > EOF
9 12
10 13
11 14 $ hg init a
12 15 $ cd a
13 16 $ hg unbundle $TESTDIR/bundles/rebase.hg
14 17 adding changesets
15 18 adding manifests
16 19 adding file changes
17 20 added 8 changesets with 7 changes to 7 files (+2 heads)
18 21 (run 'hg heads' to see heads, 'hg merge' to merge)
19 22 $ hg up tip
20 23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 24 $ cd ..
22 25
23 26
24 27 Rebasing
25 28 D onto H - simple rebase:
26 29
27 30 $ hg clone -q -u . a a1
28 31 $ cd a1
29 32
30 33 $ hg tglog
31 34 @ 7: 'H'
32 35 |
33 36 | o 6: 'G'
34 37 |/|
35 38 o | 5: 'F'
36 39 | |
37 40 | o 4: 'E'
38 41 |/
39 42 | o 3: 'D'
40 43 | |
41 44 | o 2: 'C'
42 45 | |
43 46 | o 1: 'B'
44 47 |/
45 48 o 0: 'A'
46 49
47 50
48 51 $ hg rebase -s 3 -d 7
49 52 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
50 53
51 54 $ hg tglog
52 55 @ 7: 'D'
53 56 |\
54 57 | o 6: 'H'
55 58 | |
56 59 | | o 5: 'G'
57 60 | |/|
58 61 | o | 4: 'F'
59 62 | | |
60 63 | | o 3: 'E'
61 64 | |/
62 65 o | 2: 'C'
63 66 | |
64 67 o | 1: 'B'
65 68 |/
66 69 o 0: 'A'
67 70
68 71 $ cd ..
69 72
70 73
71 74 D onto F - intermediate point:
72 75
73 76 $ hg clone -q -u . a a2
74 77 $ cd a2
75 78
76 79 $ hg rebase -s 3 -d 5
77 80 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
78 81
79 82 $ hg tglog
80 83 @ 7: 'D'
81 84 |\
82 85 | | o 6: 'H'
83 86 | |/
84 87 | | o 5: 'G'
85 88 | |/|
86 89 | o | 4: 'F'
87 90 | | |
88 91 | | o 3: 'E'
89 92 | |/
90 93 o | 2: 'C'
91 94 | |
92 95 o | 1: 'B'
93 96 |/
94 97 o 0: 'A'
95 98
96 99 $ cd ..
97 100
98 101
99 102 E onto H - skip of G:
100 103
101 104 $ hg clone -q -u . a a3
102 105 $ cd a3
103 106
104 107 $ hg rebase -s 4 -d 7
105 108 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
106 109
107 110 $ hg tglog
108 111 @ 6: 'E'
109 112 |
110 113 o 5: 'H'
111 114 |
112 115 o 4: 'F'
113 116 |
114 117 | o 3: 'D'
115 118 | |
116 119 | o 2: 'C'
117 120 | |
118 121 | o 1: 'B'
119 122 |/
120 123 o 0: 'A'
121 124
122 125 $ cd ..
123 126
124 127
125 128 F onto E - rebase of a branching point (skip G):
126 129
127 130 $ hg clone -q -u . a a4
128 131 $ cd a4
129 132
130 133 $ hg rebase -s 5 -d 4
131 134 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
132 135
133 136 $ hg tglog
134 137 @ 6: 'H'
135 138 |
136 139 o 5: 'F'
137 140 |
138 141 o 4: 'E'
139 142 |
140 143 | o 3: 'D'
141 144 | |
142 145 | o 2: 'C'
143 146 | |
144 147 | o 1: 'B'
145 148 |/
146 149 o 0: 'A'
147 150
148 151 $ cd ..
149 152
150 153
151 154 G onto H - merged revision having a parent in ancestors of target:
152 155
153 156 $ hg clone -q -u . a a5
154 157 $ cd a5
155 158
156 159 $ hg rebase -s 6 -d 7
157 160 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
158 161
159 162 $ hg tglog
160 163 @ 7: 'G'
161 164 |\
162 165 | o 6: 'H'
163 166 | |
164 167 | o 5: 'F'
165 168 | |
166 169 o | 4: 'E'
167 170 |/
168 171 | o 3: 'D'
169 172 | |
170 173 | o 2: 'C'
171 174 | |
172 175 | o 1: 'B'
173 176 |/
174 177 o 0: 'A'
175 178
176 179 $ cd ..
177 180
178 181
179 182 F onto B - G maintains E as parent:
180 183
181 184 $ hg clone -q -u . a a6
182 185 $ cd a6
183 186
184 187 $ hg rebase -s 5 -d 1
185 188 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
186 189
187 190 $ hg tglog
188 191 @ 7: 'H'
189 192 |
190 193 | o 6: 'G'
191 194 |/|
192 195 o | 5: 'F'
193 196 | |
194 197 | o 4: 'E'
195 198 | |
196 199 | | o 3: 'D'
197 200 | | |
198 201 +---o 2: 'C'
199 202 | |
200 203 o | 1: 'B'
201 204 |/
202 205 o 0: 'A'
203 206
204 207 $ cd ..
205 208
206 209
207 210 These will fail (using --source):
208 211
209 212 G onto F - rebase onto an ancestor:
210 213
211 214 $ hg clone -q -u . a a7
212 215 $ cd a7
213 216
214 217 $ hg rebase -s 6 -d 5
215 218 nothing to rebase
216 219 [1]
217 220
218 221 F onto G - rebase onto a descendant:
219 222
220 223 $ hg rebase -s 5 -d 6
221 224 abort: source is ancestor of destination
222 225 [255]
223 226
224 227 G onto B - merge revision with both parents not in ancestors of target:
225 228
226 229 $ hg rebase -s 6 -d 1
227 230 abort: cannot use revision 6 as base, result would have 3 parents
228 231 [255]
229 232
230 233
231 234 These will abort gracefully (using --base):
232 235
233 236 G onto G - rebase onto same changeset:
234 237
235 238 $ hg rebase -b 6 -d 6
236 239 nothing to rebase
237 240 [1]
238 241
239 242 G onto F - rebase onto an ancestor:
240 243
241 244 $ hg rebase -b 6 -d 5
242 245 nothing to rebase
243 246 [1]
244 247
245 248 F onto G - rebase onto a descendant:
246 249
247 250 $ hg rebase -b 5 -d 6
248 251 nothing to rebase
249 252 [1]
250 253
251 254 C onto A - rebase onto an ancestor:
252 255
253 256 $ hg rebase -d 0 -s 2
254 257 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-backup.hg (glob)
255 258 $ hg tglog
256 259 @ 7: 'D'
257 260 |
258 261 o 6: 'C'
259 262 |
260 263 | o 5: 'H'
261 264 | |
262 265 | | o 4: 'G'
263 266 | |/|
264 267 | o | 3: 'F'
265 268 |/ /
266 269 | o 2: 'E'
267 270 |/
268 271 | o 1: 'B'
269 272 |/
270 273 o 0: 'A'
271 274
275
276 Check rebasing public changeset
277
278 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
279 $ hg rebase -d 5 -b 6
280 abort: Can't rebase immutable changeset e1c4361dd923
281 (see hg help phases for details)
282 [255]
283
284 $ hg rebase -d 5 -b 6 --keep
272 285 $ cd ..
273 286
274 287 Test for revset
275 288
276 289 We need a bit different graph
277 290 All destination are B
278 291
279 292 $ hg init ah
280 293 $ cd ah
281 294 $ hg unbundle $TESTDIR/bundles/rebase-revset.hg
282 295 adding changesets
283 296 adding manifests
284 297 adding file changes
285 298 added 9 changesets with 9 changes to 9 files (+2 heads)
286 299 (run 'hg heads' to see heads, 'hg merge' to merge)
287 300 $ hg tglog
288 301 o 8: 'I'
289 302 |
290 303 o 7: 'H'
291 304 |
292 305 o 6: 'G'
293 306 |
294 307 | o 5: 'F'
295 308 | |
296 309 | o 4: 'E'
297 310 |/
298 311 o 3: 'D'
299 312 |
300 313 o 2: 'C'
301 314 |
302 315 | o 1: 'B'
303 316 |/
304 317 o 0: 'A'
305 318
306 319 $ cd ..
307 320
308 321
309 322 Simple case with keep:
310 323
311 324 Source on have two descendant heads but ask for one
312 325
313 326 $ hg clone -q -u . ah ah1
314 327 $ cd ah1
315 328 $ hg rebase -r '2::8' -d 1
316 329 abort: can't remove original changesets with unrebased descendants
317 330 (use --keep to keep original changesets)
318 331 [255]
319 332 $ hg rebase -r '2::8' -d 1 --keep
320 333 $ hg tglog
321 334 @ 13: 'I'
322 335 |
323 336 o 12: 'H'
324 337 |
325 338 o 11: 'G'
326 339 |
327 340 o 10: 'D'
328 341 |
329 342 o 9: 'C'
330 343 |
331 344 | o 8: 'I'
332 345 | |
333 346 | o 7: 'H'
334 347 | |
335 348 | o 6: 'G'
336 349 | |
337 350 | | o 5: 'F'
338 351 | | |
339 352 | | o 4: 'E'
340 353 | |/
341 354 | o 3: 'D'
342 355 | |
343 356 | o 2: 'C'
344 357 | |
345 358 o | 1: 'B'
346 359 |/
347 360 o 0: 'A'
348 361
349 362
350 363 $ cd ..
351 364
352 365 Base on have one descendant heads we ask for but common ancestor have two
353 366
354 367 $ hg clone -q -u . ah ah2
355 368 $ cd ah2
356 369 $ hg rebase -r '3::8' -d 1
357 370 abort: can't remove original changesets with unrebased descendants
358 371 (use --keep to keep original changesets)
359 372 [255]
360 373 $ hg rebase -r '3::8' -d 1 --keep
361 374 $ hg tglog
362 375 @ 12: 'I'
363 376 |
364 377 o 11: 'H'
365 378 |
366 379 o 10: 'G'
367 380 |
368 381 o 9: 'D'
369 382 |\
370 383 | | o 8: 'I'
371 384 | | |
372 385 | | o 7: 'H'
373 386 | | |
374 387 | | o 6: 'G'
375 388 | | |
376 389 | | | o 5: 'F'
377 390 | | | |
378 391 | | | o 4: 'E'
379 392 | | |/
380 393 | | o 3: 'D'
381 394 | |/
382 395 | o 2: 'C'
383 396 | |
384 397 o | 1: 'B'
385 398 |/
386 399 o 0: 'A'
387 400
388 401
389 402 $ cd ..
390 403
391 404 rebase subset
392 405
393 406 $ hg clone -q -u . ah ah3
394 407 $ cd ah3
395 408 $ hg rebase -r '3::7' -d 1
396 409 abort: can't remove original changesets with unrebased descendants
397 410 (use --keep to keep original changesets)
398 411 [255]
399 412 $ hg rebase -r '3::7' -d 1 --keep
400 413 $ hg tglog
401 414 @ 11: 'H'
402 415 |
403 416 o 10: 'G'
404 417 |
405 418 o 9: 'D'
406 419 |\
407 420 | | o 8: 'I'
408 421 | | |
409 422 | | o 7: 'H'
410 423 | | |
411 424 | | o 6: 'G'
412 425 | | |
413 426 | | | o 5: 'F'
414 427 | | | |
415 428 | | | o 4: 'E'
416 429 | | |/
417 430 | | o 3: 'D'
418 431 | |/
419 432 | o 2: 'C'
420 433 | |
421 434 o | 1: 'B'
422 435 |/
423 436 o 0: 'A'
424 437
425 438
426 439 $ cd ..
427 440
428 441 rebase subset with multiple head
429 442
430 443 $ hg clone -q -u . ah ah4
431 444 $ cd ah4
432 445 $ hg rebase -r '3::(7+5)' -d 1
433 446 abort: can't remove original changesets with unrebased descendants
434 447 (use --keep to keep original changesets)
435 448 [255]
436 449 $ hg rebase -r '3::(7+5)' -d 1 --keep
437 450 $ hg tglog
438 451 @ 13: 'H'
439 452 |
440 453 o 12: 'G'
441 454 |
442 455 | o 11: 'F'
443 456 | |
444 457 | o 10: 'E'
445 458 |/
446 459 o 9: 'D'
447 460 |\
448 461 | | o 8: 'I'
449 462 | | |
450 463 | | o 7: 'H'
451 464 | | |
452 465 | | o 6: 'G'
453 466 | | |
454 467 | | | o 5: 'F'
455 468 | | | |
456 469 | | | o 4: 'E'
457 470 | | |/
458 471 | | o 3: 'D'
459 472 | |/
460 473 | o 2: 'C'
461 474 | |
462 475 o | 1: 'B'
463 476 |/
464 477 o 0: 'A'
465 478
466 479
467 480 $ cd ..
468 481
469 482 More advanced tests
470 483
471 484 rebase on ancestor with revset
472 485
473 486 $ hg clone -q -u . ah ah5
474 487 $ cd ah5
475 488 $ hg rebase -r '6::' -d 2
476 489 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-backup.hg (glob)
477 490 $ hg tglog
478 491 @ 8: 'I'
479 492 |
480 493 o 7: 'H'
481 494 |
482 495 o 6: 'G'
483 496 |
484 497 | o 5: 'F'
485 498 | |
486 499 | o 4: 'E'
487 500 | |
488 501 | o 3: 'D'
489 502 |/
490 503 o 2: 'C'
491 504 |
492 505 | o 1: 'B'
493 506 |/
494 507 o 0: 'A'
495 508
496 509 $ cd ..
497 510
498 511
499 512 rebase with multiple root.
500 513 We rebase E and G on B
501 514 We would expect heads are I, F if it was supported
502 515
503 516 $ hg clone -q -u . ah ah6
504 517 $ cd ah6
505 518 $ hg rebase -r '(4+6)::' -d 1
506 519 abort: can't rebase multiple roots
507 520 [255]
508 521 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now