diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -6154,6 +6154,7 @@ [('C', 'clean', None, _('discard uncommitted changes (no backup)')), ('c', 'check', None, _('require clean working directory')), ('m', 'merge', None, _('merge uncommitted changes')), + ('', 'abort', False, _('abort interrupted update')), ('d', 'date', '', _('tipmost revision matching date'), _('DATE')), ('r', 'rev', '', _('revision'), _('REV')) ] + mergetoolopts, @@ -6220,6 +6221,7 @@ clean = opts.get(r'clean') check = opts.get(r'check') merge = opts.get(r'merge') + abort = opts.get(r'abort') if rev and node: raise error.Abort(_("please specify just one revision")) @@ -6245,6 +6247,8 @@ updatecheck = 'none' with repo.wlock(): + if abort: + return hg.abortupdate(ui, repo) cmdutil.clearunfinished(repo) if date: rev = cmdutil.finddate(ui, repo, date) diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -984,6 +984,35 @@ _showstats(repo, stats) return stats.unresolvedcount > 0 +def _unmarkandresolvelocal(ui, repo , ms): + """Helper for abortupdate(). This unmarks partially resolved files and then + resolves the update generated conflicts.""" + wctx = repo[None] + for f in ms: + ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED) + try: + overrides = {('ui', 'forcemerge'): ':local'} + with ui.configoverride(overrides, 'resolve'): + ms.preresolve(f, wctx) + ms.resolve(f, wctx) + finally: + ms.commit() + +def abortupdate(ui, repo): + """logic to abort an conflicted update""" + ms = mergemod.mergestate.read(repo) + if not ms.active(): + raise error.Abort(_('no update in progress')) + node = ms.localctx.hex() + _unmarkandresolvelocal(ui, repo, ms) + repo.ui.status(_("aborting the update, updating back to" + " %s\n") % node[:12]) + mergemod.update(repo, node, branchmerge=False, force=False) + ms2 = mergemod.mergestate.read(repo) + _unmarkandresolvelocal(ui, repo, ms2) + ui.status(_("update aborted\n")) + ui.status(_("working directory is now at %s\n") % node[:12]) + def _incoming(displaychlist, subreporecurse, ui, repo, source, opts, buffered=False): """ diff --git a/tests/test-update-abort.t b/tests/test-update-abort.t new file mode 100644 --- /dev/null +++ b/tests/test-update-abort.t @@ -0,0 +1,177 @@ +Tests for 'hg update --abort' + + $ cat >> $HGRCPATH << EOF + > [extensions] + > graphlog= + > EOF + +Basic test + $ hg init test + $ cd test + $ echo before > file + $ hg add file + $ hg commit -mbefore + $ echo after > file + $ hg commit -mafter + $ echo edited > file + +abort flag with no interrupted update + $ hg update --abort + abort: no update in progress + [255] + +Pre-update log and file content + $ hg glog + @ changeset: 1:47d1da7c1f80 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: after + | + o changeset: 0:dd67ebc4de84 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: before + + + $ cat file + edited + $ hg update 0 + merging file + warning: conflicts while merging file! (edit, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges + [1] + + $ hg update --abort + aborting the update, updating back to 47d1da7c1f80 + merging file + warning: conflicts while merging file! (edit, then use 'hg resolve --mark') + update aborted + working directory is now at 47d1da7c1f80 + +Post-update log and file content + $ hg glog + @ changeset: 1:47d1da7c1f80 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: after + | + o changeset: 0:dd67ebc4de84 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: before + + + $ cat file + edited + +Test when not all files are resolved + $ echo foo > foo + $ hg add foo + $ hg commit -m "added foo" + $ echo changed > file + $ echo bar > foo + $ hg update 0 + file 'foo' was deleted in other [destination] but was modified in local [working copy]. + You can use (c)hanged version, (d)elete, or leave (u)nresolved. + What do you want to do? u + merging file + warning: conflicts while merging file! (edit, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 2 files unresolved + use 'hg resolve' to retry unresolved file merges + [1] + $ echo resolved > file + $ hg resolve --mark + (no more unresolved files) + $ cat file + resolved + $ hg update --abort + aborting the update, updating back to a2b94c20eadb + merging file + merging foo + warning: conflicts while merging file! (edit, then use 'hg resolve --mark') + warning: conflicts while merging foo! (edit, then use 'hg resolve --mark') + update aborted + working directory is now at a2b94c20eadb + $ cat file + changed + $ cat foo + bar + $ cd .. + +Test with dirty subrepo + $ hg init repo + $ cd repo + $ echo foo > bar + $ hg add bar + $ hg commit -minitial + $ mkdir subrepo + $ cd subrepo + $ echo foo1 > bar1 + $ hg add bar1 + $ hg commit -m "initial subrepo" + $ echo edited > bar1 + $ hg up 0 + file 'subrepo/bar1' was deleted in other [destination] but was modified in local [working copy]. + You can use (c)hanged version, (d)elete, or leave (u)nresolved. + What do you want to do? u + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges + [1] + $ hg update --abort + aborting the update, updating back to 4fa4579cc2b0 + merging subrepo/bar1 + warning: conflicts while merging subrepo/bar1! (edit, then use 'hg resolve --mark') + update aborted + working directory is now at 4fa4579cc2b0 + $ cat bar1 + edited + $ cd .. + +Test with not all subrepos resolved + $ mkdir subrepo2 + $ cd subrepo2 + $ echo foo2 > bar2 + $ hg add bar2 + $ hg commit -m "initial subrepo2" + $ echo bar > bar2 + $ cd .. + $ cd subrepo + $ echo edited1 > bar1 + $ cd .. + $ hg up 0 + file 'subrepo/bar1' was deleted in other [destination] but was modified in local [working copy]. + You can use (c)hanged version, (d)elete, or leave (u)nresolved. + What do you want to do? u + file 'subrepo2/bar2' was deleted in other [destination] but was modified in local [working copy]. + You can use (c)hanged version, (d)elete, or leave (u)nresolved. + What do you want to do? u + 0 files updated, 0 files merged, 0 files removed, 2 files unresolved + use 'hg resolve' to retry unresolved file merges + [1] + $ cd subrepo2 + $ echo resolved > bar2 + $ cat bar2 + resolved + $ hg resolve --mark + (no more unresolved files) + $ cd .. + $ hg update --abort + aborting the update, updating back to 79268ebc79e3 + merging subrepo/bar1 + merging subrepo2/bar2 + warning: conflicts while merging subrepo/bar1! (edit, then use 'hg resolve --mark') + warning: conflicts while merging subrepo2/bar2! (edit, then use 'hg resolve --mark') + update aborted + working directory is now at 79268ebc79e3 + $ cd subrepo2 + $ cat bar2 + bar + $ cd .. + $ cd subrepo + $ cat bar1 + edited1 + $ cd .. + $ cd ..