630 if opts.get('parent'): |
630 if opts.get('parent'): |
631 raise error.Abort(_('cannot use --parent on non-merge changeset')) |
631 raise error.Abort(_('cannot use --parent on non-merge changeset')) |
632 parent = p1 |
632 parent = p1 |
633 |
633 |
634 # the backout should appear on the same branch |
634 # the backout should appear on the same branch |
635 try: |
635 branch = repo.dirstate.branch() |
636 branch = repo.dirstate.branch() |
636 bheads = repo.branchheads(branch) |
637 bheads = repo.branchheads(branch) |
637 rctx = scmutil.revsingle(repo, hex(parent)) |
638 rctx = scmutil.revsingle(repo, hex(parent)) |
638 if not opts.get('merge') and op1 != node: |
639 if not opts.get('merge') and op1 != node: |
639 dsguard = cmdutil.dirstateguard(repo, 'backout') |
640 dsguard = cmdutil.dirstateguard(repo, 'backout') |
640 try: |
641 try: |
641 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), |
642 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), |
642 'backout') |
643 'backout') |
643 stats = mergemod.update(repo, parent, True, True, node, False) |
644 stats = mergemod.update(repo, parent, True, True, node, False) |
644 repo.setparents(op1, op2) |
645 repo.setparents(op1, op2) |
645 dsguard.close() |
646 dsguard.close() |
646 hg._showstats(repo, stats) |
647 hg._showstats(repo, stats) |
647 if stats[3]: |
648 if stats[3]: |
648 repo.ui.status(_("use 'hg resolve' to retry unresolved " |
649 repo.ui.status(_("use 'hg resolve' to retry unresolved " |
649 "file merges\n")) |
650 "file merges\n")) |
650 return 1 |
651 return 1 |
651 elif not commit: |
652 elif not commit: |
652 msg = _("changeset %s backed out, " |
653 msg = _("changeset %s backed out, " |
653 "don't forget to commit.\n") |
654 "don't forget to commit.\n") |
654 ui.status(msg % short(node)) |
655 ui.status(msg % short(node)) |
655 return 0 |
656 return 0 |
656 finally: |
657 finally: |
657 ui.setconfig('ui', 'forcemerge', '', '') |
658 ui.setconfig('ui', 'forcemerge', '', '') |
658 lockmod.release(dsguard) |
659 lockmod.release(dsguard) |
659 else: |
660 else: |
660 hg.clean(repo, node, show_stats=False) |
661 hg.clean(repo, node, show_stats=False) |
661 repo.dirstate.setbranch(branch) |
662 repo.dirstate.setbranch(branch) |
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents()) |
663 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents()) |
663 |
664 |
664 |
665 |
665 def commitfunc(ui, repo, message, match, opts): |
666 def commitfunc(ui, repo, message, match, opts): |
666 editform = 'backout' |
667 editform = 'backout' |
667 e = cmdutil.getcommiteditor(editform=editform, **opts) |
668 e = cmdutil.getcommiteditor(editform=editform, **opts) |
668 if not message: |
669 if not message: |
669 # we don't translate commit messages |
670 # we don't translate commit messages |
670 message = "Backed out changeset %s" % short(node) |
671 message = "Backed out changeset %s" % short(node) |
671 e = cmdutil.getcommiteditor(edit=True, editform=editform) |
672 e = cmdutil.getcommiteditor(edit=True, editform=editform) |
672 return repo.commit(message, opts.get('user'), opts.get('date'), |
673 return repo.commit(message, opts.get('user'), opts.get('date'), |
673 match, editor=e) |
674 match, editor=e) |
674 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts) |
675 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts) |
675 if not newnode: |
676 if not newnode: |
676 ui.status(_("nothing changed\n")) |
677 ui.status(_("nothing changed\n")) |
677 return 1 |
678 return 1 |
678 cmdutil.commitstatus(repo, newnode, branch, bheads) |
679 cmdutil.commitstatus(repo, newnode, branch, bheads) |
679 |
680 |
680 def nice(node): |
681 def nice(node): |
681 return '%d:%s' % (repo.changelog.rev(node), short(node)) |
682 return '%d:%s' % (repo.changelog.rev(node), short(node)) |
682 ui.status(_('changeset %s backs out changeset %s\n') % |
683 ui.status(_('changeset %s backs out changeset %s\n') % |
683 (nice(repo.changelog.tip()), nice(node))) |
684 (nice(repo.changelog.tip()), nice(node))) |
684 if opts.get('merge') and op1 != node: |
685 if opts.get('merge') and op1 != node: |
685 hg.clean(repo, op1, show_stats=False) |
686 hg.clean(repo, op1, show_stats=False) |
686 ui.status(_('merging with changeset %s\n') |
687 ui.status(_('merging with changeset %s\n') |
687 % nice(repo.changelog.tip())) |
688 % nice(repo.changelog.tip())) |
688 try: |
689 try: |
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), |
690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), |
690 'backout') |
691 'backout') |
691 return hg.merge(repo, hex(repo.changelog.tip())) |
692 return hg.merge(repo, hex(repo.changelog.tip())) |
692 finally: |
693 finally: |
693 ui.setconfig('ui', 'forcemerge', '', '') |
694 ui.setconfig('ui', 'forcemerge', '', '') |
|
695 finally: |
|
696 # TODO: get rid of this meaningless try/finally enclosing. |
|
697 # this is kept only to reduce changes in a patch. |
|
698 pass |
|
699 return 0 |
694 return 0 |
700 |
695 |
701 @command('bisect', |
696 @command('bisect', |
702 [('r', 'reset', False, _('reset bisect state')), |
697 [('r', 'reset', False, _('reset bisect state')), |
703 ('g', 'good', False, _('mark changeset good')), |
698 ('g', 'good', False, _('mark changeset good')), |