diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -296,6 +296,9 @@ coreconfigitem('merge', 'followcopies', default=True, ) +coreconfigitem('merge', 'abortonfailure', + default=False, +) coreconfigitem('pager', 'ignore', default=list, ) diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -514,13 +514,30 @@ repo.ui.status(_('running merge tool %s for file %s\n') % (tool, fcd.path())) repo.ui.debug('launching merge tool: %s\n' % cmd) - r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool') + onerr = getmergeerrorhandler(repo) + r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool', + onerr=onerr) repo.ui.debug('merge tool returned: %s\n' % r) return True, r, False finally: util.unlink(b) util.unlink(c) +def getmergeerrorhandler(repo): + """ + Traditionally, the merge process attempts to merge all unresolved files + using the merge tool of choice, regardless of whether previous file merge + attempts succeeded or failed. Setting the merge.abortonfailure option to + True changes this behavior so that a failed merge will immediately abort + the merge operation, leaving the user in a normal unresolved merge state. + """ + onerr = None + if repo.ui.configbool('merge', 'abortonfailure'): + def onerr(*args): + msg = _('merge aborted due to nonrzero mergetool return code') + raise error.Abort(msg) + return onerr + def _formatconflictmarker(repo, ctx, template, label, pad): """Applies the given template to the ctx, prefixed by the label. diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -1239,6 +1239,14 @@ different contents. Similar to ``merge.checkignored``, except for files that are not ignored. (default: ``abort``) +``abortonfailure`` + Traditionally, the merge process attempts to merge all unresolved files + using the merge tool of choice, regardless of whether previous file merge + attempts succeeded or failed. Setting the ``merge.abortonfailure`` option to + True changes this behavior so that a failed merge will immediately abort + the merge operation, leaving the user in a normal unresolved merge state. + (default: ``False``) + ``merge-patterns`` ------------------ diff --git a/tests/test-filemerge-abort.t b/tests/test-filemerge-abort.t new file mode 100644 --- /dev/null +++ b/tests/test-filemerge-abort.t @@ -0,0 +1,36 @@ + $ cat >> $HGRCPATH < [extensions] + > rebase= + > [phases] + > publish=False + > [merge] + > abortonfailure=True + > EOF + + $ hg init repo + $ cd repo + $ echo a > a + $ echo b > b + $ hg commit -qAm ab + $ echo c >> a + $ echo c >> b + $ hg commit -qAm c + $ hg up -q .^ + $ echo d >> a + $ echo d >> b + $ hg commit -qAm d + $ hg rebase -s 1 -d 2 --tool false + rebasing 1:1f28a51c3c9b "c" + merging a + merging b + abort: merge aborted due to nonrzero mergetool return code + [255] + $ hg rebase --abort + rebase aborted + $ hg rebase -s 1 -d 2 --tool true + rebasing 1:1f28a51c3c9b "c" + merging a + merging b + note: rebase of 1:1f28a51c3c9b created no changes to commit + saved backup bundle to $TESTTMP/repo/.hg/strip-backup/1f28a51c3c9b-5312ccf5-rebase.hg (glob) +