diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -3176,22 +3176,25 @@ def _performrevert(repo, parents, ctx, n configprefix='revert.interactive.') diffopts.nodates = True diffopts.git = True - operation = 'discard' - reversehunks = True - if node != parent: - operation = 'apply' - reversehunks = False - if reversehunks: + operation = 'apply' + if node == parent: + if repo.ui.configbool('experimental', + 'revert.interactive.select-to-keep'): + operation = 'keep' + else: + operation = 'discard' + + if operation == 'apply': + diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) + else: diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts) - else: - diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) originalchunks = patch.parsepatch(diff) try: chunks, opts = recordfilter(repo.ui, originalchunks, operation=operation) - if reversehunks: + if operation == 'discard': chunks = patch.reversehunks(chunks) except error.PatchError as err: @@ -3205,6 +3208,7 @@ def _performrevert(repo, parents, ctx, n # chunks are serialized per file, but files aren't sorted for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))): prntstatusmsg('revert', f) + files = set() for c in chunks: if ishunk(c): abs = c.header.filename() @@ -3214,6 +3218,10 @@ def _performrevert(repo, parents, ctx, n bakname = scmutil.backuppath(repo.ui, repo, abs) util.copyfile(target, bakname) tobackup.remove(abs) + if abs not in files: + files.add(abs) + if operation == 'keep': + checkout(abs) c.write(fp) dopatch = fp.tell() fp.seek(0) diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -595,6 +595,9 @@ coreconfigitem('experimental', 'remotena coreconfigitem('experimental', 'removeemptydirs', default=True, ) +coreconfigitem('experimental', 'revert.interactive.select-to-keep', + default=False, +) coreconfigitem('experimental', 'revisions.prefixhexnode', default=False, ) diff --git a/mercurial/crecord.py b/mercurial/crecord.py --- a/mercurial/crecord.py +++ b/mercurial/crecord.py @@ -566,6 +566,7 @@ def testchunkselector(testfn, ui, header _headermessages = { # {operation: text} 'apply': _('Select hunks to apply'), 'discard': _('Select hunks to discard'), + 'keep': _('Select hunks to keep'), None: _('Select hunks to record'), } diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -1012,11 +1012,13 @@ def getmessages(): 'multiple': { 'apply': _("apply change %d/%d to '%s'?"), 'discard': _("discard change %d/%d to '%s'?"), + 'keep': _("keep change %d/%d to '%s'?"), 'record': _("record change %d/%d to '%s'?"), }, 'single': { 'apply': _("apply this change to '%s'?"), 'discard': _("discard this change to '%s'?"), + 'keep': _("keep this change to '%s'?"), 'record': _("record this change to '%s'?"), }, 'help': { @@ -1040,6 +1042,16 @@ def getmessages(): '$$ Discard &all changes to all remaining files' '$$ &Quit, discarding no changes' '$$ &? (display help)'), + 'keep': _('[Ynesfdaq?]' + '$$ &Yes, keep this change' + '$$ &No, skip this change' + '$$ &Edit this change manually' + '$$ &Skip remaining changes to this file' + '$$ Keep remaining changes to this &file' + '$$ &Done, skip remaining changes and files' + '$$ Keep &all changes to all remaining files' + '$$ &Quit, keeping all changes' + '$$ &? (display help)'), 'record': _('[Ynesfdaq?]' '$$ &Yes, record this change' '$$ &No, skip this change' diff --git a/tests/test-revert-interactive.t b/tests/test-revert-interactive.t --- a/tests/test-revert-interactive.t +++ b/tests/test-revert-interactive.t @@ -444,4 +444,52 @@ Prompt before undeleting file(issue6008) > EOF add back removed file a (Yn)? n $ ls + $ hg revert -a + undeleting a $ cd .. + +Test "keep" mode + + $ cat <> $HGRCPATH + > [experimental] + > revert.interactive.select-to-keep = true + > EOF + + $ cd repo + $ printf "x\na\ny\n" > a + $ hg diff + diff -r cb9a9f314b8b a + --- a/a Thu Jan 01 00:00:00 1970 +0000 + +++ b/a Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +1,3 @@ + +x + a + +y + $ cat > $TESTTMP/editor.sh << '__EOF__' + > echo "+new line" >> "$1" + > __EOF__ + + $ HGEDITOR="\"sh\" \"${TESTTMP}/editor.sh\"" hg revert -i < y + > n + > e + > EOF + diff --git a/a b/a + 2 hunks, 2 lines changed + examine changes to 'a'? [Ynesfdaq?] y + + @@ -1,1 +1,2 @@ + +x + a + keep change 1/2 to 'a'? [Ynesfdaq?] n + + @@ -1,1 +2,2 @@ + a + +y + keep change 2/2 to 'a'? [Ynesfdaq?] e + + reverting a + $ cat a + a + y + new line