773 return _dobackout(ui, repo, node, rev, **opts) |
773 return _dobackout(ui, repo, node, rev, **opts) |
774 |
774 |
775 |
775 |
776 def _dobackout(ui, repo, node=None, rev=None, **opts): |
776 def _dobackout(ui, repo, node=None, rev=None, **opts): |
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge']) |
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge']) |
778 opts = pycompat.byteskwargs(opts) |
|
779 |
778 |
780 if rev and node: |
779 if rev and node: |
781 raise error.InputError(_(b"please specify just one revision")) |
780 raise error.InputError(_(b"please specify just one revision")) |
782 |
781 |
783 if not rev: |
782 if not rev: |
784 rev = node |
783 rev = node |
785 |
784 |
786 if not rev: |
785 if not rev: |
787 raise error.InputError(_(b"please specify a revision to backout")) |
786 raise error.InputError(_(b"please specify a revision to backout")) |
788 |
787 |
789 date = opts.get(b'date') |
788 date = opts.get('date') |
790 if date: |
789 if date: |
791 opts[b'date'] = dateutil.parsedate(date) |
790 opts['date'] = dateutil.parsedate(date) |
792 |
791 |
793 cmdutil.checkunfinished(repo) |
792 cmdutil.checkunfinished(repo) |
794 cmdutil.bailifchanged(repo) |
793 cmdutil.bailifchanged(repo) |
795 ctx = logcmdutil.revsingle(repo, rev) |
794 ctx = logcmdutil.revsingle(repo, rev) |
796 node = ctx.node() |
795 node = ctx.node() |
803 |
802 |
804 p1, p2 = repo.changelog.parents(node) |
803 p1, p2 = repo.changelog.parents(node) |
805 if p1 == repo.nullid: |
804 if p1 == repo.nullid: |
806 raise error.InputError(_(b'cannot backout a change with no parents')) |
805 raise error.InputError(_(b'cannot backout a change with no parents')) |
807 if p2 != repo.nullid: |
806 if p2 != repo.nullid: |
808 if not opts.get(b'parent'): |
807 if not opts.get('parent'): |
809 raise error.InputError(_(b'cannot backout a merge changeset')) |
808 raise error.InputError(_(b'cannot backout a merge changeset')) |
810 p = repo.lookup(opts[b'parent']) |
809 p = repo.lookup(opts['parent']) |
811 if p not in (p1, p2): |
810 if p not in (p1, p2): |
812 raise error.InputError( |
811 raise error.InputError( |
813 _(b'%s is not a parent of %s') % (short(p), short(node)) |
812 _(b'%s is not a parent of %s') % (short(p), short(node)) |
814 ) |
813 ) |
815 parent = p |
814 parent = p |
816 else: |
815 else: |
817 if opts.get(b'parent'): |
816 if opts.get('parent'): |
818 raise error.InputError( |
817 raise error.InputError( |
819 _(b'cannot use --parent on non-merge changeset') |
818 _(b'cannot use --parent on non-merge changeset') |
820 ) |
819 ) |
821 parent = p1 |
820 parent = p1 |
822 |
821 |
823 # the backout should appear on the same branch |
822 # the backout should appear on the same branch |
824 branch = repo.dirstate.branch() |
823 branch = repo.dirstate.branch() |
825 bheads = repo.branchheads(branch) |
824 bheads = repo.branchheads(branch) |
826 rctx = scmutil.revsingle(repo, hex(parent)) |
825 rctx = scmutil.revsingle(repo, hex(parent)) |
827 if not opts.get(b'merge') and op1 != node: |
826 if not opts.get('merge') and op1 != node: |
828 with repo.transaction(b"backout"): |
827 with repo.transaction(b"backout"): |
829 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')} |
828 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')} |
830 with ui.configoverride(overrides, b'backout'): |
829 with ui.configoverride(overrides, b'backout'): |
831 stats = mergemod.back_out(ctx, parent=repo[parent]) |
830 stats = mergemod.back_out(ctx, parent=repo[parent]) |
832 repo.setparents(op1, op2) |
831 repo.setparents(op1, op2) |
833 hg._showstats(repo, stats) |
832 hg._showstats(repo, stats) |
834 if stats.unresolvedcount: |
833 if stats.unresolvedcount: |
839 else: |
838 else: |
840 hg.clean(repo, node, show_stats=False) |
839 hg.clean(repo, node, show_stats=False) |
841 repo.dirstate.setbranch(branch, repo.currenttransaction()) |
840 repo.dirstate.setbranch(branch, repo.currenttransaction()) |
842 cmdutil.revert(ui, repo, rctx) |
841 cmdutil.revert(ui, repo, rctx) |
843 |
842 |
844 if opts.get(b'no_commit'): |
843 if opts.get('no_commit'): |
845 msg = _(b"changeset %s backed out, don't forget to commit.\n") |
844 msg = _(b"changeset %s backed out, don't forget to commit.\n") |
846 ui.status(msg % short(node)) |
845 ui.status(msg % short(node)) |
847 return 0 |
846 return 0 |
848 |
847 |
849 def commitfunc(ui, repo, message, match, opts): |
848 def commitfunc(ui, repo, message, match, opts): |
860 ) |
859 ) |
861 |
860 |
862 # save to detect changes |
861 # save to detect changes |
863 tip = repo.changelog.tip() |
862 tip = repo.changelog.tip() |
864 |
863 |
865 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts) |
864 newnode = cmdutil.commit( |
|
865 ui, repo, commitfunc, [], pycompat.byteskwargs(opts) |
|
866 ) |
866 if not newnode: |
867 if not newnode: |
867 ui.status(_(b"nothing changed\n")) |
868 ui.status(_(b"nothing changed\n")) |
868 return 1 |
869 return 1 |
869 cmdutil.commitstatus(repo, newnode, branch, bheads, tip) |
870 cmdutil.commitstatus(repo, newnode, branch, bheads, tip) |
870 |
871 |
873 |
874 |
874 ui.status( |
875 ui.status( |
875 _(b'changeset %s backs out changeset %s\n') |
876 _(b'changeset %s backs out changeset %s\n') |
876 % (nice(newnode), nice(node)) |
877 % (nice(newnode), nice(node)) |
877 ) |
878 ) |
878 if opts.get(b'merge') and op1 != node: |
879 if opts.get('merge') and op1 != node: |
879 hg.clean(repo, op1, show_stats=False) |
880 hg.clean(repo, op1, show_stats=False) |
880 ui.status(_(b'merging with changeset %s\n') % nice(newnode)) |
881 ui.status(_(b'merging with changeset %s\n') % nice(newnode)) |
881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')} |
882 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')} |
882 with ui.configoverride(overrides, b'backout'): |
883 with ui.configoverride(overrides, b'backout'): |
883 return hg.merge(repo[b'tip']) |
884 return hg.merge(repo[b'tip']) |
884 return 0 |
885 return 0 |
885 |
886 |
886 |
887 |