89 name = fp.readline().strip() |
89 name = fp.readline().strip() |
90 wctx = fp.readline().strip() |
90 wctx = fp.readline().strip() |
91 pendingctx = fp.readline().strip() |
91 pendingctx = fp.readline().strip() |
92 parents = [bin(h) for h in fp.readline().split()] |
92 parents = [bin(h) for h in fp.readline().split()] |
93 stripnodes = [bin(h) for h in fp.readline().split()] |
93 stripnodes = [bin(h) for h in fp.readline().split()] |
94 unknownfiles = fp.readline()[:-1].split('\0') |
|
95 finally: |
94 finally: |
96 fp.close() |
95 fp.close() |
97 |
96 |
98 obj = cls() |
97 obj = cls() |
99 obj.name = name |
98 obj.name = name |
100 obj.wctx = repo[bin(wctx)] |
99 obj.wctx = repo[bin(wctx)] |
101 obj.pendingctx = repo[bin(pendingctx)] |
100 obj.pendingctx = repo[bin(pendingctx)] |
102 obj.parents = parents |
101 obj.parents = parents |
103 obj.stripnodes = stripnodes |
102 obj.stripnodes = stripnodes |
104 obj.unknownfiles = unknownfiles |
|
105 |
103 |
106 return obj |
104 return obj |
107 |
105 |
108 @classmethod |
106 @classmethod |
109 def save(cls, repo, name, originalwctx, pendingctx, stripnodes, |
107 def save(cls, repo, name, originalwctx, pendingctx, stripnodes): |
110 unknownfiles): |
|
111 fp = repo.opener(cls._filename, 'wb') |
108 fp = repo.opener(cls._filename, 'wb') |
112 fp.write('%i\n' % cls._version) |
109 fp.write('%i\n' % cls._version) |
113 fp.write('%s\n' % name) |
110 fp.write('%s\n' % name) |
114 fp.write('%s\n' % hex(originalwctx.node())) |
111 fp.write('%s\n' % hex(originalwctx.node())) |
115 fp.write('%s\n' % hex(pendingctx.node())) |
112 fp.write('%s\n' % hex(pendingctx.node())) |
116 fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()])) |
113 fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()])) |
117 fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes])) |
114 fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes])) |
118 fp.write('%s\n' % '\0'.join(unknownfiles)) |
|
119 fp.close() |
115 fp.close() |
120 |
116 |
121 @classmethod |
117 @classmethod |
122 def clear(cls, repo): |
118 def clear(cls, repo): |
123 util.unlinkpath(repo.join(cls._filename), ignoremissing=True) |
119 util.unlinkpath(repo.join(cls._filename), ignoremissing=True) |
377 repo.join('unshelverebasestate')) |
373 repo.join('unshelverebasestate')) |
378 raise |
374 raise |
379 |
375 |
380 lock = repo.lock() |
376 lock = repo.lock() |
381 |
377 |
382 mergefiles(ui, repo, state.wctx, state.pendingctx, state.unknownfiles) |
378 mergefiles(ui, repo, state.wctx, state.pendingctx) |
383 |
379 |
384 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') |
380 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') |
385 shelvedstate.clear(repo) |
381 shelvedstate.clear(repo) |
386 ui.warn(_("unshelve of '%s' aborted\n") % state.name) |
382 ui.warn(_("unshelve of '%s' aborted\n") % state.name) |
387 finally: |
383 finally: |
388 lockmod.release(lock, wlock) |
384 lockmod.release(lock, wlock) |
389 |
385 |
390 def mergefiles(ui, repo, wctx, shelvectx, unknownfiles): |
386 def mergefiles(ui, repo, wctx, shelvectx): |
391 """updates to wctx and merges the changes from shelvectx into the |
387 """updates to wctx and merges the changes from shelvectx into the |
392 dirstate. drops any files in unknownfiles from the dirstate.""" |
388 dirstate.""" |
393 oldquiet = ui.quiet |
389 oldquiet = ui.quiet |
394 try: |
390 try: |
395 ui.quiet = True |
391 ui.quiet = True |
396 hg.update(repo, wctx.node()) |
392 hg.update(repo, wctx.node()) |
397 files = [] |
393 files = [] |
398 files.extend(shelvectx.files()) |
394 files.extend(shelvectx.files()) |
399 files.extend(shelvectx.parents()[0].files()) |
395 files.extend(shelvectx.parents()[0].files()) |
|
396 |
|
397 # revert will overwrite unknown files, so move them out of the way |
|
398 m, a, r, d, u = repo.status(unknown=True)[:5] |
|
399 for file in u: |
|
400 if file in files: |
|
401 util.rename(file, file + ".orig") |
400 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(), |
402 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(), |
401 *pathtofiles(repo, files), |
403 *pathtofiles(repo, files), |
402 **{'no_backup': True}) |
404 **{'no_backup': True}) |
403 finally: |
405 finally: |
404 ui.quiet = oldquiet |
406 ui.quiet = oldquiet |
405 |
|
406 # Send untracked files back to being untracked |
|
407 dirstate = repo.dirstate |
|
408 for f in unknownfiles: |
|
409 dirstate.drop(f) |
|
410 |
407 |
411 def unshelvecleanup(ui, repo, name, opts): |
408 def unshelvecleanup(ui, repo, name, opts): |
412 """remove related files after an unshelve""" |
409 """remove related files after an unshelve""" |
413 if not opts['keep']: |
410 if not opts['keep']: |
414 for filetype in 'hg files patch'.split(): |
411 for filetype in 'hg files patch'.split(): |
444 shelvectx = repo['tip'] |
441 shelvectx = repo['tip'] |
445 if not shelvectx in state.pendingctx.children(): |
442 if not shelvectx in state.pendingctx.children(): |
446 # rebase was a no-op, so it produced no child commit |
443 # rebase was a no-op, so it produced no child commit |
447 shelvectx = state.pendingctx |
444 shelvectx = state.pendingctx |
448 |
445 |
449 mergefiles(ui, repo, state.wctx, shelvectx, state.unknownfiles) |
446 mergefiles(ui, repo, state.wctx, shelvectx) |
450 |
447 |
451 state.stripnodes.append(shelvectx.node()) |
448 state.stripnodes.append(shelvectx.node()) |
452 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') |
449 repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') |
453 shelvedstate.clear(repo) |
450 shelvedstate.clear(repo) |
454 unshelvecleanup(ui, repo, state.name, opts) |
451 unshelvecleanup(ui, repo, state.name, opts) |
536 # where tmpwctx is an optional commit with the user's pending changes |
533 # where tmpwctx is an optional commit with the user's pending changes |
537 # and shelvectx is the unshelved changes. Then we merge it all down |
534 # and shelvectx is the unshelved changes. Then we merge it all down |
538 # to the original wctx. |
535 # to the original wctx. |
539 |
536 |
540 # Store pending changes in a commit |
537 # Store pending changes in a commit |
541 m, a, r, d, u = repo.status(unknown=True)[:5] |
538 m, a, r, d = repo.status()[:4] |
542 if m or a or r or d or u: |
539 if m or a or r or d: |
543 def commitfunc(ui, repo, message, match, opts): |
540 def commitfunc(ui, repo, message, match, opts): |
544 hasmq = util.safehasattr(repo, 'mq') |
541 hasmq = util.safehasattr(repo, 'mq') |
545 if hasmq: |
542 if hasmq: |
546 saved, repo.mq.checkapplied = repo.mq.checkapplied, False |
543 saved, repo.mq.checkapplied = repo.mq.checkapplied, False |
547 |
544 |
586 except error.InterventionRequired: |
582 except error.InterventionRequired: |
587 tr.close() |
583 tr.close() |
588 |
584 |
589 stripnodes = [repo.changelog.node(rev) |
585 stripnodes = [repo.changelog.node(rev) |
590 for rev in xrange(oldtiprev, len(repo))] |
586 for rev in xrange(oldtiprev, len(repo))] |
591 shelvedstate.save(repo, basename, wctx, tmpwctx, stripnodes, u) |
587 shelvedstate.save(repo, basename, wctx, tmpwctx, stripnodes) |
592 |
588 |
593 util.rename(repo.join('rebasestate'), |
589 util.rename(repo.join('rebasestate'), |
594 repo.join('unshelverebasestate')) |
590 repo.join('unshelverebasestate')) |
595 raise error.InterventionRequired( |
591 raise error.InterventionRequired( |
596 _("unresolved conflicts (see 'hg resolve', then " |
592 _("unresolved conflicts (see 'hg resolve', then " |
601 |
597 |
602 if not shelvectx in tmpwctx.children(): |
598 if not shelvectx in tmpwctx.children(): |
603 # rebase was a no-op, so it produced no child commit |
599 # rebase was a no-op, so it produced no child commit |
604 shelvectx = tmpwctx |
600 shelvectx = tmpwctx |
605 |
601 |
606 mergefiles(ui, repo, wctx, shelvectx, u) |
602 mergefiles(ui, repo, wctx, shelvectx) |
607 shelvedstate.clear(repo) |
603 shelvedstate.clear(repo) |
608 |
604 |
609 # The transaction aborting will strip all the commits for us, |
605 # The transaction aborting will strip all the commits for us, |
610 # but it doesn't update the inmemory structures, so addchangegroup |
606 # but it doesn't update the inmemory structures, so addchangegroup |
611 # hooks still fire and try to operate on the missing commits. |
607 # hooks still fire and try to operate on the missing commits. |