##// END OF EJS Templates
rebase: improve error message for --base being empty or causing emptiness...
Mads Kiilerich -
r20249:dc515784 default
parent child Browse files
Show More
@@ -1,921 +1,947 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, scmutil, phases, obsolete, error
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 revignored = -3
27 27
28 28 cmdtable = {}
29 29 command = cmdutil.command(cmdtable)
30 30 testedwith = 'internal'
31 31
32 32 def _savegraft(ctx, extra):
33 33 s = ctx.extra().get('source', None)
34 34 if s is not None:
35 35 extra['source'] = s
36 36
37 37 def _savebranch(ctx, extra):
38 38 extra['branch'] = ctx.branch()
39 39
40 40 def _makeextrafn(copiers):
41 41 """make an extrafn out of the given copy-functions.
42 42
43 43 A copy function takes a context and an extra dict, and mutates the
44 44 extra dict as needed based on the given context.
45 45 """
46 46 def extrafn(ctx, extra):
47 47 for c in copiers:
48 48 c(ctx, extra)
49 49 return extrafn
50 50
51 51 @command('rebase',
52 52 [('s', 'source', '',
53 53 _('rebase from the specified changeset'), _('REV')),
54 54 ('b', 'base', '',
55 55 _('rebase from the base of the specified changeset '
56 56 '(up to greatest common ancestor of base and dest)'),
57 57 _('REV')),
58 58 ('r', 'rev', [],
59 59 _('rebase these revisions'),
60 60 _('REV')),
61 61 ('d', 'dest', '',
62 62 _('rebase onto the specified changeset'), _('REV')),
63 63 ('', 'collapse', False, _('collapse the rebased changesets')),
64 64 ('m', 'message', '',
65 65 _('use text as collapse commit message'), _('TEXT')),
66 66 ('e', 'edit', False, _('invoke editor on commit messages')),
67 67 ('l', 'logfile', '',
68 68 _('read collapse commit message from file'), _('FILE')),
69 69 ('', 'keep', False, _('keep original changesets')),
70 70 ('', 'keepbranches', False, _('keep original branch names')),
71 71 ('D', 'detach', False, _('(DEPRECATED)')),
72 72 ('t', 'tool', '', _('specify merge tool')),
73 73 ('c', 'continue', False, _('continue an interrupted rebase')),
74 74 ('a', 'abort', False, _('abort an interrupted rebase'))] +
75 75 templateopts,
76 76 _('[-s REV | -b REV] [-d REV] [OPTION]'))
77 77 def rebase(ui, repo, **opts):
78 78 """move changeset (and descendants) to a different branch
79 79
80 80 Rebase uses repeated merging to graft changesets from one part of
81 81 history (the source) onto another (the destination). This can be
82 82 useful for linearizing *local* changes relative to a master
83 83 development tree.
84 84
85 85 You should not rebase changesets that have already been shared
86 86 with others. Doing so will force everybody else to perform the
87 87 same rebase or they will end up with duplicated changesets after
88 88 pulling in your rebased changesets.
89 89
90 90 In its default configuration, Mercurial will prevent you from
91 91 rebasing published changes. See :hg:`help phases` for details.
92 92
93 93 If you don't specify a destination changeset (``-d/--dest``),
94 94 rebase uses the current branch tip as the destination. (The
95 95 destination changeset is not modified by rebasing, but new
96 96 changesets are added as its descendants.)
97 97
98 98 You can specify which changesets to rebase in two ways: as a
99 99 "source" changeset or as a "base" changeset. Both are shorthand
100 100 for a topologically related set of changesets (the "source
101 101 branch"). If you specify source (``-s/--source``), rebase will
102 102 rebase that changeset and all of its descendants onto dest. If you
103 103 specify base (``-b/--base``), rebase will select ancestors of base
104 104 back to but not including the common ancestor with dest. Thus,
105 105 ``-b`` is less precise but more convenient than ``-s``: you can
106 106 specify any changeset in the source branch, and rebase will select
107 107 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
108 108 uses the parent of the working directory as the base.
109 109
110 110 For advanced usage, a third way is available through the ``--rev``
111 111 option. It allows you to specify an arbitrary set of changesets to
112 112 rebase. Descendants of revs you specify with this option are not
113 113 automatically included in the rebase.
114 114
115 115 By default, rebase recreates the changesets in the source branch
116 116 as descendants of dest and then destroys the originals. Use
117 117 ``--keep`` to preserve the original source changesets. Some
118 118 changesets in the source branch (e.g. merges from the destination
119 119 branch) may be dropped if they no longer contribute any change.
120 120
121 121 One result of the rules for selecting the destination changeset
122 122 and source branch is that, unlike ``merge``, rebase will do
123 123 nothing if you are at the branch tip of a named branch
124 124 with two heads. You need to explicitly specify source and/or
125 125 destination (or ``update`` to the other head, if it's the head of
126 126 the intended source branch).
127 127
128 128 If a rebase is interrupted to manually resolve a merge, it can be
129 129 continued with --continue/-c or aborted with --abort/-a.
130 130
131 131 Returns 0 on success, 1 if nothing to rebase or there are
132 132 unresolved conflicts.
133 133 """
134 134 originalwd = target = None
135 135 activebookmark = None
136 136 external = nullrev
137 137 state = {}
138 138 skipped = set()
139 139 targetancestors = set()
140 140
141 141 editor = None
142 142 if opts.get('edit'):
143 143 editor = cmdutil.commitforceeditor
144 144
145 145 lock = wlock = None
146 146 try:
147 147 wlock = repo.wlock()
148 148 lock = repo.lock()
149 149
150 150 # Validate input and define rebasing points
151 151 destf = opts.get('dest', None)
152 152 srcf = opts.get('source', None)
153 153 basef = opts.get('base', None)
154 154 revf = opts.get('rev', [])
155 155 contf = opts.get('continue')
156 156 abortf = opts.get('abort')
157 157 collapsef = opts.get('collapse', False)
158 158 collapsemsg = cmdutil.logmessage(ui, opts)
159 159 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
160 160 extrafns = [_savegraft]
161 161 if e:
162 162 extrafns = [e]
163 163 keepf = opts.get('keep', False)
164 164 keepbranchesf = opts.get('keepbranches', False)
165 165 # keepopen is not meant for use on the command line, but by
166 166 # other extensions
167 167 keepopen = opts.get('keepopen', False)
168 168
169 169 if collapsemsg and not collapsef:
170 170 raise util.Abort(
171 171 _('message can only be specified with collapse'))
172 172
173 173 if contf or abortf:
174 174 if contf and abortf:
175 175 raise util.Abort(_('cannot use both abort and continue'))
176 176 if collapsef:
177 177 raise util.Abort(
178 178 _('cannot use collapse with continue or abort'))
179 179 if srcf or basef or destf:
180 180 raise util.Abort(
181 181 _('abort and continue do not allow specifying revisions'))
182 182 if opts.get('tool', False):
183 183 ui.warn(_('tool option will be ignored\n'))
184 184
185 185 try:
186 186 (originalwd, target, state, skipped, collapsef, keepf,
187 187 keepbranchesf, external, activebookmark) = restorestatus(repo)
188 188 except error.RepoLookupError:
189 189 if abortf:
190 190 clearstatus(repo)
191 191 repo.ui.warn(_('rebase aborted (no revision is removed,'
192 192 ' only broken state is cleared)\n'))
193 193 return 0
194 194 else:
195 195 msg = _('cannot continue inconsistent rebase')
196 196 hint = _('use "hg rebase --abort" to clear borken state')
197 197 raise util.Abort(msg, hint=hint)
198 198 if abortf:
199 199 return abort(repo, originalwd, target, state)
200 200 else:
201 201 if srcf and basef:
202 202 raise util.Abort(_('cannot specify both a '
203 203 'source and a base'))
204 204 if revf and basef:
205 205 raise util.Abort(_('cannot specify both a '
206 206 'revision and a base'))
207 207 if revf and srcf:
208 208 raise util.Abort(_('cannot specify both a '
209 209 'revision and a source'))
210 210
211 211 cmdutil.checkunfinished(repo)
212 212 cmdutil.bailifchanged(repo)
213 213
214 214 if not destf:
215 215 # Destination defaults to the latest revision in the
216 216 # current branch
217 217 branch = repo[None].branch()
218 218 dest = repo[branch]
219 219 else:
220 220 dest = scmutil.revsingle(repo, destf)
221 221
222 222 if revf:
223 223 rebaseset = scmutil.revrange(repo, revf)
224 224 if not rebaseset:
225 225 raise util.Abort(_('empty "rev" revision set - '
226 226 'nothing to rebase'))
227 227 elif srcf:
228 228 src = scmutil.revrange(repo, [srcf])
229 229 if not src:
230 230 raise util.Abort(_('empty "source" revision set - '
231 231 'nothing to rebase'))
232 232 rebaseset = repo.revs('(%ld)::', src)
233 233 assert rebaseset
234 234 else:
235 235 base = scmutil.revrange(repo, [basef or '.'])
236 if not base:
237 raise util.Abort(_('empty "base" revision set - '
238 "can't compute rebase set"))
236 239 rebaseset = repo.revs(
237 240 '(children(ancestor(%ld, %d)) and ::(%ld))::',
238 241 base, dest, base)
242 if not rebaseset:
243 if base == [dest.rev()]:
244 if basef:
245 ui.status(_('nothing to rebase - %s is both "base"'
246 ' and destination\n') % dest)
247 else:
248 ui.status(_('nothing to rebase - working directory '
249 'parent is also destination\n'))
250 elif not repo.revs('%ld - ::%d', base, dest):
251 if basef:
252 ui.status(_('nothing to rebase - "base" %s is '
253 'already an ancestor of destination '
254 '%s\n') %
255 ('+'.join(str(repo[r]) for r in base),
256 dest))
257 else:
258 ui.status(_('nothing to rebase - working '
259 'directory parent is already an '
260 'ancestor of destination %s\n') % dest)
261 else: # can it happen?
262 ui.status(_('nothing to rebase from %s to %s\n') %
263 ('+'.join(str(repo[r]) for r in base), dest))
264 return 1
239 265 if rebaseset:
240 266 root = min(rebaseset)
241 267 else:
242 268 root = None
243 269
244 270 if not rebaseset:
245 271 repo.ui.debug('base is ancestor of destination\n')
246 272 result = None
247 273 elif (not (keepf or obsolete._enabled)
248 274 and repo.revs('first(children(%ld) - %ld)',
249 275 rebaseset, rebaseset)):
250 276 raise util.Abort(
251 277 _("can't remove original changesets with"
252 278 " unrebased descendants"),
253 279 hint=_('use --keep to keep original changesets'))
254 280 else:
255 281 result = buildstate(repo, dest, rebaseset, collapsef)
256 282
257 283 if not result:
258 284 # Empty state built, nothing to rebase
259 285 ui.status(_('nothing to rebase\n'))
260 286 return 1
261 287 elif not keepf and not repo[root].mutable():
262 288 raise util.Abort(_("can't rebase immutable changeset %s")
263 289 % repo[root],
264 290 hint=_('see hg help phases for details'))
265 291 else:
266 292 originalwd, target, state = result
267 293 if collapsef:
268 294 targetancestors = repo.changelog.ancestors([target],
269 295 inclusive=True)
270 296 external = externalparent(repo, state, targetancestors)
271 297
272 298 if keepbranchesf:
273 299 # insert _savebranch at the start of extrafns so if
274 300 # there's a user-provided extrafn it can clobber branch if
275 301 # desired
276 302 extrafns.insert(0, _savebranch)
277 303 if collapsef:
278 304 branches = set()
279 305 for rev in state:
280 306 branches.add(repo[rev].branch())
281 307 if len(branches) > 1:
282 308 raise util.Abort(_('cannot collapse multiple named '
283 309 'branches'))
284 310
285 311
286 312 # Rebase
287 313 if not targetancestors:
288 314 targetancestors = repo.changelog.ancestors([target], inclusive=True)
289 315
290 316 # Keep track of the current bookmarks in order to reset them later
291 317 currentbookmarks = repo._bookmarks.copy()
292 318 activebookmark = activebookmark or repo._bookmarkcurrent
293 319 if activebookmark:
294 320 bookmarks.unsetcurrent(repo)
295 321
296 322 extrafn = _makeextrafn(extrafns)
297 323
298 324 sortedstate = sorted(state)
299 325 total = len(sortedstate)
300 326 pos = 0
301 327 for rev in sortedstate:
302 328 pos += 1
303 329 if state[rev] == -1:
304 330 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])),
305 331 _('changesets'), total)
306 332 p1, p2 = defineparents(repo, rev, target, state,
307 333 targetancestors)
308 334 storestatus(repo, originalwd, target, state, collapsef, keepf,
309 335 keepbranchesf, external, activebookmark)
310 336 if len(repo.parents()) == 2:
311 337 repo.ui.debug('resuming interrupted rebase\n')
312 338 else:
313 339 try:
314 340 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
315 341 stats = rebasenode(repo, rev, p1, state, collapsef)
316 342 if stats and stats[3] > 0:
317 343 raise error.InterventionRequired(
318 344 _('unresolved conflicts (see hg '
319 345 'resolve, then hg rebase --continue)'))
320 346 finally:
321 347 ui.setconfig('ui', 'forcemerge', '')
322 348 cmdutil.duplicatecopies(repo, rev, target)
323 349 if not collapsef:
324 350 newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn,
325 351 editor=editor)
326 352 else:
327 353 # Skip commit if we are collapsing
328 354 repo.setparents(repo[p1].node())
329 355 newrev = None
330 356 # Update the state
331 357 if newrev is not None:
332 358 state[rev] = repo[newrev].rev()
333 359 else:
334 360 if not collapsef:
335 361 ui.note(_('no changes, revision %d skipped\n') % rev)
336 362 ui.debug('next revision set to %s\n' % p1)
337 363 skipped.add(rev)
338 364 state[rev] = p1
339 365
340 366 ui.progress(_('rebasing'), None)
341 367 ui.note(_('rebase merging completed\n'))
342 368
343 369 if collapsef and not keepopen:
344 370 p1, p2 = defineparents(repo, min(state), target,
345 371 state, targetancestors)
346 372 if collapsemsg:
347 373 commitmsg = collapsemsg
348 374 else:
349 375 commitmsg = 'Collapsed revision'
350 376 for rebased in state:
351 377 if rebased not in skipped and state[rebased] > nullmerge:
352 378 commitmsg += '\n* %s' % repo[rebased].description()
353 379 commitmsg = ui.edit(commitmsg, repo.ui.username())
354 380 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
355 381 extrafn=extrafn, editor=editor)
356 382 for oldrev in state.iterkeys():
357 383 if state[oldrev] > nullmerge:
358 384 state[oldrev] = newrev
359 385
360 386 if 'qtip' in repo.tags():
361 387 updatemq(repo, state, skipped, **opts)
362 388
363 389 if currentbookmarks:
364 390 # Nodeids are needed to reset bookmarks
365 391 nstate = {}
366 392 for k, v in state.iteritems():
367 393 if v > nullmerge:
368 394 nstate[repo[k].node()] = repo[v].node()
369 395 # XXX this is the same as dest.node() for the non-continue path --
370 396 # this should probably be cleaned up
371 397 targetnode = repo[target].node()
372 398
373 399 # restore original working directory
374 400 # (we do this before stripping)
375 401 newwd = state.get(originalwd, originalwd)
376 402 if newwd not in [c.rev() for c in repo[None].parents()]:
377 403 ui.note(_("update back to initial working directory parent\n"))
378 404 hg.updaterepo(repo, newwd, False)
379 405
380 406 if not keepf:
381 407 collapsedas = None
382 408 if collapsef:
383 409 collapsedas = newrev
384 410 clearrebased(ui, repo, state, skipped, collapsedas)
385 411
386 412 if currentbookmarks:
387 413 updatebookmarks(repo, targetnode, nstate, currentbookmarks)
388 414
389 415 clearstatus(repo)
390 416 ui.note(_("rebase completed\n"))
391 417 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
392 418 if skipped:
393 419 ui.note(_("%d revisions have been skipped\n") % len(skipped))
394 420
395 421 if (activebookmark and
396 422 repo['.'].node() == repo._bookmarks[activebookmark]):
397 423 bookmarks.setcurrent(repo, activebookmark)
398 424
399 425 finally:
400 426 release(lock, wlock)
401 427
402 428 def externalparent(repo, state, targetancestors):
403 429 """Return the revision that should be used as the second parent
404 430 when the revisions in state is collapsed on top of targetancestors.
405 431 Abort if there is more than one parent.
406 432 """
407 433 parents = set()
408 434 source = min(state)
409 435 for rev in state:
410 436 if rev == source:
411 437 continue
412 438 for p in repo[rev].parents():
413 439 if (p.rev() not in state
414 440 and p.rev() not in targetancestors):
415 441 parents.add(p.rev())
416 442 if not parents:
417 443 return nullrev
418 444 if len(parents) == 1:
419 445 return parents.pop()
420 446 raise util.Abort(_('unable to collapse on top of %s, there is more '
421 447 'than one external parent: %s') %
422 448 (max(targetancestors),
423 449 ', '.join(str(p) for p in sorted(parents))))
424 450
425 451 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
426 452 'Commit the changes and store useful information in extra'
427 453 try:
428 454 repo.setparents(repo[p1].node(), repo[p2].node())
429 455 ctx = repo[rev]
430 456 if commitmsg is None:
431 457 commitmsg = ctx.description()
432 458 extra = {'rebase_source': ctx.hex()}
433 459 if extrafn:
434 460 extrafn(ctx, extra)
435 461 # Commit might fail if unresolved files exist
436 462 newrev = repo.commit(text=commitmsg, user=ctx.user(),
437 463 date=ctx.date(), extra=extra, editor=editor)
438 464 repo.dirstate.setbranch(repo[newrev].branch())
439 465 targetphase = max(ctx.phase(), phases.draft)
440 466 # retractboundary doesn't overwrite upper phase inherited from parent
441 467 newnode = repo[newrev].node()
442 468 if newnode:
443 469 phases.retractboundary(repo, targetphase, [newnode])
444 470 return newrev
445 471 except util.Abort:
446 472 # Invalidate the previous setparents
447 473 repo.dirstate.invalidate()
448 474 raise
449 475
450 476 def rebasenode(repo, rev, p1, state, collapse):
451 477 'Rebase a single revision'
452 478 # Merge phase
453 479 # Update to target and merge it with local
454 480 if repo['.'].rev() != repo[p1].rev():
455 481 repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
456 482 merge.update(repo, p1, False, True, False)
457 483 else:
458 484 repo.ui.debug(" already in target\n")
459 485 repo.dirstate.write()
460 486 repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
461 487 if repo[rev].rev() == repo[min(state)].rev():
462 488 # Case (1) initial changeset of a non-detaching rebase.
463 489 # Let the merge mechanism find the base itself.
464 490 base = None
465 491 elif not repo[rev].p2():
466 492 # Case (2) detaching the node with a single parent, use this parent
467 493 base = repo[rev].p1().node()
468 494 else:
469 495 # In case of merge, we need to pick the right parent as merge base.
470 496 #
471 497 # Imagine we have:
472 498 # - M: currently rebase revision in this step
473 499 # - A: one parent of M
474 500 # - B: second parent of M
475 501 # - D: destination of this merge step (p1 var)
476 502 #
477 503 # If we are rebasing on D, D is the successors of A or B. The right
478 504 # merge base is the one D succeed to. We pretend it is B for the rest
479 505 # of this comment
480 506 #
481 507 # If we pick B as the base, the merge involves:
482 508 # - changes from B to M (actual changeset payload)
483 509 # - changes from B to D (induced by rebase) as D is a rebased
484 510 # version of B)
485 511 # Which exactly represent the rebase operation.
486 512 #
487 513 # If we pick the A as the base, the merge involves
488 514 # - changes from A to M (actual changeset payload)
489 515 # - changes from A to D (with include changes between unrelated A and B
490 516 # plus changes induced by rebase)
491 517 # Which does not represent anything sensible and creates a lot of
492 518 # conflicts.
493 519 for p in repo[rev].parents():
494 520 if state.get(p.rev()) == repo[p1].rev():
495 521 base = p.node()
496 522 break
497 523 if base is not None:
498 524 repo.ui.debug(" detach base %d:%s\n" % (repo[base].rev(), repo[base]))
499 525 # When collapsing in-place, the parent is the common ancestor, we
500 526 # have to allow merging with it.
501 527 return merge.update(repo, rev, True, True, False, base, collapse)
502 528
503 529 def nearestrebased(repo, rev, state):
504 530 """return the nearest ancestors of rev in the rebase result"""
505 531 rebased = [r for r in state if state[r] > nullmerge]
506 532 candidates = repo.revs('max(%ld and (::%d))', rebased, rev)
507 533 if candidates:
508 534 return state[candidates[0]]
509 535 else:
510 536 return None
511 537
512 538 def defineparents(repo, rev, target, state, targetancestors):
513 539 'Return the new parent relationship of the revision that will be rebased'
514 540 parents = repo[rev].parents()
515 541 p1 = p2 = nullrev
516 542
517 543 P1n = parents[0].rev()
518 544 if P1n in targetancestors:
519 545 p1 = target
520 546 elif P1n in state:
521 547 if state[P1n] == nullmerge:
522 548 p1 = target
523 549 elif state[P1n] == revignored:
524 550 p1 = nearestrebased(repo, P1n, state)
525 551 if p1 is None:
526 552 p1 = target
527 553 else:
528 554 p1 = state[P1n]
529 555 else: # P1n external
530 556 p1 = target
531 557 p2 = P1n
532 558
533 559 if len(parents) == 2 and parents[1].rev() not in targetancestors:
534 560 P2n = parents[1].rev()
535 561 # interesting second parent
536 562 if P2n in state:
537 563 if p1 == target: # P1n in targetancestors or external
538 564 p1 = state[P2n]
539 565 elif state[P2n] == revignored:
540 566 p2 = nearestrebased(repo, P2n, state)
541 567 if p2 is None:
542 568 # no ancestors rebased yet, detach
543 569 p2 = target
544 570 else:
545 571 p2 = state[P2n]
546 572 else: # P2n external
547 573 if p2 != nullrev: # P1n external too => rev is a merged revision
548 574 raise util.Abort(_('cannot use revision %d as base, result '
549 575 'would have 3 parents') % rev)
550 576 p2 = P2n
551 577 repo.ui.debug(" future parents are %d and %d\n" %
552 578 (repo[p1].rev(), repo[p2].rev()))
553 579 return p1, p2
554 580
555 581 def isagitpatch(repo, patchname):
556 582 'Return true if the given patch is in git format'
557 583 mqpatch = os.path.join(repo.mq.path, patchname)
558 584 for line in patch.linereader(file(mqpatch, 'rb')):
559 585 if line.startswith('diff --git'):
560 586 return True
561 587 return False
562 588
563 589 def updatemq(repo, state, skipped, **opts):
564 590 'Update rebased mq patches - finalize and then import them'
565 591 mqrebase = {}
566 592 mq = repo.mq
567 593 original_series = mq.fullseries[:]
568 594 skippedpatches = set()
569 595
570 596 for p in mq.applied:
571 597 rev = repo[p.node].rev()
572 598 if rev in state:
573 599 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
574 600 (rev, p.name))
575 601 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
576 602 else:
577 603 # Applied but not rebased, not sure this should happen
578 604 skippedpatches.add(p.name)
579 605
580 606 if mqrebase:
581 607 mq.finish(repo, mqrebase.keys())
582 608
583 609 # We must start import from the newest revision
584 610 for rev in sorted(mqrebase, reverse=True):
585 611 if rev not in skipped:
586 612 name, isgit = mqrebase[rev]
587 613 repo.ui.debug('import mq patch %d (%s)\n' % (state[rev], name))
588 614 mq.qimport(repo, (), patchname=name, git=isgit,
589 615 rev=[str(state[rev])])
590 616 else:
591 617 # Rebased and skipped
592 618 skippedpatches.add(mqrebase[rev][0])
593 619
594 620 # Patches were either applied and rebased and imported in
595 621 # order, applied and removed or unapplied. Discard the removed
596 622 # ones while preserving the original series order and guards.
597 623 newseries = [s for s in original_series
598 624 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
599 625 mq.fullseries[:] = newseries
600 626 mq.seriesdirty = True
601 627 mq.savedirty()
602 628
603 629 def updatebookmarks(repo, targetnode, nstate, originalbookmarks):
604 630 'Move bookmarks to their correct changesets, and delete divergent ones'
605 631 marks = repo._bookmarks
606 632 for k, v in originalbookmarks.iteritems():
607 633 if v in nstate:
608 634 # update the bookmarks for revs that have moved
609 635 marks[k] = nstate[v]
610 636 bookmarks.deletedivergent(repo, [targetnode], k)
611 637
612 638 marks.write()
613 639
614 640 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
615 641 external, activebookmark):
616 642 'Store the current status to allow recovery'
617 643 f = repo.opener("rebasestate", "w")
618 644 f.write(repo[originalwd].hex() + '\n')
619 645 f.write(repo[target].hex() + '\n')
620 646 f.write(repo[external].hex() + '\n')
621 647 f.write('%d\n' % int(collapse))
622 648 f.write('%d\n' % int(keep))
623 649 f.write('%d\n' % int(keepbranches))
624 650 f.write('%s\n' % (activebookmark or ''))
625 651 for d, v in state.iteritems():
626 652 oldrev = repo[d].hex()
627 653 if v > nullmerge:
628 654 newrev = repo[v].hex()
629 655 else:
630 656 newrev = v
631 657 f.write("%s:%s\n" % (oldrev, newrev))
632 658 f.close()
633 659 repo.ui.debug('rebase status stored\n')
634 660
635 661 def clearstatus(repo):
636 662 'Remove the status files'
637 663 util.unlinkpath(repo.join("rebasestate"), ignoremissing=True)
638 664
639 665 def restorestatus(repo):
640 666 'Restore a previously stored status'
641 667 try:
642 668 target = None
643 669 collapse = False
644 670 external = nullrev
645 671 activebookmark = None
646 672 state = {}
647 673 f = repo.opener("rebasestate")
648 674 for i, l in enumerate(f.read().splitlines()):
649 675 if i == 0:
650 676 originalwd = repo[l].rev()
651 677 elif i == 1:
652 678 target = repo[l].rev()
653 679 elif i == 2:
654 680 external = repo[l].rev()
655 681 elif i == 3:
656 682 collapse = bool(int(l))
657 683 elif i == 4:
658 684 keep = bool(int(l))
659 685 elif i == 5:
660 686 keepbranches = bool(int(l))
661 687 elif i == 6 and not (len(l) == 81 and ':' in l):
662 688 # line 6 is a recent addition, so for backwards compatibility
663 689 # check that the line doesn't look like the oldrev:newrev lines
664 690 activebookmark = l
665 691 else:
666 692 oldrev, newrev = l.split(':')
667 693 if newrev in (str(nullmerge), str(revignored)):
668 694 state[repo[oldrev].rev()] = int(newrev)
669 695 else:
670 696 state[repo[oldrev].rev()] = repo[newrev].rev()
671 697 skipped = set()
672 698 # recompute the set of skipped revs
673 699 if not collapse:
674 700 seen = set([target])
675 701 for old, new in sorted(state.items()):
676 702 if new != nullrev and new in seen:
677 703 skipped.add(old)
678 704 seen.add(new)
679 705 repo.ui.debug('computed skipped revs: %s\n' % skipped)
680 706 repo.ui.debug('rebase status resumed\n')
681 707 return (originalwd, target, state, skipped,
682 708 collapse, keep, keepbranches, external, activebookmark)
683 709 except IOError, err:
684 710 if err.errno != errno.ENOENT:
685 711 raise
686 712 raise util.Abort(_('no rebase in progress'))
687 713
688 714 def inrebase(repo, originalwd, state):
689 715 '''check whether the working dir is in an interrupted rebase'''
690 716 parents = [p.rev() for p in repo.parents()]
691 717 if originalwd in parents:
692 718 return True
693 719
694 720 for newrev in state.itervalues():
695 721 if newrev in parents:
696 722 return True
697 723
698 724 return False
699 725
700 726 def abort(repo, originalwd, target, state):
701 727 'Restore the repository to its original state'
702 728 dstates = [s for s in state.values() if s > nullrev]
703 729 immutable = [d for d in dstates if not repo[d].mutable()]
704 730 cleanup = True
705 731 if immutable:
706 732 repo.ui.warn(_("warning: can't clean up immutable changesets %s\n")
707 733 % ', '.join(str(repo[r]) for r in immutable),
708 734 hint=_('see hg help phases for details'))
709 735 cleanup = False
710 736
711 737 descendants = set()
712 738 if dstates:
713 739 descendants = set(repo.changelog.descendants(dstates))
714 740 if descendants - set(dstates):
715 741 repo.ui.warn(_("warning: new changesets detected on target branch, "
716 742 "can't strip\n"))
717 743 cleanup = False
718 744
719 745 if cleanup:
720 746 # Update away from the rebase if necessary
721 747 if inrebase(repo, originalwd, state):
722 748 merge.update(repo, repo[originalwd].rev(), False, True, False)
723 749
724 750 # Strip from the first rebased revision
725 751 rebased = filter(lambda x: x > -1 and x != target, state.values())
726 752 if rebased:
727 753 strippoints = [c.node() for c in repo.set('roots(%ld)', rebased)]
728 754 # no backup of rebased cset versions needed
729 755 repair.strip(repo.ui, repo, strippoints)
730 756
731 757 clearstatus(repo)
732 758 repo.ui.warn(_('rebase aborted\n'))
733 759 return 0
734 760
735 761 def buildstate(repo, dest, rebaseset, collapse):
736 762 '''Define which revisions are going to be rebased and where
737 763
738 764 repo: repo
739 765 dest: context
740 766 rebaseset: set of rev
741 767 '''
742 768
743 769 # This check isn't strictly necessary, since mq detects commits over an
744 770 # applied patch. But it prevents messing up the working directory when
745 771 # a partially completed rebase is blocked by mq.
746 772 if 'qtip' in repo.tags() and (dest.node() in
747 773 [s.node for s in repo.mq.applied]):
748 774 raise util.Abort(_('cannot rebase onto an applied mq patch'))
749 775
750 776 roots = list(repo.set('roots(%ld)', rebaseset))
751 777 if not roots:
752 778 raise util.Abort(_('no matching revisions'))
753 779 roots.sort()
754 780 state = {}
755 781 detachset = set()
756 782 for root in roots:
757 783 commonbase = root.ancestor(dest)
758 784 if commonbase == root:
759 785 raise util.Abort(_('source is ancestor of destination'))
760 786 if commonbase == dest:
761 787 samebranch = root.branch() == dest.branch()
762 788 if not collapse and samebranch and root in dest.children():
763 789 repo.ui.debug('source is a child of destination\n')
764 790 return None
765 791
766 792 repo.ui.debug('rebase onto %d starting from %s\n' % (dest, roots))
767 793 state.update(dict.fromkeys(rebaseset, nullrev))
768 794 # Rebase tries to turn <dest> into a parent of <root> while
769 795 # preserving the number of parents of rebased changesets:
770 796 #
771 797 # - A changeset with a single parent will always be rebased as a
772 798 # changeset with a single parent.
773 799 #
774 800 # - A merge will be rebased as merge unless its parents are both
775 801 # ancestors of <dest> or are themselves in the rebased set and
776 802 # pruned while rebased.
777 803 #
778 804 # If one parent of <root> is an ancestor of <dest>, the rebased
779 805 # version of this parent will be <dest>. This is always true with
780 806 # --base option.
781 807 #
782 808 # Otherwise, we need to *replace* the original parents with
783 809 # <dest>. This "detaches" the rebased set from its former location
784 810 # and rebases it onto <dest>. Changes introduced by ancestors of
785 811 # <root> not common with <dest> (the detachset, marked as
786 812 # nullmerge) are "removed" from the rebased changesets.
787 813 #
788 814 # - If <root> has a single parent, set it to <dest>.
789 815 #
790 816 # - If <root> is a merge, we cannot decide which parent to
791 817 # replace, the rebase operation is not clearly defined.
792 818 #
793 819 # The table below sums up this behavior:
794 820 #
795 821 # +------------------+----------------------+-------------------------+
796 822 # | | one parent | merge |
797 823 # +------------------+----------------------+-------------------------+
798 824 # | parent in | new parent is <dest> | parents in ::<dest> are |
799 825 # | ::<dest> | | remapped to <dest> |
800 826 # +------------------+----------------------+-------------------------+
801 827 # | unrelated source | new parent is <dest> | ambiguous, abort |
802 828 # +------------------+----------------------+-------------------------+
803 829 #
804 830 # The actual abort is handled by `defineparents`
805 831 if len(root.parents()) <= 1:
806 832 # ancestors of <root> not ancestors of <dest>
807 833 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
808 834 [root.rev()]))
809 835 for r in detachset:
810 836 if r not in state:
811 837 state[r] = nullmerge
812 838 if len(roots) > 1:
813 839 # If we have multiple roots, we may have "hole" in the rebase set.
814 840 # Rebase roots that descend from those "hole" should not be detached as
815 841 # other root are. We use the special `revignored` to inform rebase that
816 842 # the revision should be ignored but that `defineparents` should search
817 843 # a rebase destination that make sense regarding rebased topology.
818 844 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
819 845 for ignored in set(rebasedomain) - set(rebaseset):
820 846 state[ignored] = revignored
821 847 return repo['.'].rev(), dest.rev(), state
822 848
823 849 def clearrebased(ui, repo, state, skipped, collapsedas=None):
824 850 """dispose of rebased revision at the end of the rebase
825 851
826 852 If `collapsedas` is not None, the rebase was a collapse whose result if the
827 853 `collapsedas` node."""
828 854 if obsolete._enabled:
829 855 markers = []
830 856 for rev, newrev in sorted(state.items()):
831 857 if newrev >= 0:
832 858 if rev in skipped:
833 859 succs = ()
834 860 elif collapsedas is not None:
835 861 succs = (repo[collapsedas],)
836 862 else:
837 863 succs = (repo[newrev],)
838 864 markers.append((repo[rev], succs))
839 865 if markers:
840 866 obsolete.createmarkers(repo, markers)
841 867 else:
842 868 rebased = [rev for rev in state if state[rev] > nullmerge]
843 869 if rebased:
844 870 stripped = []
845 871 for root in repo.set('roots(%ld)', rebased):
846 872 if set(repo.changelog.descendants([root.rev()])) - set(state):
847 873 ui.warn(_("warning: new changesets detected "
848 874 "on source branch, not stripping\n"))
849 875 else:
850 876 stripped.append(root.node())
851 877 if stripped:
852 878 # backup the old csets by default
853 879 repair.strip(ui, repo, stripped, "all")
854 880
855 881
856 882 def pullrebase(orig, ui, repo, *args, **opts):
857 883 'Call rebase after pull if the latter has been invoked with --rebase'
858 884 if opts.get('rebase'):
859 885 if opts.get('update'):
860 886 del opts['update']
861 887 ui.debug('--update and --rebase are not compatible, ignoring '
862 888 'the update flag\n')
863 889
864 890 movemarkfrom = repo['.'].node()
865 891 revsprepull = len(repo)
866 892 origpostincoming = commands.postincoming
867 893 def _dummy(*args, **kwargs):
868 894 pass
869 895 commands.postincoming = _dummy
870 896 try:
871 897 orig(ui, repo, *args, **opts)
872 898 finally:
873 899 commands.postincoming = origpostincoming
874 900 revspostpull = len(repo)
875 901 if revspostpull > revsprepull:
876 902 # --rev option from pull conflict with rebase own --rev
877 903 # dropping it
878 904 if 'rev' in opts:
879 905 del opts['rev']
880 906 rebase(ui, repo, **opts)
881 907 branch = repo[None].branch()
882 908 dest = repo[branch].rev()
883 909 if dest != repo['.'].rev():
884 910 # there was nothing to rebase we force an update
885 911 hg.update(repo, dest)
886 912 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
887 913 ui.status(_("updating bookmark %s\n")
888 914 % repo._bookmarkcurrent)
889 915 else:
890 916 if opts.get('tool'):
891 917 raise util.Abort(_('--tool can only be used with --rebase'))
892 918 orig(ui, repo, *args, **opts)
893 919
894 920 def summaryhook(ui, repo):
895 921 if not os.path.exists(repo.join('rebasestate')):
896 922 return
897 923 try:
898 924 state = restorestatus(repo)[2]
899 925 except error.RepoLookupError:
900 926 # i18n: column positioning for "hg summary"
901 927 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
902 928 ui.write(msg)
903 929 return
904 930 numrebased = len([i for i in state.itervalues() if i != -1])
905 931 # i18n: column positioning for "hg summary"
906 932 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
907 933 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
908 934 ui.label(_('%d remaining'), 'rebase.remaining') %
909 935 (len(state) - numrebased)))
910 936
911 937 def uisetup(ui):
912 938 'Replace pull with a decorator to provide --rebase option'
913 939 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
914 940 entry[1].append(('', 'rebase', None,
915 941 _("rebase working directory to branch head")))
916 942 entry[1].append(('t', 'tool', '',
917 943 _("specify merge tool for rebase")))
918 944 cmdutil.summaryhooks.add('rebase', summaryhook)
919 945 cmdutil.unfinishedstates.append(
920 946 ['rebasestate', False, False, _('rebase in progress'),
921 947 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
@@ -1,2287 +1,2287 b''
1 1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 2 $ mkdir "${USERCACHE}"
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles=
6 6 > purge=
7 7 > rebase=
8 8 > transplant=
9 9 > [phases]
10 10 > publish=False
11 11 > [largefiles]
12 12 > minsize=2
13 13 > patterns=glob:**.dat
14 14 > usercache=${USERCACHE}
15 15 > [hooks]
16 16 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
17 17 > EOF
18 18
19 19 Create the repo with a couple of revisions of both large and normal
20 20 files.
21 21 Test status and dirstate of largefiles and that summary output is correct.
22 22
23 23 $ hg init a
24 24 $ cd a
25 25 $ mkdir sub
26 26 $ echo normal1 > normal1
27 27 $ echo normal2 > sub/normal2
28 28 $ echo large1 > large1
29 29 $ echo large2 > sub/large2
30 30 $ hg add normal1 sub/normal2
31 31 $ hg add --large large1 sub/large2
32 32 $ hg commit -m "add files"
33 33 Invoking status precommit hook
34 34 A large1
35 35 A normal1
36 36 A sub/large2
37 37 A sub/normal2
38 38 $ touch large1 sub/large2
39 39 $ sleep 1
40 40 $ hg st
41 41 $ hg debugstate --nodates
42 42 n 644 41 .hglf/large1
43 43 n 644 41 .hglf/sub/large2
44 44 n 644 8 normal1
45 45 n 644 8 sub/normal2
46 46 $ hg debugstate --large
47 47 n 644 7 large1
48 48 n 644 7 sub/large2
49 49 $ echo normal11 > normal1
50 50 $ echo normal22 > sub/normal2
51 51 $ echo large11 > large1
52 52 $ echo large22 > sub/large2
53 53 $ hg commit -m "edit files"
54 54 Invoking status precommit hook
55 55 M large1
56 56 M normal1
57 57 M sub/large2
58 58 M sub/normal2
59 59 $ hg sum --large
60 60 parent: 1:ce8896473775 tip
61 61 edit files
62 62 branch: default
63 63 commit: (clean)
64 64 update: (current)
65 65 largefiles: (no remote repo)
66 66
67 67 Commit preserved largefile contents.
68 68
69 69 $ cat normal1
70 70 normal11
71 71 $ cat large1
72 72 large11
73 73 $ cat sub/normal2
74 74 normal22
75 75 $ cat sub/large2
76 76 large22
77 77
78 78 Test status, subdir and unknown files
79 79
80 80 $ echo unknown > sub/unknown
81 81 $ hg st --all
82 82 ? sub/unknown
83 83 C large1
84 84 C normal1
85 85 C sub/large2
86 86 C sub/normal2
87 87 $ hg st --all sub
88 88 ? sub/unknown
89 89 C sub/large2
90 90 C sub/normal2
91 91 $ rm sub/unknown
92 92
93 93 Test messages and exit codes for remove warning cases
94 94
95 95 $ hg remove -A large1
96 96 not removing large1: file still exists
97 97 [1]
98 98 $ echo 'modified' > large1
99 99 $ hg remove large1
100 100 not removing large1: file is modified (use -f to force removal)
101 101 [1]
102 102 $ echo 'new' > normalnew
103 103 $ hg add normalnew
104 104 $ echo 'new' > largenew
105 105 $ hg add --large normalnew
106 106 normalnew already tracked!
107 107 $ hg remove normalnew largenew
108 108 not removing largenew: file is untracked
109 109 not removing normalnew: file has been marked for add (use forget to undo)
110 110 [1]
111 111 $ rm normalnew largenew
112 112 $ hg up -Cq
113 113
114 114 Remove both largefiles and normal files.
115 115
116 116 $ hg remove normal1 large1
117 117 $ hg status large1
118 118 R large1
119 119 $ hg commit -m "remove files"
120 120 Invoking status precommit hook
121 121 R large1
122 122 R normal1
123 123 $ ls
124 124 sub
125 125 $ echo "testlargefile" > large1-test
126 126 $ hg add --large large1-test
127 127 $ hg st
128 128 A large1-test
129 129 $ hg rm large1-test
130 130 not removing large1-test: file has been marked for add (use forget to undo)
131 131 [1]
132 132 $ hg st
133 133 A large1-test
134 134 $ hg forget large1-test
135 135 $ hg st
136 136 ? large1-test
137 137 $ hg remove large1-test
138 138 not removing large1-test: file is untracked
139 139 [1]
140 140 $ hg forget large1-test
141 141 not removing large1-test: file is already untracked
142 142 [1]
143 143 $ rm large1-test
144 144
145 145 Copy both largefiles and normal files (testing that status output is correct).
146 146
147 147 $ hg cp sub/normal2 normal1
148 148 $ hg cp sub/large2 large1
149 149 $ hg commit -m "copy files"
150 150 Invoking status precommit hook
151 151 A large1
152 152 A normal1
153 153 $ cat normal1
154 154 normal22
155 155 $ cat large1
156 156 large22
157 157
158 158 Test moving largefiles and verify that normal files are also unaffected.
159 159
160 160 $ hg mv normal1 normal3
161 161 $ hg mv large1 large3
162 162 $ hg mv sub/normal2 sub/normal4
163 163 $ hg mv sub/large2 sub/large4
164 164 $ hg commit -m "move files"
165 165 Invoking status precommit hook
166 166 A large3
167 167 A normal3
168 168 A sub/large4
169 169 A sub/normal4
170 170 R large1
171 171 R normal1
172 172 R sub/large2
173 173 R sub/normal2
174 174 $ cat normal3
175 175 normal22
176 176 $ cat large3
177 177 large22
178 178 $ cat sub/normal4
179 179 normal22
180 180 $ cat sub/large4
181 181 large22
182 182
183 183 Test copies and moves from a directory other than root (issue3516)
184 184
185 185 $ cd ..
186 186 $ hg init lf_cpmv
187 187 $ cd lf_cpmv
188 188 $ mkdir dira
189 189 $ mkdir dira/dirb
190 190 $ touch dira/dirb/largefile
191 191 $ hg add --large dira/dirb/largefile
192 192 $ hg commit -m "added"
193 193 Invoking status precommit hook
194 194 A dira/dirb/largefile
195 195 $ cd dira
196 196 $ hg cp dirb/largefile foo/largefile
197 197 $ hg ci -m "deep copy"
198 198 Invoking status precommit hook
199 199 A dira/foo/largefile
200 200 $ find . | sort
201 201 .
202 202 ./dirb
203 203 ./dirb/largefile
204 204 ./foo
205 205 ./foo/largefile
206 206 $ hg mv foo/largefile baz/largefile
207 207 $ hg ci -m "moved"
208 208 Invoking status precommit hook
209 209 A dira/baz/largefile
210 210 R dira/foo/largefile
211 211 $ find . | sort
212 212 .
213 213 ./baz
214 214 ./baz/largefile
215 215 ./dirb
216 216 ./dirb/largefile
217 217 ./foo
218 218 $ cd ../../a
219 219
220 220 #if serve
221 221 Test display of largefiles in hgweb
222 222
223 223 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
224 224 $ cat ../hg.pid >> $DAEMON_PIDS
225 225 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
226 226 200 Script output follows
227 227
228 228
229 229 drwxr-xr-x sub
230 230 -rw-r--r-- 41 large3
231 231 -rw-r--r-- 9 normal3
232 232
233 233
234 234 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
235 235 200 Script output follows
236 236
237 237
238 238 -rw-r--r-- 41 large4
239 239 -rw-r--r-- 9 normal4
240 240
241 241
242 242 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
243 243 #endif
244 244
245 245 Test archiving the various revisions. These hit corner cases known with
246 246 archiving.
247 247
248 248 $ hg archive -r 0 ../archive0
249 249 $ hg archive -r 1 ../archive1
250 250 $ hg archive -r 2 ../archive2
251 251 $ hg archive -r 3 ../archive3
252 252 $ hg archive -r 4 ../archive4
253 253 $ cd ../archive0
254 254 $ cat normal1
255 255 normal1
256 256 $ cat large1
257 257 large1
258 258 $ cat sub/normal2
259 259 normal2
260 260 $ cat sub/large2
261 261 large2
262 262 $ cd ../archive1
263 263 $ cat normal1
264 264 normal11
265 265 $ cat large1
266 266 large11
267 267 $ cat sub/normal2
268 268 normal22
269 269 $ cat sub/large2
270 270 large22
271 271 $ cd ../archive2
272 272 $ ls
273 273 sub
274 274 $ cat sub/normal2
275 275 normal22
276 276 $ cat sub/large2
277 277 large22
278 278 $ cd ../archive3
279 279 $ cat normal1
280 280 normal22
281 281 $ cat large1
282 282 large22
283 283 $ cat sub/normal2
284 284 normal22
285 285 $ cat sub/large2
286 286 large22
287 287 $ cd ../archive4
288 288 $ cat normal3
289 289 normal22
290 290 $ cat large3
291 291 large22
292 292 $ cat sub/normal4
293 293 normal22
294 294 $ cat sub/large4
295 295 large22
296 296
297 297 Commit corner case: specify files to commit.
298 298
299 299 $ cd ../a
300 300 $ echo normal3 > normal3
301 301 $ echo large3 > large3
302 302 $ echo normal4 > sub/normal4
303 303 $ echo large4 > sub/large4
304 304 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
305 305 Invoking status precommit hook
306 306 M large3
307 307 M normal3
308 308 M sub/large4
309 309 M sub/normal4
310 310 $ cat normal3
311 311 normal3
312 312 $ cat large3
313 313 large3
314 314 $ cat sub/normal4
315 315 normal4
316 316 $ cat sub/large4
317 317 large4
318 318
319 319 One more commit corner case: commit from a subdirectory.
320 320
321 321 $ cd ../a
322 322 $ echo normal33 > normal3
323 323 $ echo large33 > large3
324 324 $ echo normal44 > sub/normal4
325 325 $ echo large44 > sub/large4
326 326 $ cd sub
327 327 $ hg commit -m "edit files yet again"
328 328 Invoking status precommit hook
329 329 M large3
330 330 M normal3
331 331 M sub/large4
332 332 M sub/normal4
333 333 $ cat ../normal3
334 334 normal33
335 335 $ cat ../large3
336 336 large33
337 337 $ cat normal4
338 338 normal44
339 339 $ cat large4
340 340 large44
341 341
342 342 Committing standins is not allowed.
343 343
344 344 $ cd ..
345 345 $ echo large3 > large3
346 346 $ hg commit .hglf/large3 -m "try to commit standin"
347 347 abort: file ".hglf/large3" is a largefile standin
348 348 (commit the largefile itself instead)
349 349 [255]
350 350
351 351 Corner cases for adding largefiles.
352 352
353 353 $ echo large5 > large5
354 354 $ hg add --large large5
355 355 $ hg add --large large5
356 356 large5 already a largefile
357 357 $ mkdir sub2
358 358 $ echo large6 > sub2/large6
359 359 $ echo large7 > sub2/large7
360 360 $ hg add --large sub2
361 361 adding sub2/large6 as a largefile (glob)
362 362 adding sub2/large7 as a largefile (glob)
363 363 $ hg st
364 364 M large3
365 365 A large5
366 366 A sub2/large6
367 367 A sub2/large7
368 368
369 369 Committing directories containing only largefiles.
370 370
371 371 $ mkdir -p z/y/x/m
372 372 $ touch z/y/x/m/large1
373 373 $ touch z/y/x/large2
374 374 $ hg add --large z/y/x/m/large1 z/y/x/large2
375 375 $ hg commit -m "Subdir with directory only containing largefiles" z
376 376 Invoking status precommit hook
377 377 M large3
378 378 A large5
379 379 A sub2/large6
380 380 A sub2/large7
381 381 A z/y/x/large2
382 382 A z/y/x/m/large1
383 383 $ hg rollback --quiet
384 384 $ touch z/y/x/m/normal
385 385 $ hg add z/y/x/m/normal
386 386 $ hg commit -m "Subdir with mixed contents" z
387 387 Invoking status precommit hook
388 388 M large3
389 389 A large5
390 390 A sub2/large6
391 391 A sub2/large7
392 392 A z/y/x/large2
393 393 A z/y/x/m/large1
394 394 A z/y/x/m/normal
395 395 $ hg st
396 396 M large3
397 397 A large5
398 398 A sub2/large6
399 399 A sub2/large7
400 400 $ hg rollback --quiet
401 401 $ hg revert z/y/x/large2 z/y/x/m/large1
402 402 $ rm z/y/x/large2 z/y/x/m/large1
403 403 $ hg commit -m "Subdir with normal contents" z
404 404 Invoking status precommit hook
405 405 M large3
406 406 A large5
407 407 A sub2/large6
408 408 A sub2/large7
409 409 A z/y/x/m/normal
410 410 $ hg st
411 411 M large3
412 412 A large5
413 413 A sub2/large6
414 414 A sub2/large7
415 415 $ hg rollback --quiet
416 416 $ hg revert --quiet z
417 417 $ hg commit -m "Empty subdir" z
418 418 abort: z: no match under directory!
419 419 [255]
420 420 $ rm -rf z
421 421 $ hg ci -m "standin" .hglf
422 422 abort: file ".hglf" is a largefile standin
423 423 (commit the largefile itself instead)
424 424 [255]
425 425
426 426 Test "hg status" with combination of 'file pattern' and 'directory
427 427 pattern' for largefiles:
428 428
429 429 $ hg status sub2/large6 sub2
430 430 A sub2/large6
431 431 A sub2/large7
432 432
433 433 Config settings (pattern **.dat, minsize 2 MB) are respected.
434 434
435 435 $ echo testdata > test.dat
436 436 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
437 437 $ hg add
438 438 adding reallylarge as a largefile
439 439 adding test.dat as a largefile
440 440
441 441 Test that minsize and --lfsize handle float values;
442 442 also tests that --lfsize overrides largefiles.minsize.
443 443 (0.250 MB = 256 kB = 262144 B)
444 444
445 445 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
446 446 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
447 447 $ hg --config largefiles.minsize=.25 add
448 448 adding ratherlarge as a largefile
449 449 adding medium
450 450 $ hg forget medium
451 451 $ hg --config largefiles.minsize=.25 add --lfsize=.125
452 452 adding medium as a largefile
453 453 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
454 454 $ hg --config largefiles.minsize=.25 add --lfsize=.125
455 455 adding notlarge
456 456 $ hg forget notlarge
457 457
458 458 Test forget on largefiles.
459 459
460 460 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
461 461 $ hg commit -m "add/edit more largefiles"
462 462 Invoking status precommit hook
463 463 A sub2/large6
464 464 A sub2/large7
465 465 R large3
466 466 ? large5
467 467 ? medium
468 468 ? notlarge
469 469 ? ratherlarge
470 470 ? reallylarge
471 471 ? test.dat
472 472 $ hg st
473 473 ? large3
474 474 ? large5
475 475 ? medium
476 476 ? notlarge
477 477 ? ratherlarge
478 478 ? reallylarge
479 479 ? test.dat
480 480
481 481 Purge with largefiles: verify that largefiles are still in the working
482 482 dir after a purge.
483 483
484 484 $ hg purge --all
485 485 $ cat sub/large4
486 486 large44
487 487 $ cat sub2/large6
488 488 large6
489 489 $ cat sub2/large7
490 490 large7
491 491
492 492 Test addremove: verify that files that should be added as largfiles are added as
493 493 such and that already-existing largfiles are not added as normal files by
494 494 accident.
495 495
496 496 $ rm normal3
497 497 $ rm sub/large4
498 498 $ echo "testing addremove with patterns" > testaddremove.dat
499 499 $ echo "normaladdremove" > normaladdremove
500 500 $ hg addremove
501 501 removing sub/large4
502 502 adding testaddremove.dat as a largefile
503 503 removing normal3
504 504 adding normaladdremove
505 505
506 506 Test addremove with -R
507 507
508 508 $ hg up -C
509 509 getting changed largefiles
510 510 1 largefiles updated, 0 removed
511 511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 512 $ rm normal3
513 513 $ rm sub/large4
514 514 $ echo "testing addremove with patterns" > testaddremove.dat
515 515 $ echo "normaladdremove" > normaladdremove
516 516 $ cd ..
517 517 $ hg -R a addremove
518 518 removing sub/large4
519 519 adding a/testaddremove.dat as a largefile (glob)
520 520 removing normal3
521 521 adding normaladdremove
522 522 $ cd a
523 523
524 524 Test 3364
525 525 $ hg clone . ../addrm
526 526 updating to branch default
527 527 getting changed largefiles
528 528 3 largefiles updated, 0 removed
529 529 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 530 $ cd ../addrm
531 531 $ cat >> .hg/hgrc <<EOF
532 532 > [hooks]
533 533 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
534 534 > EOF
535 535 $ touch foo
536 536 $ hg add --large foo
537 537 $ hg ci -m "add foo"
538 538 Invoking status precommit hook
539 539 A foo
540 540 Invoking status postcommit hook
541 541 C foo
542 542 C normal3
543 543 C sub/large4
544 544 C sub/normal4
545 545 C sub2/large6
546 546 C sub2/large7
547 547 $ rm foo
548 548 $ hg st
549 549 ! foo
550 550 hmm.. no precommit invoked, but there is a postcommit??
551 551 $ hg ci -m "will not checkin"
552 552 nothing changed
553 553 Invoking status postcommit hook
554 554 ! foo
555 555 C normal3
556 556 C sub/large4
557 557 C sub/normal4
558 558 C sub2/large6
559 559 C sub2/large7
560 560 [1]
561 561 $ hg addremove
562 562 removing foo
563 563 $ hg st
564 564 R foo
565 565 $ hg ci -m "used to say nothing changed"
566 566 Invoking status precommit hook
567 567 R foo
568 568 Invoking status postcommit hook
569 569 C normal3
570 570 C sub/large4
571 571 C sub/normal4
572 572 C sub2/large6
573 573 C sub2/large7
574 574 $ hg st
575 575
576 576 Test 3507 (both normal files and largefiles were a problem)
577 577
578 578 $ touch normal
579 579 $ touch large
580 580 $ hg add normal
581 581 $ hg add --large large
582 582 $ hg ci -m "added"
583 583 Invoking status precommit hook
584 584 A large
585 585 A normal
586 586 Invoking status postcommit hook
587 587 C large
588 588 C normal
589 589 C normal3
590 590 C sub/large4
591 591 C sub/normal4
592 592 C sub2/large6
593 593 C sub2/large7
594 594 $ hg remove normal
595 595 $ hg addremove --traceback
596 596 $ hg ci -m "addremoved normal"
597 597 Invoking status precommit hook
598 598 R normal
599 599 Invoking status postcommit hook
600 600 C large
601 601 C normal3
602 602 C sub/large4
603 603 C sub/normal4
604 604 C sub2/large6
605 605 C sub2/large7
606 606 $ hg up -C '.^'
607 607 getting changed largefiles
608 608 0 largefiles updated, 0 removed
609 609 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 610 $ hg remove large
611 611 $ hg addremove --traceback
612 612 $ hg ci -m "removed large"
613 613 Invoking status precommit hook
614 614 R large
615 615 created new head
616 616 Invoking status postcommit hook
617 617 C normal
618 618 C normal3
619 619 C sub/large4
620 620 C sub/normal4
621 621 C sub2/large6
622 622 C sub2/large7
623 623
624 624 Test commit -A (issue 3542)
625 625 $ echo large8 > large8
626 626 $ hg add --large large8
627 627 $ hg ci -Am 'this used to add large8 as normal and commit both'
628 628 Invoking status precommit hook
629 629 A large8
630 630 Invoking status postcommit hook
631 631 C large8
632 632 C normal
633 633 C normal3
634 634 C sub/large4
635 635 C sub/normal4
636 636 C sub2/large6
637 637 C sub2/large7
638 638 $ rm large8
639 639 $ hg ci -Am 'this used to not notice the rm'
640 640 removing large8
641 641 Invoking status precommit hook
642 642 R large8
643 643 Invoking status postcommit hook
644 644 C normal
645 645 C normal3
646 646 C sub/large4
647 647 C sub/normal4
648 648 C sub2/large6
649 649 C sub2/large7
650 650
651 651 Test that a standin can't be added as a large file
652 652
653 653 $ touch large
654 654 $ hg add --large large
655 655 $ hg ci -m "add"
656 656 Invoking status precommit hook
657 657 A large
658 658 Invoking status postcommit hook
659 659 C large
660 660 C normal
661 661 C normal3
662 662 C sub/large4
663 663 C sub/normal4
664 664 C sub2/large6
665 665 C sub2/large7
666 666 $ hg remove large
667 667 $ touch large
668 668 $ hg addremove --config largefiles.patterns=**large --traceback
669 669 adding large as a largefile
670 670
671 671 Test that outgoing --large works (with revsets too)
672 672 $ hg outgoing --rev '.^' --large
673 673 comparing with $TESTTMP/a (glob)
674 674 searching for changes
675 675 changeset: 8:c02fd3b77ec4
676 676 user: test
677 677 date: Thu Jan 01 00:00:00 1970 +0000
678 678 summary: add foo
679 679
680 680 changeset: 9:289dd08c9bbb
681 681 user: test
682 682 date: Thu Jan 01 00:00:00 1970 +0000
683 683 summary: used to say nothing changed
684 684
685 685 changeset: 10:34f23ac6ac12
686 686 user: test
687 687 date: Thu Jan 01 00:00:00 1970 +0000
688 688 summary: added
689 689
690 690 changeset: 12:710c1b2f523c
691 691 parent: 10:34f23ac6ac12
692 692 user: test
693 693 date: Thu Jan 01 00:00:00 1970 +0000
694 694 summary: removed large
695 695
696 696 changeset: 13:0a3e75774479
697 697 user: test
698 698 date: Thu Jan 01 00:00:00 1970 +0000
699 699 summary: this used to add large8 as normal and commit both
700 700
701 701 changeset: 14:84f3d378175c
702 702 user: test
703 703 date: Thu Jan 01 00:00:00 1970 +0000
704 704 summary: this used to not notice the rm
705 705
706 706 searching for changes
707 707 largefiles to upload:
708 708 foo
709 709 large
710 710 large8
711 711
712 712 $ cd ../a
713 713
714 714 Clone a largefiles repo.
715 715
716 716 $ hg clone . ../b
717 717 updating to branch default
718 718 getting changed largefiles
719 719 3 largefiles updated, 0 removed
720 720 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 721 $ cd ../b
722 722 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
723 723 7:daea875e9014 add/edit more largefiles
724 724 6:4355d653f84f edit files yet again
725 725 5:9d5af5072dbd edit files again
726 726 4:74c02385b94c move files
727 727 3:9e8fbc4bce62 copy files
728 728 2:51a0ae4d5864 remove files
729 729 1:ce8896473775 edit files
730 730 0:30d30fe6a5be add files
731 731 $ cat normal3
732 732 normal33
733 733 $ cat sub/normal4
734 734 normal44
735 735 $ cat sub/large4
736 736 large44
737 737 $ cat sub2/large6
738 738 large6
739 739 $ cat sub2/large7
740 740 large7
741 741 $ hg log -qf sub2/large7
742 742 7:daea875e9014
743 743 $ cd ..
744 744 $ hg clone a -r 3 c
745 745 adding changesets
746 746 adding manifests
747 747 adding file changes
748 748 added 4 changesets with 10 changes to 4 files
749 749 updating to branch default
750 750 getting changed largefiles
751 751 2 largefiles updated, 0 removed
752 752 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
753 753 $ cd c
754 754 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
755 755 3:9e8fbc4bce62 copy files
756 756 2:51a0ae4d5864 remove files
757 757 1:ce8896473775 edit files
758 758 0:30d30fe6a5be add files
759 759 $ cat normal1
760 760 normal22
761 761 $ cat large1
762 762 large22
763 763 $ cat sub/normal2
764 764 normal22
765 765 $ cat sub/large2
766 766 large22
767 767
768 768 Old revisions of a clone have correct largefiles content (this also
769 769 tests update).
770 770
771 771 $ hg update -r 1
772 772 getting changed largefiles
773 773 1 largefiles updated, 0 removed
774 774 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
775 775 $ cat large1
776 776 large11
777 777 $ cat sub/large2
778 778 large22
779 779 $ cd ..
780 780
781 781 Test cloning with --all-largefiles flag
782 782
783 783 $ rm "${USERCACHE}"/*
784 784 $ hg clone --all-largefiles a a-backup
785 785 updating to branch default
786 786 getting changed largefiles
787 787 3 largefiles updated, 0 removed
788 788 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
789 789 8 additional largefiles cached
790 790
791 791 $ rm "${USERCACHE}"/*
792 792 $ hg clone --all-largefiles -u 0 a a-clone0
793 793 updating to branch default
794 794 getting changed largefiles
795 795 2 largefiles updated, 0 removed
796 796 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
797 797 9 additional largefiles cached
798 798 $ hg -R a-clone0 sum
799 799 parent: 0:30d30fe6a5be
800 800 add files
801 801 branch: default
802 802 commit: (clean)
803 803 update: 7 new changesets (update)
804 804
805 805 $ rm "${USERCACHE}"/*
806 806 $ hg clone --all-largefiles -u 1 a a-clone1
807 807 updating to branch default
808 808 getting changed largefiles
809 809 2 largefiles updated, 0 removed
810 810 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
811 811 8 additional largefiles cached
812 812 $ hg -R a-clone1 verify --large --lfa --lfc
813 813 checking changesets
814 814 checking manifests
815 815 crosschecking files in changesets and manifests
816 816 checking files
817 817 10 files, 8 changesets, 24 total revisions
818 818 searching 8 changesets for largefiles
819 819 verified contents of 13 revisions of 6 largefiles
820 820 $ hg -R a-clone1 sum
821 821 parent: 1:ce8896473775
822 822 edit files
823 823 branch: default
824 824 commit: (clean)
825 825 update: 6 new changesets (update)
826 826
827 827 $ rm "${USERCACHE}"/*
828 828 $ hg clone --all-largefiles -U a a-clone-u
829 829 11 additional largefiles cached
830 830 $ hg -R a-clone-u sum
831 831 parent: -1:000000000000 (no revision checked out)
832 832 branch: default
833 833 commit: (clean)
834 834 update: 8 new changesets (update)
835 835
836 836 Show computed destination directory:
837 837
838 838 $ mkdir xyz
839 839 $ cd xyz
840 840 $ hg clone ../a
841 841 destination directory: a
842 842 updating to branch default
843 843 getting changed largefiles
844 844 3 largefiles updated, 0 removed
845 845 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
846 846 $ cd ..
847 847
848 848 Clone URL without path:
849 849
850 850 $ hg clone file://
851 851 abort: repository / not found!
852 852 [255]
853 853
854 854 Ensure base clone command argument validation
855 855
856 856 $ hg clone -U -u 0 a a-clone-failure
857 857 abort: cannot specify both --noupdate and --updaterev
858 858 [255]
859 859
860 860 $ hg clone --all-largefiles a ssh://localhost/a
861 861 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
862 862 [255]
863 863
864 864 Test pulling with --all-largefiles flag. Also test that the largefiles are
865 865 downloaded from 'default' instead of 'default-push' when no source is specified
866 866 (issue3584)
867 867
868 868 $ rm -Rf a-backup
869 869 $ hg clone -r 1 a a-backup
870 870 adding changesets
871 871 adding manifests
872 872 adding file changes
873 873 added 2 changesets with 8 changes to 4 files
874 874 updating to branch default
875 875 getting changed largefiles
876 876 2 largefiles updated, 0 removed
877 877 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
878 878 $ rm "${USERCACHE}"/*
879 879 $ cd a-backup
880 880 $ hg pull --all-largefiles --config paths.default-push=bogus/path
881 881 pulling from $TESTTMP/a (glob)
882 882 searching for changes
883 883 adding changesets
884 884 adding manifests
885 885 adding file changes
886 886 added 6 changesets with 16 changes to 8 files
887 887 (run 'hg update' to get a working copy)
888 888 6 largefiles cached
889 889
890 890 redo pull with --lfrev and check it pulls largefiles for the right revs
891 891
892 892 $ hg rollback
893 893 repository tip rolled back to revision 1 (undo pull)
894 894 $ hg pull -v --lfrev 'heads(pulled())+min(pulled())'
895 895 pulling from $TESTTMP/a (glob)
896 896 searching for changes
897 897 all local heads known remotely
898 898 6 changesets found
899 899 adding changesets
900 900 adding manifests
901 901 adding file changes
902 902 added 6 changesets with 16 changes to 8 files
903 903 calling hook changegroup.lfiles: <function checkrequireslfiles at *> (glob)
904 904 (run 'hg update' to get a working copy)
905 905 pulling largefiles for revision 7
906 906 found 971fb41e78fea4f8e0ba5244784239371cb00591 in store
907 907 found 0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30 in store
908 908 found bb3151689acb10f0c3125c560d5e63df914bc1af in store
909 909 pulling largefiles for revision 2
910 910 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
911 911 0 largefiles cached
912 912
913 913 lfpull
914 914
915 915 $ hg lfpull -r : --config largefiles.usercache=usercache-lfpull
916 916 2 largefiles cached
917 917 $ hg lfpull -v -r 4+2 --config largefiles.usercache=usercache-lfpull
918 918 pulling largefiles for revision 4
919 919 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
920 920 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
921 921 pulling largefiles for revision 2
922 922 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
923 923 0 largefiles cached
924 924
925 925 $ ls usercache-lfpull/* | sort
926 926 usercache-lfpull/1deebade43c8c498a3c8daddac0244dc55d1331d
927 927 usercache-lfpull/4669e532d5b2c093a78eca010077e708a071bb64
928 928
929 929 $ cd ..
930 930
931 931 Rebasing between two repositories does not revert largefiles to old
932 932 revisions (this was a very bad bug that took a lot of work to fix).
933 933
934 934 $ hg clone a d
935 935 updating to branch default
936 936 getting changed largefiles
937 937 3 largefiles updated, 0 removed
938 938 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
939 939 $ cd b
940 940 $ echo large4-modified > sub/large4
941 941 $ echo normal3-modified > normal3
942 942 $ hg commit -m "modify normal file and largefile in repo b"
943 943 Invoking status precommit hook
944 944 M normal3
945 945 M sub/large4
946 946 $ cd ../d
947 947 $ echo large6-modified > sub2/large6
948 948 $ echo normal4-modified > sub/normal4
949 949 $ hg commit -m "modify normal file largefile in repo d"
950 950 Invoking status precommit hook
951 951 M sub/normal4
952 952 M sub2/large6
953 953 $ cd ..
954 954 $ hg clone d e
955 955 updating to branch default
956 956 getting changed largefiles
957 957 3 largefiles updated, 0 removed
958 958 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
959 959 $ cd d
960 960
961 961 More rebase testing, but also test that the largefiles are downloaded from
962 962 'default-push' when no source is specified (issue3584). (The largefile from the
963 963 pulled revision is however not downloaded but found in the local cache.)
964 964 Largefiles are fetched for the new pulled revision, not for existing revisions,
965 965 rebased or not.
966 966
967 967 $ [ ! -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
968 968 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
969 969 pulling from $TESTTMP/b (glob)
970 970 searching for changes
971 971 adding changesets
972 972 adding manifests
973 973 adding file changes
974 974 added 1 changesets with 2 changes to 2 files (+1 heads)
975 975 Invoking status precommit hook
976 976 M sub/normal4
977 977 M sub2/large6
978 978 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
979 979 0 largefiles cached
980 nothing to rebase
980 nothing to rebase - working directory parent is also destination
981 981 $ [ -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
982 982 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
983 983 9:598410d3eb9a modify normal file largefile in repo d
984 984 8:a381d2c8c80e modify normal file and largefile in repo b
985 985 7:daea875e9014 add/edit more largefiles
986 986 6:4355d653f84f edit files yet again
987 987 5:9d5af5072dbd edit files again
988 988 4:74c02385b94c move files
989 989 3:9e8fbc4bce62 copy files
990 990 2:51a0ae4d5864 remove files
991 991 1:ce8896473775 edit files
992 992 0:30d30fe6a5be add files
993 993 $ cat normal3
994 994 normal3-modified
995 995 $ cat sub/normal4
996 996 normal4-modified
997 997 $ cat sub/large4
998 998 large4-modified
999 999 $ cat sub2/large6
1000 1000 large6-modified
1001 1001 $ cat sub2/large7
1002 1002 large7
1003 1003 $ cd ../e
1004 1004 $ hg pull ../b
1005 1005 pulling from ../b
1006 1006 searching for changes
1007 1007 adding changesets
1008 1008 adding manifests
1009 1009 adding file changes
1010 1010 added 1 changesets with 2 changes to 2 files (+1 heads)
1011 1011 (run 'hg heads' to see heads, 'hg merge' to merge)
1012 1012 $ hg rebase
1013 1013 Invoking status precommit hook
1014 1014 M sub/normal4
1015 1015 M sub2/large6
1016 1016 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
1017 1017 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1018 1018 9:598410d3eb9a modify normal file largefile in repo d
1019 1019 8:a381d2c8c80e modify normal file and largefile in repo b
1020 1020 7:daea875e9014 add/edit more largefiles
1021 1021 6:4355d653f84f edit files yet again
1022 1022 5:9d5af5072dbd edit files again
1023 1023 4:74c02385b94c move files
1024 1024 3:9e8fbc4bce62 copy files
1025 1025 2:51a0ae4d5864 remove files
1026 1026 1:ce8896473775 edit files
1027 1027 0:30d30fe6a5be add files
1028 1028 $ cat normal3
1029 1029 normal3-modified
1030 1030 $ cat sub/normal4
1031 1031 normal4-modified
1032 1032 $ cat sub/large4
1033 1033 large4-modified
1034 1034 $ cat sub2/large6
1035 1035 large6-modified
1036 1036 $ cat sub2/large7
1037 1037 large7
1038 1038
1039 1039 Log on largefiles
1040 1040
1041 1041 - same output
1042 1042 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1043 1043 8:a381d2c8c80e modify normal file and largefile in repo b
1044 1044 6:4355d653f84f edit files yet again
1045 1045 5:9d5af5072dbd edit files again
1046 1046 4:74c02385b94c move files
1047 1047 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
1048 1048 8:a381d2c8c80e modify normal file and largefile in repo b
1049 1049 6:4355d653f84f edit files yet again
1050 1050 5:9d5af5072dbd edit files again
1051 1051 4:74c02385b94c move files
1052 1052
1053 1053 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1054 1054 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1055 1055 8:a381d2c8c80e modify normal file and largefile in repo b
1056 1056 6:4355d653f84f edit files yet again
1057 1057 5:9d5af5072dbd edit files again
1058 1058 4:74c02385b94c move files
1059 1059 1:ce8896473775 edit files
1060 1060 0:30d30fe6a5be add files
1061 1061 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1062 1062 9:598410d3eb9a modify normal file largefile in repo d
1063 1063 8:a381d2c8c80e modify normal file and largefile in repo b
1064 1064 6:4355d653f84f edit files yet again
1065 1065 5:9d5af5072dbd edit files again
1066 1066 4:74c02385b94c move files
1067 1067 1:ce8896473775 edit files
1068 1068 0:30d30fe6a5be add files
1069 1069
1070 1070 - globbing gives same result
1071 1071 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1072 1072 9:598410d3eb9a modify normal file largefile in repo d
1073 1073 8:a381d2c8c80e modify normal file and largefile in repo b
1074 1074 6:4355d653f84f edit files yet again
1075 1075 5:9d5af5072dbd edit files again
1076 1076 4:74c02385b94c move files
1077 1077 1:ce8896473775 edit files
1078 1078 0:30d30fe6a5be add files
1079 1079
1080 1080 Rollback on largefiles.
1081 1081
1082 1082 $ echo large4-modified-again > sub/large4
1083 1083 $ hg commit -m "Modify large4 again"
1084 1084 Invoking status precommit hook
1085 1085 M sub/large4
1086 1086 $ hg rollback
1087 1087 repository tip rolled back to revision 9 (undo commit)
1088 1088 working directory now based on revision 9
1089 1089 $ hg st
1090 1090 M sub/large4
1091 1091 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1092 1092 9:598410d3eb9a modify normal file largefile in repo d
1093 1093 8:a381d2c8c80e modify normal file and largefile in repo b
1094 1094 7:daea875e9014 add/edit more largefiles
1095 1095 6:4355d653f84f edit files yet again
1096 1096 5:9d5af5072dbd edit files again
1097 1097 4:74c02385b94c move files
1098 1098 3:9e8fbc4bce62 copy files
1099 1099 2:51a0ae4d5864 remove files
1100 1100 1:ce8896473775 edit files
1101 1101 0:30d30fe6a5be add files
1102 1102 $ cat sub/large4
1103 1103 large4-modified-again
1104 1104
1105 1105 "update --check" refuses to update with uncommitted changes.
1106 1106 $ hg update --check 8
1107 1107 abort: uncommitted changes
1108 1108 [255]
1109 1109
1110 1110 "update --clean" leaves correct largefiles in working copy, even when there is
1111 1111 .orig files from revert in .hglf.
1112 1112
1113 1113 $ echo mistake > sub2/large7
1114 1114 $ hg revert sub2/large7
1115 1115 $ hg -q update --clean -r null
1116 1116 $ hg update --clean
1117 1117 getting changed largefiles
1118 1118 3 largefiles updated, 0 removed
1119 1119 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1120 1120 $ cat normal3
1121 1121 normal3-modified
1122 1122 $ cat sub/normal4
1123 1123 normal4-modified
1124 1124 $ cat sub/large4
1125 1125 large4-modified
1126 1126 $ cat sub2/large6
1127 1127 large6-modified
1128 1128 $ cat sub2/large7
1129 1129 large7
1130 1130 $ cat sub2/large7.orig
1131 1131 mistake
1132 1132 $ cat .hglf/sub2/large7.orig
1133 1133 9dbfb2c79b1c40981b258c3efa1b10b03f18ad31
1134 1134
1135 1135 demonstrate misfeature: .orig file is overwritten on every update -C,
1136 1136 also when clean:
1137 1137 $ hg update --clean
1138 1138 getting changed largefiles
1139 1139 0 largefiles updated, 0 removed
1140 1140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1141 1141 $ cat sub2/large7.orig
1142 1142 large7
1143 1143 $ rm sub2/large7.orig .hglf/sub2/large7.orig
1144 1144
1145 1145 Now "update check" is happy.
1146 1146 $ hg update --check 8
1147 1147 getting changed largefiles
1148 1148 1 largefiles updated, 0 removed
1149 1149 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1150 1150 $ hg update --check
1151 1151 getting changed largefiles
1152 1152 1 largefiles updated, 0 removed
1153 1153 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1154 1154
1155 1155 Test removing empty largefiles directories on update
1156 1156 $ test -d sub2 && echo "sub2 exists"
1157 1157 sub2 exists
1158 1158 $ hg update -q null
1159 1159 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1160 1160 [1]
1161 1161 $ hg update -q
1162 1162
1163 1163 Test hg remove removes empty largefiles directories
1164 1164 $ test -d sub2 && echo "sub2 exists"
1165 1165 sub2 exists
1166 1166 $ hg remove sub2/*
1167 1167 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1168 1168 [1]
1169 1169 $ hg revert sub2/large6 sub2/large7
1170 1170
1171 1171 "revert" works on largefiles (and normal files too).
1172 1172 $ echo hack3 >> normal3
1173 1173 $ echo hack4 >> sub/normal4
1174 1174 $ echo hack4 >> sub/large4
1175 1175 $ rm sub2/large6
1176 1176 $ hg revert sub2/large6
1177 1177 $ hg rm sub2/large6
1178 1178 $ echo new >> sub2/large8
1179 1179 $ hg add --large sub2/large8
1180 1180 # XXX we don't really want to report that we're reverting the standin;
1181 1181 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1182 1182 $ hg revert sub
1183 1183 reverting .hglf/sub/large4 (glob)
1184 1184 reverting sub/normal4 (glob)
1185 1185 $ hg status
1186 1186 M normal3
1187 1187 A sub2/large8
1188 1188 R sub2/large6
1189 1189 ? sub/large4.orig
1190 1190 ? sub/normal4.orig
1191 1191 $ cat sub/normal4
1192 1192 normal4-modified
1193 1193 $ cat sub/large4
1194 1194 large4-modified
1195 1195 $ hg revert -a --no-backup
1196 1196 undeleting .hglf/sub2/large6 (glob)
1197 1197 forgetting .hglf/sub2/large8 (glob)
1198 1198 reverting normal3
1199 1199 $ hg status
1200 1200 ? sub/large4.orig
1201 1201 ? sub/normal4.orig
1202 1202 ? sub2/large8
1203 1203 $ cat normal3
1204 1204 normal3-modified
1205 1205 $ cat sub2/large6
1206 1206 large6-modified
1207 1207 $ rm sub/*.orig sub2/large8
1208 1208
1209 1209 revert some files to an older revision
1210 1210 $ hg revert --no-backup -r 8 sub2
1211 1211 reverting .hglf/sub2/large6 (glob)
1212 1212 $ cat sub2/large6
1213 1213 large6
1214 1214 $ hg revert --no-backup -C -r '.^' sub2
1215 1215 reverting .hglf/sub2/large6 (glob)
1216 1216 $ hg revert --no-backup sub2
1217 1217 reverting .hglf/sub2/large6 (glob)
1218 1218 $ hg status
1219 1219
1220 1220 "verify --large" actually verifies largefiles
1221 1221
1222 1222 - Where Do We Come From? What Are We? Where Are We Going?
1223 1223 $ pwd
1224 1224 $TESTTMP/e
1225 1225 $ hg paths
1226 1226 default = $TESTTMP/d (glob)
1227 1227
1228 1228 $ hg verify --large
1229 1229 checking changesets
1230 1230 checking manifests
1231 1231 crosschecking files in changesets and manifests
1232 1232 checking files
1233 1233 10 files, 10 changesets, 28 total revisions
1234 1234 searching 1 changesets for largefiles
1235 1235 verified existence of 3 revisions of 3 largefiles
1236 1236
1237 1237 - introduce missing blob in local store repo and make sure that this is caught:
1238 1238 $ mv $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 .
1239 1239 $ hg verify --large
1240 1240 checking changesets
1241 1241 checking manifests
1242 1242 crosschecking files in changesets and manifests
1243 1243 checking files
1244 1244 10 files, 10 changesets, 28 total revisions
1245 1245 searching 1 changesets for largefiles
1246 1246 changeset 9:598410d3eb9a: sub/large4 references missing $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1247 1247 verified existence of 3 revisions of 3 largefiles
1248 1248 [1]
1249 1249
1250 1250 - introduce corruption and make sure that it is caught when checking content:
1251 1251 $ echo '5 cents' > $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1252 1252 $ hg verify -q --large --lfc
1253 1253 changeset 9:598410d3eb9a: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1254 1254 [1]
1255 1255
1256 1256 - cleanup
1257 1257 $ mv e166e74c7303192238d60af5a9c4ce9bef0b7928 $TESTTMP/d/.hg/largefiles/
1258 1258
1259 1259 - verifying all revisions will fail because we didn't clone all largefiles to d:
1260 1260 $ echo 'T-shirt' > $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1261 1261 $ hg verify -q --lfa --lfc
1262 1262 changeset 0:30d30fe6a5be: large1 references missing $TESTTMP/d/.hg/largefiles/4669e532d5b2c093a78eca010077e708a071bb64 (glob)
1263 1263 changeset 0:30d30fe6a5be: sub/large2 references missing $TESTTMP/d/.hg/largefiles/1deebade43c8c498a3c8daddac0244dc55d1331d (glob)
1264 1264 changeset 1:ce8896473775: large1 references missing $TESTTMP/d/.hg/largefiles/5f78770c0e77ba4287ad6ef3071c9bf9c379742f (glob)
1265 1265 changeset 1:ce8896473775: sub/large2 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1266 1266 changeset 3:9e8fbc4bce62: large1 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1267 1267 changeset 4:74c02385b94c: large3 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1268 1268 changeset 4:74c02385b94c: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1269 1269 changeset 5:9d5af5072dbd: large3 references missing $TESTTMP/d/.hg/largefiles/baaf12afde9d8d67f25dab6dced0d2bf77dba47c (glob)
1270 1270 changeset 5:9d5af5072dbd: sub/large4 references missing $TESTTMP/d/.hg/largefiles/aeb2210d19f02886dde00dac279729a48471e2f9 (glob)
1271 1271 changeset 6:4355d653f84f: large3 references missing $TESTTMP/d/.hg/largefiles/7838695e10da2bb75ac1156565f40a2595fa2fa0 (glob)
1272 1272 [1]
1273 1273
1274 1274 - cleanup
1275 1275 $ rm $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1276 1276 $ rm -f .hglf/sub/*.orig
1277 1277
1278 1278 Update to revision with missing largefile - and make sure it really is missing
1279 1279
1280 1280 $ rm ${USERCACHE}/7838695e10da2bb75ac1156565f40a2595fa2fa0
1281 1281 $ hg up -r 6
1282 1282 getting changed largefiles
1283 1283 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file://$TESTTMP/d (glob)
1284 1284 1 largefiles updated, 2 removed
1285 1285 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
1286 1286 $ rm normal3
1287 1287 $ echo >> sub/normal4
1288 1288 $ hg ci -m 'commit with missing files'
1289 1289 Invoking status precommit hook
1290 1290 M sub/normal4
1291 1291 ! large3
1292 1292 ! normal3
1293 1293 created new head
1294 1294 $ hg st
1295 1295 ! large3
1296 1296 ! normal3
1297 1297 $ hg up -r.
1298 1298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1299 1299 $ hg st
1300 1300 ! large3
1301 1301 ! normal3
1302 1302 $ hg up -Cr.
1303 1303 getting changed largefiles
1304 1304 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file://$TESTTMP/d (glob)
1305 1305 0 largefiles updated, 0 removed
1306 1306 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1307 1307 $ hg st
1308 1308 ! large3
1309 1309 $ hg rollback
1310 1310 repository tip rolled back to revision 9 (undo commit)
1311 1311 working directory now based on revision 6
1312 1312
1313 1313 Merge with revision with missing largefile - and make sure it tries to fetch it.
1314 1314
1315 1315 $ hg up -Cqr null
1316 1316 $ echo f > f
1317 1317 $ hg ci -Am branch
1318 1318 adding f
1319 1319 Invoking status precommit hook
1320 1320 A f
1321 1321 created new head
1322 1322 $ hg merge -r 6
1323 1323 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1324 1324 (branch merge, don't forget to commit)
1325 1325 getting changed largefiles
1326 1326 large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file://$TESTTMP/d (glob)
1327 1327 1 largefiles updated, 0 removed
1328 1328
1329 1329 $ hg rollback -q
1330 1330 $ hg up -Cq
1331 1331
1332 1332 Pulling 0 revisions with --all-largefiles should not fetch for all revisions
1333 1333
1334 1334 $ hg pull --all-largefiles
1335 1335 pulling from $TESTTMP/d (glob)
1336 1336 searching for changes
1337 1337 no changes found
1338 1338
1339 1339 Merging does not revert to old versions of largefiles and also check
1340 1340 that merging after having pulled from a non-default remote works
1341 1341 correctly.
1342 1342
1343 1343 $ cd ..
1344 1344 $ hg clone -r 7 e temp
1345 1345 adding changesets
1346 1346 adding manifests
1347 1347 adding file changes
1348 1348 added 8 changesets with 24 changes to 10 files
1349 1349 updating to branch default
1350 1350 getting changed largefiles
1351 1351 3 largefiles updated, 0 removed
1352 1352 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1353 1353 $ hg clone temp f
1354 1354 updating to branch default
1355 1355 getting changed largefiles
1356 1356 3 largefiles updated, 0 removed
1357 1357 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1358 1358 # Delete the largefiles in the largefiles system cache so that we have an
1359 1359 # opportunity to test that caching after a pull works.
1360 1360 $ rm "${USERCACHE}"/*
1361 1361 $ cd f
1362 1362 $ echo "large4-merge-test" > sub/large4
1363 1363 $ hg commit -m "Modify large4 to test merge"
1364 1364 Invoking status precommit hook
1365 1365 M sub/large4
1366 1366 # Test --cache-largefiles flag
1367 1367 $ hg pull --lfrev 'heads(pulled())' ../e
1368 1368 pulling from ../e
1369 1369 searching for changes
1370 1370 adding changesets
1371 1371 adding manifests
1372 1372 adding file changes
1373 1373 added 2 changesets with 4 changes to 4 files (+1 heads)
1374 1374 (run 'hg heads' to see heads, 'hg merge' to merge)
1375 1375 2 largefiles cached
1376 1376 $ hg merge
1377 1377 merging sub/large4
1378 1378 largefile sub/large4 has a merge conflict
1379 1379 keep (l)ocal or take (o)ther? l
1380 1380 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1381 1381 (branch merge, don't forget to commit)
1382 1382 getting changed largefiles
1383 1383 1 largefiles updated, 0 removed
1384 1384 $ hg commit -m "Merge repos e and f"
1385 1385 Invoking status precommit hook
1386 1386 M normal3
1387 1387 M sub/normal4
1388 1388 M sub2/large6
1389 1389 $ cat normal3
1390 1390 normal3-modified
1391 1391 $ cat sub/normal4
1392 1392 normal4-modified
1393 1393 $ cat sub/large4
1394 1394 large4-merge-test
1395 1395 $ cat sub2/large6
1396 1396 large6-modified
1397 1397 $ cat sub2/large7
1398 1398 large7
1399 1399
1400 1400 Test status after merging with a branch that introduces a new largefile:
1401 1401
1402 1402 $ echo large > large
1403 1403 $ hg add --large large
1404 1404 $ hg commit -m 'add largefile'
1405 1405 Invoking status precommit hook
1406 1406 A large
1407 1407 $ hg update -q ".^"
1408 1408 $ echo change >> normal3
1409 1409 $ hg commit -m 'some change'
1410 1410 Invoking status precommit hook
1411 1411 M normal3
1412 1412 created new head
1413 1413 $ hg merge
1414 1414 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1415 1415 (branch merge, don't forget to commit)
1416 1416 getting changed largefiles
1417 1417 1 largefiles updated, 0 removed
1418 1418 $ hg status
1419 1419 M large
1420 1420
1421 1421 - make sure update of merge with removed largefiles fails as expected
1422 1422 $ hg rm sub2/large6
1423 1423 $ hg up -r.
1424 1424 abort: outstanding uncommitted merges
1425 1425 [255]
1426 1426
1427 1427 - revert should be able to revert files introduced in a pending merge
1428 1428 $ hg revert --all -r .
1429 1429 removing .hglf/large (glob)
1430 1430 undeleting .hglf/sub2/large6 (glob)
1431 1431
1432 1432 Test that a normal file and a largefile with the same name and path cannot
1433 1433 coexist.
1434 1434
1435 1435 $ rm sub2/large7
1436 1436 $ echo "largeasnormal" > sub2/large7
1437 1437 $ hg add sub2/large7
1438 1438 sub2/large7 already a largefile
1439 1439
1440 1440 Test that transplanting a largefile change works correctly.
1441 1441
1442 1442 $ cd ..
1443 1443 $ hg clone -r 8 d g
1444 1444 adding changesets
1445 1445 adding manifests
1446 1446 adding file changes
1447 1447 added 9 changesets with 26 changes to 10 files
1448 1448 updating to branch default
1449 1449 getting changed largefiles
1450 1450 3 largefiles updated, 0 removed
1451 1451 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1452 1452 $ cd g
1453 1453 $ hg transplant -s ../d 598410d3eb9a
1454 1454 searching for changes
1455 1455 searching for changes
1456 1456 adding changesets
1457 1457 adding manifests
1458 1458 adding file changes
1459 1459 added 1 changesets with 2 changes to 2 files
1460 1460 getting changed largefiles
1461 1461 1 largefiles updated, 0 removed
1462 1462 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1463 1463 9:598410d3eb9a modify normal file largefile in repo d
1464 1464 8:a381d2c8c80e modify normal file and largefile in repo b
1465 1465 7:daea875e9014 add/edit more largefiles
1466 1466 6:4355d653f84f edit files yet again
1467 1467 5:9d5af5072dbd edit files again
1468 1468 4:74c02385b94c move files
1469 1469 3:9e8fbc4bce62 copy files
1470 1470 2:51a0ae4d5864 remove files
1471 1471 1:ce8896473775 edit files
1472 1472 0:30d30fe6a5be add files
1473 1473 $ cat normal3
1474 1474 normal3-modified
1475 1475 $ cat sub/normal4
1476 1476 normal4-modified
1477 1477 $ cat sub/large4
1478 1478 large4-modified
1479 1479 $ cat sub2/large6
1480 1480 large6-modified
1481 1481 $ cat sub2/large7
1482 1482 large7
1483 1483
1484 1484 Cat a largefile
1485 1485 $ hg cat normal3
1486 1486 normal3-modified
1487 1487 $ hg cat sub/large4
1488 1488 large4-modified
1489 1489 $ rm "${USERCACHE}"/*
1490 1490 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1491 1491 $ cat cat.out
1492 1492 large4-modified
1493 1493 $ rm cat.out
1494 1494 $ hg cat -r a381d2c8c80e normal3
1495 1495 normal3-modified
1496 1496 $ hg cat -r '.^' normal3
1497 1497 normal3-modified
1498 1498 $ hg cat -r '.^' sub/large4 doesntexist
1499 1499 large4-modified
1500 1500 doesntexist: no such file in rev a381d2c8c80e
1501 1501 $ hg --cwd sub cat -r '.^' large4
1502 1502 large4-modified
1503 1503 $ hg --cwd sub cat -r '.^' ../normal3
1504 1504 normal3-modified
1505 1505
1506 1506 Test that renaming a largefile results in correct output for status
1507 1507
1508 1508 $ hg rename sub/large4 large4-renamed
1509 1509 $ hg commit -m "test rename output"
1510 1510 Invoking status precommit hook
1511 1511 A large4-renamed
1512 1512 R sub/large4
1513 1513 $ cat large4-renamed
1514 1514 large4-modified
1515 1515 $ cd sub2
1516 1516 $ hg rename large6 large6-renamed
1517 1517 $ hg st
1518 1518 A sub2/large6-renamed
1519 1519 R sub2/large6
1520 1520 $ cd ..
1521 1521
1522 1522 Test --normal flag
1523 1523
1524 1524 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1525 1525 $ hg add --normal --large new-largefile
1526 1526 abort: --normal cannot be used with --large
1527 1527 [255]
1528 1528 $ hg add --normal new-largefile
1529 1529 new-largefile: up to 69 MB of RAM may be required to manage this file
1530 1530 (use 'hg revert new-largefile' to cancel the pending addition)
1531 1531 $ cd ..
1532 1532
1533 1533 #if serve
1534 1534 vanilla clients not locked out from largefiles servers on vanilla repos
1535 1535 $ mkdir r1
1536 1536 $ cd r1
1537 1537 $ hg init
1538 1538 $ echo c1 > f1
1539 1539 $ hg add f1
1540 1540 $ hg commit -m "m1"
1541 1541 Invoking status precommit hook
1542 1542 A f1
1543 1543 $ cd ..
1544 1544 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1545 1545 $ cat hg.pid >> $DAEMON_PIDS
1546 1546 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1547 1547 requesting all changes
1548 1548 adding changesets
1549 1549 adding manifests
1550 1550 adding file changes
1551 1551 added 1 changesets with 1 changes to 1 files
1552 1552 updating to branch default
1553 1553 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1554 1554
1555 1555 largefiles clients still work with vanilla servers
1556 1556 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1557 1557 $ cat hg.pid >> $DAEMON_PIDS
1558 1558 $ hg clone http://localhost:$HGPORT1 r3
1559 1559 requesting all changes
1560 1560 adding changesets
1561 1561 adding manifests
1562 1562 adding file changes
1563 1563 added 1 changesets with 1 changes to 1 files
1564 1564 updating to branch default
1565 1565 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1566 1566 #endif
1567 1567
1568 1568
1569 1569 vanilla clients locked out from largefiles http repos
1570 1570 $ mkdir r4
1571 1571 $ cd r4
1572 1572 $ hg init
1573 1573 $ echo c1 > f1
1574 1574 $ hg add --large f1
1575 1575 $ hg commit -m "m1"
1576 1576 Invoking status precommit hook
1577 1577 A f1
1578 1578 $ cd ..
1579 1579
1580 1580 largefiles can be pushed locally (issue3583)
1581 1581 $ hg init dest
1582 1582 $ cd r4
1583 1583 $ hg outgoing ../dest
1584 1584 comparing with ../dest
1585 1585 searching for changes
1586 1586 changeset: 0:639881c12b4c
1587 1587 tag: tip
1588 1588 user: test
1589 1589 date: Thu Jan 01 00:00:00 1970 +0000
1590 1590 summary: m1
1591 1591
1592 1592 $ hg push ../dest
1593 1593 pushing to ../dest
1594 1594 searching for changes
1595 1595 searching for changes
1596 1596 adding changesets
1597 1597 adding manifests
1598 1598 adding file changes
1599 1599 added 1 changesets with 1 changes to 1 files
1600 1600
1601 1601 exit code with nothing outgoing (issue3611)
1602 1602 $ hg outgoing ../dest
1603 1603 comparing with ../dest
1604 1604 searching for changes
1605 1605 no changes found
1606 1606 [1]
1607 1607 $ cd ..
1608 1608
1609 1609 #if serve
1610 1610 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1611 1611 $ cat hg.pid >> $DAEMON_PIDS
1612 1612 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1613 1613 abort: remote error:
1614 1614
1615 1615 This repository uses the largefiles extension.
1616 1616
1617 1617 Please enable it in your Mercurial config file.
1618 1618 [255]
1619 1619
1620 1620 used all HGPORTs, kill all daemons
1621 1621 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1622 1622 #endif
1623 1623
1624 1624 vanilla clients locked out from largefiles ssh repos
1625 1625 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1626 1626 abort: remote error:
1627 1627
1628 1628 This repository uses the largefiles extension.
1629 1629
1630 1630 Please enable it in your Mercurial config file.
1631 1631 [255]
1632 1632
1633 1633 #if serve
1634 1634
1635 1635 largefiles clients refuse to push largefiles repos to vanilla servers
1636 1636 $ mkdir r6
1637 1637 $ cd r6
1638 1638 $ hg init
1639 1639 $ echo c1 > f1
1640 1640 $ hg add f1
1641 1641 $ hg commit -m "m1"
1642 1642 Invoking status precommit hook
1643 1643 A f1
1644 1644 $ cat >> .hg/hgrc <<!
1645 1645 > [web]
1646 1646 > push_ssl = false
1647 1647 > allow_push = *
1648 1648 > !
1649 1649 $ cd ..
1650 1650 $ hg clone r6 r7
1651 1651 updating to branch default
1652 1652 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1653 1653 $ cd r7
1654 1654 $ echo c2 > f2
1655 1655 $ hg add --large f2
1656 1656 $ hg commit -m "m2"
1657 1657 Invoking status precommit hook
1658 1658 A f2
1659 1659 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1660 1660 $ cat ../hg.pid >> $DAEMON_PIDS
1661 1661 $ hg push http://localhost:$HGPORT
1662 1662 pushing to http://localhost:$HGPORT/
1663 1663 searching for changes
1664 1664 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1665 1665 [255]
1666 1666 $ cd ..
1667 1667
1668 1668 putlfile errors are shown (issue3123)
1669 1669 Corrupt the cached largefile in r7 and move it out of the servers usercache
1670 1670 $ mv r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 .
1671 1671 $ echo 'client side corruption' > r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1672 1672 $ rm "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1673 1673 $ hg init empty
1674 1674 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1675 1675 > --config 'web.allow_push=*' --config web.push_ssl=False
1676 1676 $ cat hg.pid >> $DAEMON_PIDS
1677 1677 $ hg push -R r7 http://localhost:$HGPORT1
1678 1678 pushing to http://localhost:$HGPORT1/
1679 1679 searching for changes
1680 1680 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1681 1681 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1682 1682 [255]
1683 1683 $ mv 4cdac4d8b084d0b599525cf732437fb337d422a8 r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1684 1684 Push of file that exists on server but is corrupted - magic healing would be nice ... but too magic
1685 1685 $ echo "server side corruption" > empty/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1686 1686 $ hg push -R r7 http://localhost:$HGPORT1
1687 1687 pushing to http://localhost:$HGPORT1/
1688 1688 searching for changes
1689 1689 searching for changes
1690 1690 remote: adding changesets
1691 1691 remote: adding manifests
1692 1692 remote: adding file changes
1693 1693 remote: added 2 changesets with 2 changes to 2 files
1694 1694 $ cat empty/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1695 1695 server side corruption
1696 1696 $ rm -rf empty
1697 1697
1698 1698 Push a largefiles repository to a served empty repository
1699 1699 $ hg init r8
1700 1700 $ echo c3 > r8/f1
1701 1701 $ hg add --large r8/f1 -R r8
1702 1702 $ hg commit -m "m1" -R r8
1703 1703 Invoking status precommit hook
1704 1704 A f1
1705 1705 $ hg init empty
1706 1706 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1707 1707 > --config 'web.allow_push=*' --config web.push_ssl=False
1708 1708 $ cat hg.pid >> $DAEMON_PIDS
1709 1709 $ rm "${USERCACHE}"/*
1710 1710 $ hg push -R r8 http://localhost:$HGPORT2/#default
1711 1711 pushing to http://localhost:$HGPORT2/
1712 1712 searching for changes
1713 1713 searching for changes
1714 1714 remote: adding changesets
1715 1715 remote: adding manifests
1716 1716 remote: adding file changes
1717 1717 remote: added 1 changesets with 1 changes to 1 files
1718 1718 $ [ -f "${USERCACHE}"/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1719 1719 $ [ -f empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1720 1720
1721 1721 Clone over http, no largefiles pulled on clone.
1722 1722
1723 1723 $ hg clone http://localhost:$HGPORT2/#default http-clone -U
1724 1724 adding changesets
1725 1725 adding manifests
1726 1726 adding file changes
1727 1727 added 1 changesets with 1 changes to 1 files
1728 1728
1729 1729 test 'verify' with remotestore:
1730 1730
1731 1731 $ rm "${USERCACHE}"/02a439e5c31c526465ab1a0ca1f431f76b827b90
1732 1732 $ mv empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 .
1733 1733 $ hg -R http-clone verify --large --lfa
1734 1734 checking changesets
1735 1735 checking manifests
1736 1736 crosschecking files in changesets and manifests
1737 1737 checking files
1738 1738 1 files, 1 changesets, 1 total revisions
1739 1739 searching 1 changesets for largefiles
1740 1740 changeset 0:cf03e5bb9936: f1 missing
1741 1741 verified existence of 1 revisions of 1 largefiles
1742 1742 [1]
1743 1743 $ mv 02a439e5c31c526465ab1a0ca1f431f76b827b90 empty/.hg/largefiles/
1744 1744 $ hg -R http-clone -q verify --large --lfa
1745 1745
1746 1746 largefiles pulled on update - a largefile missing on the server:
1747 1747 $ mv empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 .
1748 1748 $ hg -R http-clone up --config largefiles.usercache=http-clone-usercache
1749 1749 getting changed largefiles
1750 1750 f1: largefile 02a439e5c31c526465ab1a0ca1f431f76b827b90 not available from http://localhost:$HGPORT2/
1751 1751 0 largefiles updated, 0 removed
1752 1752 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1753 1753 $ hg -R http-clone st
1754 1754 ! f1
1755 1755 $ hg -R http-clone up -Cqr null
1756 1756
1757 1757 largefiles pulled on update - a largefile corrupted on the server:
1758 1758 $ echo corruption > empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90
1759 1759 $ hg -R http-clone up --config largefiles.usercache=http-clone-usercache
1760 1760 getting changed largefiles
1761 1761 f1: data corruption (expected 02a439e5c31c526465ab1a0ca1f431f76b827b90, got 6a7bb2556144babe3899b25e5428123735bb1e27)
1762 1762 0 largefiles updated, 0 removed
1763 1763 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1764 1764 $ hg -R http-clone st
1765 1765 ! f1
1766 1766 $ [ ! -f http-clone/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1767 1767 $ [ ! -f http-clone/f1 ]
1768 1768 $ [ ! -f http-clone-usercache ]
1769 1769 $ hg -R http-clone verify --large --lfc
1770 1770 checking changesets
1771 1771 checking manifests
1772 1772 crosschecking files in changesets and manifests
1773 1773 checking files
1774 1774 1 files, 1 changesets, 1 total revisions
1775 1775 searching 1 changesets for largefiles
1776 1776 verified contents of 1 revisions of 1 largefiles
1777 1777 $ hg -R http-clone up -Cqr null
1778 1778
1779 1779 largefiles pulled on update - no server side problems:
1780 1780 $ mv 02a439e5c31c526465ab1a0ca1f431f76b827b90 empty/.hg/largefiles/
1781 1781 $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
1782 1782 resolving manifests
1783 1783 branchmerge: False, force: False, partial: False
1784 1784 ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
1785 1785 .hglf/f1: remote created -> g
1786 1786 getting .hglf/f1
1787 1787 updating: .hglf/f1 1/1 files (100.00%)
1788 1788 getting changed largefiles
1789 1789 using http://localhost:$HGPORT2/
1790 1790 sending capabilities command
1791 1791 sending batch command
1792 1792 getting largefiles: 0/1 lfile (0.00%)
1793 1793 getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
1794 1794 sending getlfile command
1795 1795 found 02a439e5c31c526465ab1a0ca1f431f76b827b90 in store
1796 1796 1 largefiles updated, 0 removed
1797 1797 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1798 1798
1799 1799 $ ls http-clone-usercache/*
1800 1800 http-clone-usercache/02a439e5c31c526465ab1a0ca1f431f76b827b90
1801 1801
1802 1802 $ rm -rf empty http-clone*
1803 1803
1804 1804 used all HGPORTs, kill all daemons
1805 1805 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1806 1806
1807 1807 #endif
1808 1808
1809 1809
1810 1810 #if unix-permissions
1811 1811
1812 1812 Clone a local repository owned by another user
1813 1813 We have to simulate that here by setting $HOME and removing write permissions
1814 1814 $ ORIGHOME="$HOME"
1815 1815 $ mkdir alice
1816 1816 $ HOME="`pwd`/alice"
1817 1817 $ cd alice
1818 1818 $ hg init pubrepo
1819 1819 $ cd pubrepo
1820 1820 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1821 1821 $ hg add --large a-large-file
1822 1822 $ hg commit -m "Add a large file"
1823 1823 Invoking status precommit hook
1824 1824 A a-large-file
1825 1825 $ cd ..
1826 1826 $ chmod -R a-w pubrepo
1827 1827 $ cd ..
1828 1828 $ mkdir bob
1829 1829 $ HOME="`pwd`/bob"
1830 1830 $ cd bob
1831 1831 $ hg clone --pull ../alice/pubrepo pubrepo
1832 1832 requesting all changes
1833 1833 adding changesets
1834 1834 adding manifests
1835 1835 adding file changes
1836 1836 added 1 changesets with 1 changes to 1 files
1837 1837 updating to branch default
1838 1838 getting changed largefiles
1839 1839 1 largefiles updated, 0 removed
1840 1840 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1841 1841 $ cd ..
1842 1842 $ chmod -R u+w alice/pubrepo
1843 1843 $ HOME="$ORIGHOME"
1844 1844
1845 1845 #endif
1846 1846
1847 1847 #if symlink
1848 1848
1849 1849 Symlink to a large largefile should behave the same as a symlink to a normal file
1850 1850 $ hg init largesymlink
1851 1851 $ cd largesymlink
1852 1852 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1853 1853 $ hg add --large largefile
1854 1854 $ hg commit -m "commit a large file"
1855 1855 Invoking status precommit hook
1856 1856 A largefile
1857 1857 $ ln -s largefile largelink
1858 1858 $ hg add largelink
1859 1859 $ hg commit -m "commit a large symlink"
1860 1860 Invoking status precommit hook
1861 1861 A largelink
1862 1862 $ rm -f largelink
1863 1863 $ hg up >/dev/null
1864 1864 $ test -f largelink
1865 1865 [1]
1866 1866 $ test -L largelink
1867 1867 [1]
1868 1868 $ rm -f largelink # make next part of the test independent of the previous
1869 1869 $ hg up -C >/dev/null
1870 1870 $ test -f largelink
1871 1871 $ test -L largelink
1872 1872 $ cd ..
1873 1873
1874 1874 #endif
1875 1875
1876 1876 test for pattern matching on 'hg status':
1877 1877 to boost performance, largefiles checks whether specified patterns are
1878 1878 related to largefiles in working directory (NOT to STANDIN) or not.
1879 1879
1880 1880 $ hg init statusmatch
1881 1881 $ cd statusmatch
1882 1882
1883 1883 $ mkdir -p a/b/c/d
1884 1884 $ echo normal > a/b/c/d/e.normal.txt
1885 1885 $ hg add a/b/c/d/e.normal.txt
1886 1886 $ echo large > a/b/c/d/e.large.txt
1887 1887 $ hg add --large a/b/c/d/e.large.txt
1888 1888 $ mkdir -p a/b/c/x
1889 1889 $ echo normal > a/b/c/x/y.normal.txt
1890 1890 $ hg add a/b/c/x/y.normal.txt
1891 1891 $ hg commit -m 'add files'
1892 1892 Invoking status precommit hook
1893 1893 A a/b/c/d/e.large.txt
1894 1894 A a/b/c/d/e.normal.txt
1895 1895 A a/b/c/x/y.normal.txt
1896 1896
1897 1897 (1) no pattern: no performance boost
1898 1898 $ hg status -A
1899 1899 C a/b/c/d/e.large.txt
1900 1900 C a/b/c/d/e.normal.txt
1901 1901 C a/b/c/x/y.normal.txt
1902 1902
1903 1903 (2) pattern not related to largefiles: performance boost
1904 1904 $ hg status -A a/b/c/x
1905 1905 C a/b/c/x/y.normal.txt
1906 1906
1907 1907 (3) pattern related to largefiles: no performance boost
1908 1908 $ hg status -A a/b/c/d
1909 1909 C a/b/c/d/e.large.txt
1910 1910 C a/b/c/d/e.normal.txt
1911 1911
1912 1912 (4) pattern related to STANDIN (not to largefiles): performance boost
1913 1913 $ hg status -A .hglf/a
1914 1914 C .hglf/a/b/c/d/e.large.txt
1915 1915
1916 1916 (5) mixed case: no performance boost
1917 1917 $ hg status -A a/b/c/x a/b/c/d
1918 1918 C a/b/c/d/e.large.txt
1919 1919 C a/b/c/d/e.normal.txt
1920 1920 C a/b/c/x/y.normal.txt
1921 1921
1922 1922 verify that largefiles doesn't break filesets
1923 1923
1924 1924 $ hg log --rev . --exclude "set:binary()"
1925 1925 changeset: 0:41bd42f10efa
1926 1926 tag: tip
1927 1927 user: test
1928 1928 date: Thu Jan 01 00:00:00 1970 +0000
1929 1929 summary: add files
1930 1930
1931 1931 verify that large files in subrepos handled properly
1932 1932 $ hg init subrepo
1933 1933 $ echo "subrepo = subrepo" > .hgsub
1934 1934 $ hg add .hgsub
1935 1935 $ hg ci -m "add subrepo"
1936 1936 Invoking status precommit hook
1937 1937 A .hgsub
1938 1938 ? .hgsubstate
1939 1939 $ echo "rev 1" > subrepo/large.txt
1940 1940 $ hg -R subrepo add --large subrepo/large.txt
1941 1941 $ hg sum
1942 1942 parent: 1:8ee150ea2e9c tip
1943 1943 add subrepo
1944 1944 branch: default
1945 1945 commit: 1 subrepos
1946 1946 update: (current)
1947 1947 $ hg st
1948 1948 $ hg st -S
1949 1949 A subrepo/large.txt
1950 1950 $ hg ci -S -m "commit top repo"
1951 1951 committing subrepository subrepo
1952 1952 Invoking status precommit hook
1953 1953 A large.txt
1954 1954 Invoking status precommit hook
1955 1955 M .hgsubstate
1956 1956 # No differences
1957 1957 $ hg st -S
1958 1958 $ hg sum
1959 1959 parent: 2:ce4cd0c527a6 tip
1960 1960 commit top repo
1961 1961 branch: default
1962 1962 commit: (clean)
1963 1963 update: (current)
1964 1964 $ echo "rev 2" > subrepo/large.txt
1965 1965 $ hg st -S
1966 1966 M subrepo/large.txt
1967 1967 $ hg sum
1968 1968 parent: 2:ce4cd0c527a6 tip
1969 1969 commit top repo
1970 1970 branch: default
1971 1971 commit: 1 subrepos
1972 1972 update: (current)
1973 1973 $ hg ci -m "this commit should fail without -S"
1974 1974 abort: uncommitted changes in subrepo subrepo
1975 1975 (use --subrepos for recursive commit)
1976 1976 [255]
1977 1977
1978 1978 Add a normal file to the subrepo, then test archiving
1979 1979
1980 1980 $ echo 'normal file' > subrepo/normal.txt
1981 1981 $ hg -R subrepo add subrepo/normal.txt
1982 1982
1983 1983 Lock in subrepo, otherwise the change isn't archived
1984 1984
1985 1985 $ hg ci -S -m "add normal file to top level"
1986 1986 committing subrepository subrepo
1987 1987 Invoking status precommit hook
1988 1988 M large.txt
1989 1989 A normal.txt
1990 1990 Invoking status precommit hook
1991 1991 M .hgsubstate
1992 1992 $ hg archive -S ../lf_subrepo_archive
1993 1993 $ find ../lf_subrepo_archive | sort
1994 1994 ../lf_subrepo_archive
1995 1995 ../lf_subrepo_archive/.hg_archival.txt
1996 1996 ../lf_subrepo_archive/.hgsub
1997 1997 ../lf_subrepo_archive/.hgsubstate
1998 1998 ../lf_subrepo_archive/a
1999 1999 ../lf_subrepo_archive/a/b
2000 2000 ../lf_subrepo_archive/a/b/c
2001 2001 ../lf_subrepo_archive/a/b/c/d
2002 2002 ../lf_subrepo_archive/a/b/c/d/e.large.txt
2003 2003 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
2004 2004 ../lf_subrepo_archive/a/b/c/x
2005 2005 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
2006 2006 ../lf_subrepo_archive/subrepo
2007 2007 ../lf_subrepo_archive/subrepo/large.txt
2008 2008 ../lf_subrepo_archive/subrepo/normal.txt
2009 2009
2010 2010 Test update with subrepos.
2011 2011
2012 2012 $ hg update 0
2013 2013 getting changed largefiles
2014 2014 0 largefiles updated, 1 removed
2015 2015 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
2016 2016 $ hg status -S
2017 2017 $ hg update tip
2018 2018 getting changed largefiles
2019 2019 1 largefiles updated, 0 removed
2020 2020 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
2021 2021 $ hg status -S
2022 2022 # modify a large file
2023 2023 $ echo "modified" > subrepo/large.txt
2024 2024 $ hg st -S
2025 2025 M subrepo/large.txt
2026 2026 # update -C should revert the change.
2027 2027 $ hg update -C
2028 2028 getting changed largefiles
2029 2029 1 largefiles updated, 0 removed
2030 2030 getting changed largefiles
2031 2031 0 largefiles updated, 0 removed
2032 2032 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2033 2033 $ hg status -S
2034 2034
2035 2035 Test archiving a revision that references a subrepo that is not yet
2036 2036 cloned (see test-subrepo-recursion.t):
2037 2037
2038 2038 $ hg clone -U . ../empty
2039 2039 $ cd ../empty
2040 2040 $ hg archive --subrepos -r tip ../archive.tar.gz
2041 2041 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
2042 2042 $ cd ..
2043 2043
2044 2044 Test that addremove picks up largefiles prior to the initial commit (issue3541)
2045 2045
2046 2046 $ hg init addrm2
2047 2047 $ cd addrm2
2048 2048 $ touch large.dat
2049 2049 $ touch large2.dat
2050 2050 $ touch normal
2051 2051 $ hg add --large large.dat
2052 2052 $ hg addremove -v
2053 2053 adding large2.dat as a largefile
2054 2054 adding normal
2055 2055
2056 2056 Test that forgetting all largefiles reverts to islfilesrepo() == False
2057 2057 (addremove will add *.dat as normal files now)
2058 2058 $ hg forget large.dat
2059 2059 $ hg forget large2.dat
2060 2060 $ hg addremove -v
2061 2061 adding large.dat
2062 2062 adding large2.dat
2063 2063
2064 2064 Test commit's addremove option prior to the first commit
2065 2065 $ hg forget large.dat
2066 2066 $ hg forget large2.dat
2067 2067 $ hg add --large large.dat
2068 2068 $ hg ci -Am "commit"
2069 2069 adding large2.dat as a largefile
2070 2070 Invoking status precommit hook
2071 2071 A large.dat
2072 2072 A large2.dat
2073 2073 A normal
2074 2074 $ find .hglf | sort
2075 2075 .hglf
2076 2076 .hglf/large.dat
2077 2077 .hglf/large2.dat
2078 2078
2079 2079 Test actions on largefiles using relative paths from subdir
2080 2080
2081 2081 $ mkdir sub
2082 2082 $ cd sub
2083 2083 $ echo anotherlarge > anotherlarge
2084 2084 $ hg add --large anotherlarge
2085 2085 $ hg st
2086 2086 A sub/anotherlarge
2087 2087 $ hg st anotherlarge
2088 2088 A anotherlarge
2089 2089 $ hg commit -m anotherlarge anotherlarge
2090 2090 Invoking status precommit hook
2091 2091 A sub/anotherlarge
2092 2092 $ hg log anotherlarge
2093 2093 changeset: 1:9627a577c5e9
2094 2094 tag: tip
2095 2095 user: test
2096 2096 date: Thu Jan 01 00:00:00 1970 +0000
2097 2097 summary: anotherlarge
2098 2098
2099 2099 $ echo more >> anotherlarge
2100 2100 $ hg st .
2101 2101 M anotherlarge
2102 2102 $ hg cat anotherlarge
2103 2103 anotherlarge
2104 2104 $ hg revert anotherlarge
2105 2105 $ hg st
2106 2106 ? sub/anotherlarge.orig
2107 2107 $ cd ..
2108 2108
2109 2109 $ cd ..
2110 2110
2111 2111 issue3651: summary/outgoing with largefiles shows "no remote repo"
2112 2112 unexpectedly
2113 2113
2114 2114 $ mkdir issue3651
2115 2115 $ cd issue3651
2116 2116
2117 2117 $ hg init src
2118 2118 $ echo a > src/a
2119 2119 $ hg -R src add --large src/a
2120 2120 $ hg -R src commit -m '#0'
2121 2121 Invoking status precommit hook
2122 2122 A a
2123 2123
2124 2124 check messages when no remote repository is specified:
2125 2125 "no remote repo" route for "hg outgoing --large" is not tested here,
2126 2126 because it can't be reproduced easily.
2127 2127
2128 2128 $ hg init clone1
2129 2129 $ hg -R clone1 -q pull src
2130 2130 $ hg -R clone1 -q update
2131 2131 $ hg -R clone1 paths | grep default
2132 2132 [1]
2133 2133
2134 2134 $ hg -R clone1 summary --large
2135 2135 parent: 0:fc0bd45326d3 tip
2136 2136 #0
2137 2137 branch: default
2138 2138 commit: (clean)
2139 2139 update: (current)
2140 2140 largefiles: (no remote repo)
2141 2141
2142 2142 check messages when there is no files to upload:
2143 2143
2144 2144 $ hg -q clone src clone2
2145 2145 $ hg -R clone2 paths | grep default
2146 2146 default = $TESTTMP/issue3651/src (glob)
2147 2147
2148 2148 $ hg -R clone2 summary --large
2149 2149 parent: 0:fc0bd45326d3 tip
2150 2150 #0
2151 2151 branch: default
2152 2152 commit: (clean)
2153 2153 update: (current)
2154 2154 searching for changes
2155 2155 largefiles: (no files to upload)
2156 2156 $ hg -R clone2 outgoing --large
2157 2157 comparing with $TESTTMP/issue3651/src (glob)
2158 2158 searching for changes
2159 2159 no changes found
2160 2160 searching for changes
2161 2161 largefiles: no files to upload
2162 2162 [1]
2163 2163
2164 2164 check messages when there are files to upload:
2165 2165
2166 2166 $ echo b > clone2/b
2167 2167 $ hg -R clone2 add --large clone2/b
2168 2168 $ hg -R clone2 commit -m '#1'
2169 2169 Invoking status precommit hook
2170 2170 A b
2171 2171 $ hg -R clone2 summary --large
2172 2172 parent: 1:1acbe71ce432 tip
2173 2173 #1
2174 2174 branch: default
2175 2175 commit: (clean)
2176 2176 update: (current)
2177 2177 searching for changes
2178 2178 largefiles: 1 to upload
2179 2179 $ hg -R clone2 outgoing --large
2180 2180 comparing with $TESTTMP/issue3651/src (glob)
2181 2181 searching for changes
2182 2182 changeset: 1:1acbe71ce432
2183 2183 tag: tip
2184 2184 user: test
2185 2185 date: Thu Jan 01 00:00:00 1970 +0000
2186 2186 summary: #1
2187 2187
2188 2188 searching for changes
2189 2189 largefiles to upload:
2190 2190 b
2191 2191
2192 2192
2193 2193 $ cd ..
2194 2194
2195 2195 merge action 'd' for 'local renamed directory to d2/g' which has no filename
2196 2196
2197 2197 $ hg init merge-action
2198 2198 $ cd merge-action
2199 2199 $ touch l
2200 2200 $ hg add --large l
2201 2201 $ mkdir d1
2202 2202 $ touch d1/f
2203 2203 $ hg ci -Aqm0
2204 2204 Invoking status precommit hook
2205 2205 A d1/f
2206 2206 A l
2207 2207 $ echo > d1/f
2208 2208 $ touch d1/g
2209 2209 $ hg ci -Aqm1
2210 2210 Invoking status precommit hook
2211 2211 M d1/f
2212 2212 A d1/g
2213 2213 $ hg up -qr0
2214 2214 $ hg mv d1 d2
2215 2215 moving d1/f to d2/f (glob)
2216 2216 $ hg ci -qm2
2217 2217 Invoking status precommit hook
2218 2218 A d2/f
2219 2219 R d1/f
2220 2220 $ hg merge
2221 2221 merging d2/f and d1/f to d2/f
2222 2222 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
2223 2223 (branch merge, don't forget to commit)
2224 2224 getting changed largefiles
2225 2225 0 largefiles updated, 0 removed
2226 2226 $ cd ..
2227 2227
2228 2228 Check whether "largefiles" feature is supported only in repositories
2229 2229 enabling largefiles extension.
2230 2230
2231 2231 $ mkdir individualenabling
2232 2232 $ cd individualenabling
2233 2233
2234 2234 $ hg init enabledlocally
2235 2235 $ echo large > enabledlocally/large
2236 2236 $ hg -R enabledlocally add --large enabledlocally/large
2237 2237 $ hg -R enabledlocally commit -m '#0'
2238 2238 Invoking status precommit hook
2239 2239 A large
2240 2240
2241 2241 $ hg init notenabledlocally
2242 2242 $ echo large > notenabledlocally/large
2243 2243 $ hg -R notenabledlocally add --large notenabledlocally/large
2244 2244 $ hg -R notenabledlocally commit -m '#0'
2245 2245 Invoking status precommit hook
2246 2246 A large
2247 2247
2248 2248 $ cat >> $HGRCPATH <<EOF
2249 2249 > [extensions]
2250 2250 > # disable globally
2251 2251 > largefiles=!
2252 2252 > EOF
2253 2253 $ cat >> enabledlocally/.hg/hgrc <<EOF
2254 2254 > [extensions]
2255 2255 > # enable locally
2256 2256 > largefiles=
2257 2257 > EOF
2258 2258 $ hg -R enabledlocally root
2259 2259 $TESTTMP/individualenabling/enabledlocally (glob)
2260 2260 $ hg -R notenabledlocally root
2261 2261 abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)!
2262 2262 [255]
2263 2263
2264 2264 $ hg init push-dst
2265 2265 $ hg -R enabledlocally push push-dst
2266 2266 pushing to push-dst
2267 2267 abort: required features are not supported in the destination: largefiles
2268 2268 [255]
2269 2269
2270 2270 $ hg init pull-src
2271 2271 $ hg -R pull-src pull enabledlocally
2272 2272 pulling from enabledlocally
2273 2273 abort: required features are not supported in the destination: largefiles
2274 2274 [255]
2275 2275
2276 2276 $ hg clone enabledlocally clone-dst
2277 2277 abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)!
2278 2278 [255]
2279 2279 $ test -d clone-dst
2280 2280 [1]
2281 2281 $ hg clone --pull enabledlocally clone-pull-dst
2282 2282 abort: required features are not supported in the destination: largefiles
2283 2283 [255]
2284 2284 $ test -d clone-pull-dst
2285 2285 [1]
2286 2286
2287 2287 $ cd ..
@@ -1,450 +1,461 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > rebase=
4 4 >
5 5 > [phases]
6 6 > publish=False
7 7 >
8 8 > [alias]
9 9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 10 > EOF
11 11
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
16 16 adding changesets
17 17 adding manifests
18 18 adding file changes
19 19 added 8 changesets with 7 changes to 7 files (+2 heads)
20 20 (run 'hg heads' to see heads, 'hg merge' to merge)
21 21 $ hg up tip
22 22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 23
24 24 $ echo I > I
25 25 $ hg ci -AmI
26 26 adding I
27 27
28 28 $ hg tglog
29 29 @ 8: 'I'
30 30 |
31 31 o 7: 'H'
32 32 |
33 33 | o 6: 'G'
34 34 |/|
35 35 o | 5: 'F'
36 36 | |
37 37 | o 4: 'E'
38 38 |/
39 39 | o 3: 'D'
40 40 | |
41 41 | o 2: 'C'
42 42 | |
43 43 | o 1: 'B'
44 44 |/
45 45 o 0: 'A'
46 46
47 47 $ cd ..
48 48
49 49
50 50 These fail:
51 51
52 52 $ hg clone -q -u . a a1
53 53 $ cd a1
54 54
55 55 $ hg rebase -s 8 -d 7
56 56 nothing to rebase
57 57 [1]
58 58
59 59 $ hg rebase --continue --abort
60 60 abort: cannot use both abort and continue
61 61 [255]
62 62
63 63 $ hg rebase --continue --collapse
64 64 abort: cannot use collapse with continue or abort
65 65 [255]
66 66
67 67 $ hg rebase --continue --dest 4
68 68 abort: abort and continue do not allow specifying revisions
69 69 [255]
70 70
71 71 $ hg rebase --base 5 --source 4
72 72 abort: cannot specify both a source and a base
73 73 [255]
74 74
75 75 $ hg rebase --rev 5 --source 4
76 76 abort: cannot specify both a revision and a source
77 77 [255]
78 78 $ hg rebase --base 5 --rev 4
79 79 abort: cannot specify both a revision and a base
80 80 [255]
81 81
82 82 $ hg rebase --rev '1 & !1'
83 83 abort: empty "rev" revision set - nothing to rebase
84 84 [255]
85 85
86 86 $ hg rebase --source '1 & !1'
87 87 abort: empty "source" revision set - nothing to rebase
88 88 [255]
89 89
90 $ hg rebase --base '1 & !1'
91 abort: empty "base" revision set - can't compute rebase set
92 [255]
93
90 94 $ hg rebase
91 nothing to rebase
95 nothing to rebase - working directory parent is also destination
96 [1]
97
98 $ hg rebase -b.
99 nothing to rebase - e7ec4e813ba6 is both "base" and destination
92 100 [1]
93 101
94 102 $ hg up -q 7
95 103
96 104 $ hg rebase --traceback
97 nothing to rebase
105 nothing to rebase - working directory parent is already an ancestor of destination e7ec4e813ba6
106 [1]
107
108 $ hg rebase -b.
109 nothing to rebase - "base" 02de42196ebe is already an ancestor of destination e7ec4e813ba6
98 110 [1]
99 111
100 112 $ hg rebase --dest '1 & !1'
101 113 abort: empty revision set
102 114 [255]
103 115
104 116 These work:
105 117
106 118 Rebase with no arguments (from 3 onto 8):
107 119
108 120 $ hg up -q -C 3
109 121
110 122 $ hg rebase
111 123 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
112 124
113 125 $ hg tglog
114 126 @ 8: 'D'
115 127 |
116 128 o 7: 'C'
117 129 |
118 130 o 6: 'B'
119 131 |
120 132 o 5: 'I'
121 133 |
122 134 o 4: 'H'
123 135 |
124 136 | o 3: 'G'
125 137 |/|
126 138 o | 2: 'F'
127 139 | |
128 140 | o 1: 'E'
129 141 |/
130 142 o 0: 'A'
131 143
132 144 Try to rollback after a rebase (fail):
133 145
134 146 $ hg rollback
135 147 no rollback information available
136 148 [1]
137 149
138 150 $ cd ..
139 151
140
141 152 Rebase with base == '.' => same as no arguments (from 3 onto 8):
142 153
143 154 $ hg clone -q -u 3 a a2
144 155 $ cd a2
145 156
146 157 $ hg rebase --base .
147 158 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
148 159
149 160 $ hg tglog
150 161 @ 8: 'D'
151 162 |
152 163 o 7: 'C'
153 164 |
154 165 o 6: 'B'
155 166 |
156 167 o 5: 'I'
157 168 |
158 169 o 4: 'H'
159 170 |
160 171 | o 3: 'G'
161 172 |/|
162 173 o | 2: 'F'
163 174 | |
164 175 | o 1: 'E'
165 176 |/
166 177 o 0: 'A'
167 178
168 179 $ cd ..
169 180
170 181
171 182 Rebase with dest == branch(.) => same as no arguments (from 3 onto 8):
172 183
173 184 $ hg clone -q -u 3 a a3
174 185 $ cd a3
175 186
176 187 $ hg rebase --dest 'branch(.)'
177 188 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
178 189
179 190 $ hg tglog
180 191 @ 8: 'D'
181 192 |
182 193 o 7: 'C'
183 194 |
184 195 o 6: 'B'
185 196 |
186 197 o 5: 'I'
187 198 |
188 199 o 4: 'H'
189 200 |
190 201 | o 3: 'G'
191 202 |/|
192 203 o | 2: 'F'
193 204 | |
194 205 | o 1: 'E'
195 206 |/
196 207 o 0: 'A'
197 208
198 209 $ cd ..
199 210
200 211
201 212 Specify only source (from 2 onto 8):
202 213
203 214 $ hg clone -q -u . a a4
204 215 $ cd a4
205 216
206 217 $ hg rebase --source 'desc("C")'
207 218 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
208 219
209 220 $ hg tglog
210 221 o 8: 'D'
211 222 |
212 223 o 7: 'C'
213 224 |
214 225 @ 6: 'I'
215 226 |
216 227 o 5: 'H'
217 228 |
218 229 | o 4: 'G'
219 230 |/|
220 231 o | 3: 'F'
221 232 | |
222 233 | o 2: 'E'
223 234 |/
224 235 | o 1: 'B'
225 236 |/
226 237 o 0: 'A'
227 238
228 239 $ cd ..
229 240
230 241
231 242 Specify only dest (from 3 onto 6):
232 243
233 244 $ hg clone -q -u 3 a a5
234 245 $ cd a5
235 246
236 247 $ hg rebase --dest 6
237 248 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
238 249
239 250 $ hg tglog
240 251 @ 8: 'D'
241 252 |
242 253 o 7: 'C'
243 254 |
244 255 o 6: 'B'
245 256 |
246 257 | o 5: 'I'
247 258 | |
248 259 | o 4: 'H'
249 260 | |
250 261 o | 3: 'G'
251 262 |\|
252 263 | o 2: 'F'
253 264 | |
254 265 o | 1: 'E'
255 266 |/
256 267 o 0: 'A'
257 268
258 269 $ cd ..
259 270
260 271
261 272 Specify only base (from 1 onto 8):
262 273
263 274 $ hg clone -q -u . a a6
264 275 $ cd a6
265 276
266 277 $ hg rebase --base 'desc("D")'
267 278 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
268 279
269 280 $ hg tglog
270 281 o 8: 'D'
271 282 |
272 283 o 7: 'C'
273 284 |
274 285 o 6: 'B'
275 286 |
276 287 @ 5: 'I'
277 288 |
278 289 o 4: 'H'
279 290 |
280 291 | o 3: 'G'
281 292 |/|
282 293 o | 2: 'F'
283 294 | |
284 295 | o 1: 'E'
285 296 |/
286 297 o 0: 'A'
287 298
288 299 $ cd ..
289 300
290 301
291 302 Specify source and dest (from 2 onto 7):
292 303
293 304 $ hg clone -q -u . a a7
294 305 $ cd a7
295 306
296 307 $ hg rebase --source 2 --dest 7
297 308 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob)
298 309
299 310 $ hg tglog
300 311 o 8: 'D'
301 312 |
302 313 o 7: 'C'
303 314 |
304 315 | @ 6: 'I'
305 316 |/
306 317 o 5: 'H'
307 318 |
308 319 | o 4: 'G'
309 320 |/|
310 321 o | 3: 'F'
311 322 | |
312 323 | o 2: 'E'
313 324 |/
314 325 | o 1: 'B'
315 326 |/
316 327 o 0: 'A'
317 328
318 329 $ cd ..
319 330
320 331
321 332 Specify base and dest (from 1 onto 7):
322 333
323 334 $ hg clone -q -u . a a8
324 335 $ cd a8
325 336
326 337 $ hg rebase --base 3 --dest 7
327 338 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/*-backup.hg (glob)
328 339
329 340 $ hg tglog
330 341 o 8: 'D'
331 342 |
332 343 o 7: 'C'
333 344 |
334 345 o 6: 'B'
335 346 |
336 347 | @ 5: 'I'
337 348 |/
338 349 o 4: 'H'
339 350 |
340 351 | o 3: 'G'
341 352 |/|
342 353 o | 2: 'F'
343 354 | |
344 355 | o 1: 'E'
345 356 |/
346 357 o 0: 'A'
347 358
348 359 $ cd ..
349 360
350 361
351 362 Specify only revs (from 2 onto 8)
352 363
353 364 $ hg clone -q -u . a a9
354 365 $ cd a9
355 366
356 367 $ hg rebase --rev 'desc("C")::'
357 368 saved backup bundle to $TESTTMP/a9/.hg/strip-backup/*-backup.hg (glob)
358 369
359 370 $ hg tglog
360 371 o 8: 'D'
361 372 |
362 373 o 7: 'C'
363 374 |
364 375 @ 6: 'I'
365 376 |
366 377 o 5: 'H'
367 378 |
368 379 | o 4: 'G'
369 380 |/|
370 381 o | 3: 'F'
371 382 | |
372 383 | o 2: 'E'
373 384 |/
374 385 | o 1: 'B'
375 386 |/
376 387 o 0: 'A'
377 388
378 389 $ cd ..
379 390
380 391 Test --tool parameter:
381 392
382 393 $ hg init b
383 394 $ cd b
384 395
385 396 $ echo c1 > c1
386 397 $ hg ci -Am c1
387 398 adding c1
388 399
389 400 $ echo c2 > c2
390 401 $ hg ci -Am c2
391 402 adding c2
392 403
393 404 $ hg up -q 0
394 405 $ echo c2b > c2
395 406 $ hg ci -Am c2b
396 407 adding c2
397 408 created new head
398 409
399 410 $ cd ..
400 411
401 412 $ hg clone -q -u . b b1
402 413 $ cd b1
403 414
404 415 $ hg rebase -s 2 -d 1 --tool internal:local
405 416 saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
406 417
407 418 $ hg cat c2
408 419 c2
409 420
410 421 $ cd ..
411 422
412 423
413 424 $ hg clone -q -u . b b2
414 425 $ cd b2
415 426
416 427 $ hg rebase -s 2 -d 1 --tool internal:other
417 428 saved backup bundle to $TESTTMP/b2/.hg/strip-backup/*-backup.hg (glob)
418 429
419 430 $ hg cat c2
420 431 c2b
421 432
422 433 $ cd ..
423 434
424 435
425 436 $ hg clone -q -u . b b3
426 437 $ cd b3
427 438
428 439 $ hg rebase -s 2 -d 1 --tool internal:fail
429 440 unresolved conflicts (see hg resolve, then hg rebase --continue)
430 441 [1]
431 442
432 443 $ hg summary
433 444 parent: 1:56daeba07f4b
434 445 c2
435 446 parent: 2:e4e3f3546619 tip
436 447 c2b
437 448 branch: default
438 449 commit: 1 modified, 1 unresolved (merge)
439 450 update: (current)
440 451 rebase: 0 rebased, 1 remaining (rebase --continue)
441 452
442 453 $ hg resolve -l
443 454 U c2
444 455
445 456 $ hg resolve -m c2
446 457 $ hg rebase -c --tool internal:fail
447 458 tool option will be ignored
448 459 saved backup bundle to $TESTTMP/b3/.hg/strip-backup/*-backup.hg (glob)
449 460
450 461 $ cd ..
@@ -1,167 +1,167 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > rebase=
4 4 >
5 5 > [alias]
6 6 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
7 7 > EOF
8 8
9 9
10 10 $ hg init a
11 11 $ cd a
12 12
13 13 $ echo C1 > C1
14 14 $ hg ci -Am C1
15 15 adding C1
16 16
17 17 $ echo C2 > C2
18 18 $ hg ci -Am C2
19 19 adding C2
20 20
21 21 $ cd ..
22 22
23 23 $ hg clone a b
24 24 updating to branch default
25 25 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 26
27 27 $ hg clone a c
28 28 updating to branch default
29 29 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 30
31 31 $ cd b
32 32
33 33 $ echo L1 > L1
34 34 $ hg ci -Am L1
35 35 adding L1
36 36
37 37
38 38 $ cd ../a
39 39
40 40 $ echo R1 > R1
41 41 $ hg ci -Am R1
42 42 adding R1
43 43
44 44
45 45 $ cd ../b
46 46
47 47 Now b has one revision to be pulled from a:
48 48
49 49 $ hg pull --rebase
50 50 pulling from $TESTTMP/a (glob)
51 51 searching for changes
52 52 adding changesets
53 53 adding manifests
54 54 adding file changes
55 55 added 1 changesets with 1 changes to 1 files (+1 heads)
56 56 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
57 57
58 58 $ hg tglog
59 59 @ 3: 'L1'
60 60 |
61 61 o 2: 'R1'
62 62 |
63 63 o 1: 'C2'
64 64 |
65 65 o 0: 'C1'
66 66
67 67 Re-run:
68 68
69 69 $ hg pull --rebase
70 70 pulling from $TESTTMP/a (glob)
71 71 searching for changes
72 72 no changes found
73 73
74 74
75 75 Invoke pull --rebase and nothing to rebase:
76 76
77 77 $ cd ../c
78 78
79 79 $ hg book norebase
80 80 $ hg pull --rebase
81 81 pulling from $TESTTMP/a (glob)
82 82 searching for changes
83 83 adding changesets
84 84 adding manifests
85 85 adding file changes
86 86 added 1 changesets with 1 changes to 1 files
87 nothing to rebase
87 nothing to rebase - working directory parent is already an ancestor of destination 77ae9631bcca
88 88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89 updating bookmark norebase
90 90
91 91 $ hg tglog -l 1
92 92 @ 2: 'R1'
93 93 |
94 94
95 95 pull --rebase --update should ignore --update:
96 96
97 97 $ hg pull --rebase --update
98 98 pulling from $TESTTMP/a (glob)
99 99 searching for changes
100 100 no changes found
101 101
102 102 pull --rebase doesn't update if nothing has been pulled:
103 103
104 104 $ hg up -q 1
105 105
106 106 $ hg pull --rebase
107 107 pulling from $TESTTMP/a (glob)
108 108 searching for changes
109 109 no changes found
110 110
111 111 $ hg tglog -l 1
112 112 o 2: 'R1'
113 113 |
114 114
115 115 $ cd ..
116 116
117 117 pull --rebase works when a specific revision is pulled (issue3619)
118 118
119 119 $ cd a
120 120 $ hg tglog
121 121 @ 2: 'R1'
122 122 |
123 123 o 1: 'C2'
124 124 |
125 125 o 0: 'C1'
126 126
127 127 $ echo R2 > R2
128 128 $ hg ci -Am R2
129 129 adding R2
130 130 $ echo R3 > R3
131 131 $ hg ci -Am R3
132 132 adding R3
133 133 $ cd ../c
134 134 $ hg tglog
135 135 o 2: 'R1'
136 136 |
137 137 @ 1: 'C2'
138 138 |
139 139 o 0: 'C1'
140 140
141 141 $ echo L1 > L1
142 142 $ hg ci -Am L1
143 143 adding L1
144 144 created new head
145 145 $ hg pull --rev tip --rebase
146 146 pulling from $TESTTMP/a (glob)
147 147 searching for changes
148 148 adding changesets
149 149 adding manifests
150 150 adding file changes
151 151 added 2 changesets with 2 changes to 2 files
152 152 saved backup bundle to $TESTTMP/c/.hg/strip-backup/ff8d69a621f9-backup.hg (glob)
153 153 $ hg tglog
154 154 @ 5: 'L1'
155 155 |
156 156 o 4: 'R3'
157 157 |
158 158 o 3: 'R2'
159 159 |
160 160 o 2: 'R1'
161 161 |
162 162 o 1: 'C2'
163 163 |
164 164 o 0: 'C1'
165 165
166 166
167 167
@@ -1,651 +1,651 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > rebase=
4 4 >
5 5 > [phases]
6 6 > publish=False
7 7 >
8 8 > [alias]
9 9 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 10 > EOF
11 11
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
16 16 adding changesets
17 17 adding manifests
18 18 adding file changes
19 19 added 8 changesets with 7 changes to 7 files (+2 heads)
20 20 (run 'hg heads' to see heads, 'hg merge' to merge)
21 21 $ hg up tip
22 22 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 23 $ cd ..
24 24
25 25
26 26 Rebasing
27 27 D onto H - simple rebase:
28 28
29 29 $ hg clone -q -u . a a1
30 30 $ cd a1
31 31
32 32 $ hg tglog
33 33 @ 7: 'H'
34 34 |
35 35 | o 6: 'G'
36 36 |/|
37 37 o | 5: 'F'
38 38 | |
39 39 | o 4: 'E'
40 40 |/
41 41 | o 3: 'D'
42 42 | |
43 43 | o 2: 'C'
44 44 | |
45 45 | o 1: 'B'
46 46 |/
47 47 o 0: 'A'
48 48
49 49
50 50 $ hg rebase -s 3 -d 7
51 51 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
52 52
53 53 $ hg tglog
54 54 o 7: 'D'
55 55 |
56 56 @ 6: 'H'
57 57 |
58 58 | o 5: 'G'
59 59 |/|
60 60 o | 4: 'F'
61 61 | |
62 62 | o 3: 'E'
63 63 |/
64 64 | o 2: 'C'
65 65 | |
66 66 | o 1: 'B'
67 67 |/
68 68 o 0: 'A'
69 69
70 70 $ cd ..
71 71
72 72
73 73 D onto F - intermediate point:
74 74
75 75 $ hg clone -q -u . a a2
76 76 $ cd a2
77 77
78 78 $ hg rebase -s 3 -d 5
79 79 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
80 80
81 81 $ hg tglog
82 82 o 7: 'D'
83 83 |
84 84 | @ 6: 'H'
85 85 |/
86 86 | o 5: 'G'
87 87 |/|
88 88 o | 4: 'F'
89 89 | |
90 90 | o 3: 'E'
91 91 |/
92 92 | o 2: 'C'
93 93 | |
94 94 | o 1: 'B'
95 95 |/
96 96 o 0: 'A'
97 97
98 98 $ cd ..
99 99
100 100
101 101 E onto H - skip of G:
102 102
103 103 $ hg clone -q -u . a a3
104 104 $ cd a3
105 105
106 106 $ hg rebase -s 4 -d 7
107 107 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
108 108
109 109 $ hg tglog
110 110 o 6: 'E'
111 111 |
112 112 @ 5: 'H'
113 113 |
114 114 o 4: 'F'
115 115 |
116 116 | o 3: 'D'
117 117 | |
118 118 | o 2: 'C'
119 119 | |
120 120 | o 1: 'B'
121 121 |/
122 122 o 0: 'A'
123 123
124 124 $ cd ..
125 125
126 126
127 127 F onto E - rebase of a branching point (skip G):
128 128
129 129 $ hg clone -q -u . a a4
130 130 $ cd a4
131 131
132 132 $ hg rebase -s 5 -d 4
133 133 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
134 134
135 135 $ hg tglog
136 136 @ 6: 'H'
137 137 |
138 138 o 5: 'F'
139 139 |
140 140 o 4: 'E'
141 141 |
142 142 | o 3: 'D'
143 143 | |
144 144 | o 2: 'C'
145 145 | |
146 146 | o 1: 'B'
147 147 |/
148 148 o 0: 'A'
149 149
150 150 $ cd ..
151 151
152 152
153 153 G onto H - merged revision having a parent in ancestors of target:
154 154
155 155 $ hg clone -q -u . a a5
156 156 $ cd a5
157 157
158 158 $ hg rebase -s 6 -d 7
159 159 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
160 160
161 161 $ hg tglog
162 162 o 7: 'G'
163 163 |\
164 164 | @ 6: 'H'
165 165 | |
166 166 | o 5: 'F'
167 167 | |
168 168 o | 4: 'E'
169 169 |/
170 170 | o 3: 'D'
171 171 | |
172 172 | o 2: 'C'
173 173 | |
174 174 | o 1: 'B'
175 175 |/
176 176 o 0: 'A'
177 177
178 178 $ cd ..
179 179
180 180
181 181 F onto B - G maintains E as parent:
182 182
183 183 $ hg clone -q -u . a a6
184 184 $ cd a6
185 185
186 186 $ hg rebase -s 5 -d 1
187 187 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
188 188
189 189 $ hg tglog
190 190 @ 7: 'H'
191 191 |
192 192 | o 6: 'G'
193 193 |/|
194 194 o | 5: 'F'
195 195 | |
196 196 | o 4: 'E'
197 197 | |
198 198 | | o 3: 'D'
199 199 | | |
200 200 +---o 2: 'C'
201 201 | |
202 202 o | 1: 'B'
203 203 |/
204 204 o 0: 'A'
205 205
206 206 $ cd ..
207 207
208 208
209 209 These will fail (using --source):
210 210
211 211 G onto F - rebase onto an ancestor:
212 212
213 213 $ hg clone -q -u . a a7
214 214 $ cd a7
215 215
216 216 $ hg rebase -s 6 -d 5
217 217 nothing to rebase
218 218 [1]
219 219
220 220 F onto G - rebase onto a descendant:
221 221
222 222 $ hg rebase -s 5 -d 6
223 223 abort: source is ancestor of destination
224 224 [255]
225 225
226 226 G onto B - merge revision with both parents not in ancestors of target:
227 227
228 228 $ hg rebase -s 6 -d 1
229 229 abort: cannot use revision 6 as base, result would have 3 parents
230 230 [255]
231 231
232 232
233 233 These will abort gracefully (using --base):
234 234
235 235 G onto G - rebase onto same changeset:
236 236
237 237 $ hg rebase -b 6 -d 6
238 nothing to rebase
238 nothing to rebase - eea13746799a is both "base" and destination
239 239 [1]
240 240
241 241 G onto F - rebase onto an ancestor:
242 242
243 243 $ hg rebase -b 6 -d 5
244 244 nothing to rebase
245 245 [1]
246 246
247 247 F onto G - rebase onto a descendant:
248 248
249 249 $ hg rebase -b 5 -d 6
250 nothing to rebase
250 nothing to rebase - "base" 24b6387c8c8c is already an ancestor of destination eea13746799a
251 251 [1]
252 252
253 253 C onto A - rebase onto an ancestor:
254 254
255 255 $ hg rebase -d 0 -s 2
256 256 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-backup.hg (glob)
257 257 $ hg tglog
258 258 o 7: 'D'
259 259 |
260 260 o 6: 'C'
261 261 |
262 262 | @ 5: 'H'
263 263 | |
264 264 | | o 4: 'G'
265 265 | |/|
266 266 | o | 3: 'F'
267 267 |/ /
268 268 | o 2: 'E'
269 269 |/
270 270 | o 1: 'B'
271 271 |/
272 272 o 0: 'A'
273 273
274 274
275 275 Check rebasing public changeset
276 276
277 277 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
278 278 $ hg rebase -d 0 -b 6
279 279 nothing to rebase
280 280 [1]
281 281 $ hg rebase -d 5 -b 6
282 282 abort: can't rebase immutable changeset e1c4361dd923
283 283 (see hg help phases for details)
284 284 [255]
285 285
286 286 $ hg rebase -d 5 -b 6 --keep
287 287
288 288 Check rebasing mutable changeset
289 289 Source phase greater or equal to destination phase: new changeset get the phase of source:
290 290 $ hg rebase -s9 -d0
291 291 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-backup.hg (glob)
292 292 $ hg log --template "{phase}\n" -r 9
293 293 draft
294 294 $ hg rebase -s9 -d1
295 295 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-backup.hg (glob)
296 296 $ hg log --template "{phase}\n" -r 9
297 297 draft
298 298 $ hg phase --force --secret 9
299 299 $ hg rebase -s9 -d0
300 300 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-backup.hg (glob)
301 301 $ hg log --template "{phase}\n" -r 9
302 302 secret
303 303 $ hg rebase -s9 -d1
304 304 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-backup.hg (glob)
305 305 $ hg log --template "{phase}\n" -r 9
306 306 secret
307 307 Source phase lower than destination phase: new changeset get the phase of destination:
308 308 $ hg rebase -s8 -d9
309 309 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-backup.hg (glob)
310 310 $ hg log --template "{phase}\n" -r 'rev(9)'
311 311 secret
312 312
313 313 $ cd ..
314 314
315 315 Test for revset
316 316
317 317 We need a bit different graph
318 318 All destination are B
319 319
320 320 $ hg init ah
321 321 $ cd ah
322 322 $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
323 323 adding changesets
324 324 adding manifests
325 325 adding file changes
326 326 added 9 changesets with 9 changes to 9 files (+2 heads)
327 327 (run 'hg heads' to see heads, 'hg merge' to merge)
328 328 $ hg tglog
329 329 o 8: 'I'
330 330 |
331 331 o 7: 'H'
332 332 |
333 333 o 6: 'G'
334 334 |
335 335 | o 5: 'F'
336 336 | |
337 337 | o 4: 'E'
338 338 |/
339 339 o 3: 'D'
340 340 |
341 341 o 2: 'C'
342 342 |
343 343 | o 1: 'B'
344 344 |/
345 345 o 0: 'A'
346 346
347 347 $ cd ..
348 348
349 349
350 350 Simple case with keep:
351 351
352 352 Source on have two descendant heads but ask for one
353 353
354 354 $ hg clone -q -u . ah ah1
355 355 $ cd ah1
356 356 $ hg rebase -r '2::8' -d 1
357 357 abort: can't remove original changesets with unrebased descendants
358 358 (use --keep to keep original changesets)
359 359 [255]
360 360 $ hg rebase -r '2::8' -d 1 --keep
361 361 $ hg tglog
362 362 o 13: 'I'
363 363 |
364 364 o 12: 'H'
365 365 |
366 366 o 11: 'G'
367 367 |
368 368 o 10: 'D'
369 369 |
370 370 o 9: 'C'
371 371 |
372 372 | o 8: 'I'
373 373 | |
374 374 | o 7: 'H'
375 375 | |
376 376 | o 6: 'G'
377 377 | |
378 378 | | o 5: 'F'
379 379 | | |
380 380 | | o 4: 'E'
381 381 | |/
382 382 | o 3: 'D'
383 383 | |
384 384 | o 2: 'C'
385 385 | |
386 386 o | 1: 'B'
387 387 |/
388 388 o 0: 'A'
389 389
390 390
391 391 $ cd ..
392 392
393 393 Base on have one descendant heads we ask for but common ancestor have two
394 394
395 395 $ hg clone -q -u . ah ah2
396 396 $ cd ah2
397 397 $ hg rebase -r '3::8' -d 1
398 398 abort: can't remove original changesets with unrebased descendants
399 399 (use --keep to keep original changesets)
400 400 [255]
401 401 $ hg rebase -r '3::8' -d 1 --keep
402 402 $ hg tglog
403 403 o 12: 'I'
404 404 |
405 405 o 11: 'H'
406 406 |
407 407 o 10: 'G'
408 408 |
409 409 o 9: 'D'
410 410 |
411 411 | o 8: 'I'
412 412 | |
413 413 | o 7: 'H'
414 414 | |
415 415 | o 6: 'G'
416 416 | |
417 417 | | o 5: 'F'
418 418 | | |
419 419 | | o 4: 'E'
420 420 | |/
421 421 | o 3: 'D'
422 422 | |
423 423 | o 2: 'C'
424 424 | |
425 425 o | 1: 'B'
426 426 |/
427 427 o 0: 'A'
428 428
429 429
430 430 $ cd ..
431 431
432 432 rebase subset
433 433
434 434 $ hg clone -q -u . ah ah3
435 435 $ cd ah3
436 436 $ hg rebase -r '3::7' -d 1
437 437 abort: can't remove original changesets with unrebased descendants
438 438 (use --keep to keep original changesets)
439 439 [255]
440 440 $ hg rebase -r '3::7' -d 1 --keep
441 441 $ hg tglog
442 442 o 11: 'H'
443 443 |
444 444 o 10: 'G'
445 445 |
446 446 o 9: 'D'
447 447 |
448 448 | o 8: 'I'
449 449 | |
450 450 | o 7: 'H'
451 451 | |
452 452 | o 6: 'G'
453 453 | |
454 454 | | o 5: 'F'
455 455 | | |
456 456 | | o 4: 'E'
457 457 | |/
458 458 | o 3: 'D'
459 459 | |
460 460 | o 2: 'C'
461 461 | |
462 462 o | 1: 'B'
463 463 |/
464 464 o 0: 'A'
465 465
466 466
467 467 $ cd ..
468 468
469 469 rebase subset with multiple head
470 470
471 471 $ hg clone -q -u . ah ah4
472 472 $ cd ah4
473 473 $ hg rebase -r '3::(7+5)' -d 1
474 474 abort: can't remove original changesets with unrebased descendants
475 475 (use --keep to keep original changesets)
476 476 [255]
477 477 $ hg rebase -r '3::(7+5)' -d 1 --keep
478 478 $ hg tglog
479 479 o 13: 'H'
480 480 |
481 481 o 12: 'G'
482 482 |
483 483 | o 11: 'F'
484 484 | |
485 485 | o 10: 'E'
486 486 |/
487 487 o 9: 'D'
488 488 |
489 489 | o 8: 'I'
490 490 | |
491 491 | o 7: 'H'
492 492 | |
493 493 | o 6: 'G'
494 494 | |
495 495 | | o 5: 'F'
496 496 | | |
497 497 | | o 4: 'E'
498 498 | |/
499 499 | o 3: 'D'
500 500 | |
501 501 | o 2: 'C'
502 502 | |
503 503 o | 1: 'B'
504 504 |/
505 505 o 0: 'A'
506 506
507 507
508 508 $ cd ..
509 509
510 510 More advanced tests
511 511
512 512 rebase on ancestor with revset
513 513
514 514 $ hg clone -q -u . ah ah5
515 515 $ cd ah5
516 516 $ hg rebase -r '6::' -d 2
517 517 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-backup.hg (glob)
518 518 $ hg tglog
519 519 o 8: 'I'
520 520 |
521 521 o 7: 'H'
522 522 |
523 523 o 6: 'G'
524 524 |
525 525 | o 5: 'F'
526 526 | |
527 527 | o 4: 'E'
528 528 | |
529 529 | o 3: 'D'
530 530 |/
531 531 o 2: 'C'
532 532 |
533 533 | o 1: 'B'
534 534 |/
535 535 o 0: 'A'
536 536
537 537 $ cd ..
538 538
539 539
540 540 rebase with multiple root.
541 541 We rebase E and G on B
542 542 We would expect heads are I, F if it was supported
543 543
544 544 $ hg clone -q -u . ah ah6
545 545 $ cd ah6
546 546 $ hg rebase -r '(4+6)::' -d 1
547 547 saved backup bundle to $TESTTMP/ah6/.hg/strip-backup/3d8a618087a7-backup.hg (glob)
548 548 $ hg tglog
549 549 o 8: 'I'
550 550 |
551 551 o 7: 'H'
552 552 |
553 553 o 6: 'G'
554 554 |
555 555 | o 5: 'F'
556 556 | |
557 557 | o 4: 'E'
558 558 |/
559 559 | o 3: 'D'
560 560 | |
561 561 | o 2: 'C'
562 562 | |
563 563 o | 1: 'B'
564 564 |/
565 565 o 0: 'A'
566 566
567 567 $ cd ..
568 568
569 569 More complex rebase with multiple roots
570 570 each root have a different common ancestor with the destination and this is a detach
571 571
572 572 (setup)
573 573
574 574 $ hg clone -q -u . a a8
575 575 $ cd a8
576 576 $ echo I > I
577 577 $ hg add I
578 578 $ hg commit -m I
579 579 $ hg up 4
580 580 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
581 581 $ echo I > J
582 582 $ hg add J
583 583 $ hg commit -m J
584 584 created new head
585 585 $ echo I > K
586 586 $ hg add K
587 587 $ hg commit -m K
588 588 $ hg tglog
589 589 @ 10: 'K'
590 590 |
591 591 o 9: 'J'
592 592 |
593 593 | o 8: 'I'
594 594 | |
595 595 | o 7: 'H'
596 596 | |
597 597 +---o 6: 'G'
598 598 | |/
599 599 | o 5: 'F'
600 600 | |
601 601 o | 4: 'E'
602 602 |/
603 603 | o 3: 'D'
604 604 | |
605 605 | o 2: 'C'
606 606 | |
607 607 | o 1: 'B'
608 608 |/
609 609 o 0: 'A'
610 610
611 611 (actual test)
612 612
613 613 $ hg rebase --dest 'desc(G)' --rev 'desc(K) + desc(I)'
614 614 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/23a4ace37988-backup.hg (glob)
615 615 $ hg log --rev 'children(desc(G))'
616 616 changeset: 9:adb617877056
617 617 parent: 6:eea13746799a
618 618 user: test
619 619 date: Thu Jan 01 00:00:00 1970 +0000
620 620 summary: I
621 621
622 622 changeset: 10:882431a34a0e
623 623 tag: tip
624 624 parent: 6:eea13746799a
625 625 user: test
626 626 date: Thu Jan 01 00:00:00 1970 +0000
627 627 summary: K
628 628
629 629 $ hg tglog
630 630 @ 10: 'K'
631 631 |
632 632 | o 9: 'I'
633 633 |/
634 634 | o 8: 'J'
635 635 | |
636 636 | | o 7: 'H'
637 637 | | |
638 638 o---+ 6: 'G'
639 639 |/ /
640 640 | o 5: 'F'
641 641 | |
642 642 o | 4: 'E'
643 643 |/
644 644 | o 3: 'D'
645 645 | |
646 646 | o 2: 'C'
647 647 | |
648 648 | o 1: 'B'
649 649 |/
650 650 o 0: 'A'
651 651
General Comments 0
You need to be logged in to leave comments. Login now