Patchwork D6738: unshelve: add --unresolved flag to unshelve mergestate with unresolved files

login
register
mail settings
Submitter phabricator
Date Aug. 17, 2019, 8:41 p.m.
Message ID <differential-rev-PHID-DREV-h4s467rd4ldwz3uxt6fk-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/41341/
State New
Headers show

Comments

phabricator - Aug. 17, 2019, 8:41 p.m.
navaneeth.suresh created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  `hg unshelve --unresolved` will get the user back to the old unresolved merge by
  the following steps:
  
  Step 1: If the user has committed new changesets after shelving the changes,
  they must update the working directory to one of the merge parents.
  
  Step 2: Change parents of dirstate to `p1` and `p2`.
  
  Step 3: In order to restore our partially resolved state, we will write from
  data stored in changeset extras.
  
  Step 4: We now have a state in which files marked as resolved might have
  conflicts. But, we will apply the changes in shelve on the top of this so that we
  can get our old unresolved merge again by the usual unshelve mechanism.
  
  The usual rebase step is avoided on unresolved shelve changesets.
  
  `$ hg unshelve --unresolved` will abort when:
  
  1. The working directory is dirty.
  2. If there is an ongoing merge.
  3. If the working directory is not at either p1 or p2.
  
  (`p1`, `p2` are the parents of the unresolved shelve changeset)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

AFFECTED FILES
  mercurial/commands.py
  mercurial/shelve.py
  tests/test-completion.t
  tests/test-shelve-unresolved.t

CHANGE DETAILS




To: navaneeth.suresh, #hg-reviewers
Cc: mercurial-devel
phabricator - Aug. 19, 2019, 3:10 p.m.
pulkit added inline comments.

INLINE COMMENTS

> shelve.py:754
> +    ms = merge.mergestate.clean(repo)
> +    ms._writerecordsv2(_decodemergerecords(records))
> +

we should write both the versions, `_writerecords()` should be used.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6738/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

To: navaneeth.suresh, #hg-reviewers
Cc: pulkit, mercurial-devel
phabricator - Aug. 20, 2019, 1:20 p.m.
navaneeth.suresh added inline comments.

INLINE COMMENTS

> pulkit wrote in shelve.py:754
> we should write both the versions, `_writerecords()` should be used.

i had tried to support it earlier. but, it throws the following error. i think it's okay to use the latest format only since, we haven't stored any mergestate using the previous format. the repo won't get corrupted.

  +  Traceback (most recent call last):
  +    File "/tmp/hgtests.TEheee/install/bin/hg", line 43, in <module>
  +      dispatch.run()
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 99, in run
  +      status = dispatch(req)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 225, in dispatch
  +      ret = _runcatch(req) or 0
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 376, in _runcatch
  +      return _callcatch(ui, _runcatchfunc)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 384, in _callcatch
  +      return scmutil.callcatch(ui, func)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/scmutil.py", line 167, in callcatch
  +      return func()
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 367, in _runcatchfunc
  +      return _dispatch(req)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1021, in _dispatch
  +      cmdpats, cmdoptions)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 756, in runcommand
  +      ret = _runcommand(ui, options, cmd, d)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1030, in _runcommand
  +      return cmdfunc()
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1018, in <lambda>
  +      d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/util.py", line 1682, in check
  +      return func(*args, **kwargs)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/commands.py", line 6229, in unshelve
  +      return shelvemod.dounshelve(ui, repo, *shelved, **opts)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/shelve.py", line 1090, in dounshelve
  +      restoreunresolvedshelve(ui, repo, shelvectx, basename)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/shelve.py", line 754, in restoreunresolvedshelve
  +      ms._writerecords(_decodemergerecords(records))
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/merge.py", line 452, in _writerecords
  +      self._writerecordsv1(records)
  +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/merge.py", line 460, in _writerecordsv1
  +      assert lrecords[0] == RECORD_LOCAL
  +  AssertionError
  +  [1]

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6738/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

To: navaneeth.suresh, #hg-reviewers
Cc: pulkit, mercurial-devel
phabricator - Aug. 25, 2019, 2:25 p.m.
pulkit added inline comments.

INLINE COMMENTS

> navaneeth.suresh wrote in shelve.py:754
> i had tried to support it earlier. but, it throws the following error. i think it's okay to use the latest format only since, we haven't stored any mergestate using the previous format. the repo won't get corrupted.
> 
>   +  Traceback (most recent call last):
>   +    File "/tmp/hgtests.TEheee/install/bin/hg", line 43, in <module>
>   +      dispatch.run()
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 99, in run
>   +      status = dispatch(req)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 225, in dispatch
>   +      ret = _runcatch(req) or 0
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 376, in _runcatch
>   +      return _callcatch(ui, _runcatchfunc)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 384, in _callcatch
>   +      return scmutil.callcatch(ui, func)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/scmutil.py", line 167, in callcatch
>   +      return func()
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 367, in _runcatchfunc
>   +      return _dispatch(req)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1021, in _dispatch
>   +      cmdpats, cmdoptions)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 756, in runcommand
>   +      ret = _runcommand(ui, options, cmd, d)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1030, in _runcommand
>   +      return cmdfunc()
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/dispatch.py", line 1018, in <lambda>
>   +      d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/util.py", line 1682, in check
>   +      return func(*args, **kwargs)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/commands.py", line 6229, in unshelve
>   +      return shelvemod.dounshelve(ui, repo, *shelved, **opts)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/shelve.py", line 1090, in dounshelve
>   +      restoreunresolvedshelve(ui, repo, shelvectx, basename)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/shelve.py", line 754, in restoreunresolvedshelve
>   +      ms._writerecords(_decodemergerecords(records))
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/merge.py", line 452, in _writerecords
>   +      self._writerecordsv1(records)
>   +    File "/tmp/hgtests.TEheee/install/lib/python/mercurial/merge.py", line 460, in _writerecordsv1
>   +      assert lrecords[0] == RECORD_LOCAL
>   +  AssertionError
>   +  [1]

Then we are somehow parsing or building the records in not correct way.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6738/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

To: navaneeth.suresh, #hg-reviewers
Cc: pulkit, mercurial-devel
phabricator - Sept. 12, 2019, 5:47 a.m.
pulkit added inline comments.

INLINE COMMENTS

> pulkit wrote in shelve.py:754
> Then we are somehow parsing or building the records in not correct way.

Did you manage to find why that error comes up?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6738/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

To: navaneeth.suresh, #hg-reviewers
Cc: pulkit, mercurial-devel
phabricator - Oct. 4, 2019, 8:53 p.m.
navaneeth.suresh added inline comments.

INLINE COMMENTS

> pulkit wrote in shelve.py:754
> Did you manage to find why that error comes up?

Yes. This was because we are not storing the local version of the files. So, it will be `None` as returned while reading the mergestate. So, it should throw an `AssertionError`. We can get rid of this only when we store the local versions of the files in future.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6738/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6738

To: navaneeth.suresh, #hg-reviewers
Cc: pulkit, mercurial-devel

Patch

diff --git a/tests/test-shelve-unresolved.t b/tests/test-shelve-unresolved.t
--- a/tests/test-shelve-unresolved.t
+++ b/tests/test-shelve-unresolved.t
@@ -171,3 +171,290 @@ 
   +=======
   +B
   +>>>>>>> merge rev:    fd9a4049234b - test: B
+
+-- now, fix an urgent bug
+  $ echo fixed >> bug
+  $ ls
+  bar
+  bug
+  file1
+  file1.orig
+  file2
+  file2.orig
+  $ hg add bug
+  $ hg ci -m "fix bug"
+  $ hg log -G
+  @  changeset:   3:a53a9a7475b3
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     fix bug
+  |
+  o  changeset:   2:69004294ad57
+  |  parent:      0:c32ef6121744
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     C
+  |
+  | o  changeset:   1:fd9a4049234b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B
+  |
+  o  changeset:   0:c32ef6121744
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     A
+  
+-- let's get back to the old mergestate
+-- we need to update to one of the merge parents. otherwise, abort.
+  $ hg unshelve --unresolved
+  unshelving change 'default'
+  abort: dirstate is not on either of the merge parents.
+  use hg update to one of the merge parents.
+  [255]
+
+  $ hg up 2
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ cat file2
+  A
+  C
+
+-- flag --unshelve is not passed. but, the last shelve is unresolved
+  $ hg unshelve
+  unshelving change 'default'
+  abort: default is an unresolved shelve, use --unresolved to unshelve it
+  [255]
+
+  $ hg unshelve --unresolved
+  unshelving change 'default'
+
+  $ hg log -G
+  o  changeset:   3:a53a9a7475b3
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     fix bug
+  |
+  @  changeset:   2:69004294ad57
+  |  parent:      0:c32ef6121744
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     C
+  |
+  | @  changeset:   1:fd9a4049234b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B
+  |
+  o  changeset:   0:c32ef6121744
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     A
+  
+  $ cat file1
+  A
+  B
+  C
+  $ hg diff
+  diff -r 69004294ad57 file1
+  --- a/file1	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file1	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,2 +1,3 @@
+   A
+  +B
+   C
+  diff -r 69004294ad57 file2
+  --- a/file2	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file2	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,2 +1,6 @@
+   A
+  +<<<<<<< working copy: 69004294ad57 - test: C
+   C
+  +=======
+  +B
+  +>>>>>>> merge rev:    fd9a4049234b - test: B
+  $ cat file2
+  A
+  <<<<<<< working copy: 69004294ad57 - test: C
+  C
+  =======
+  B
+  >>>>>>> merge rev:    fd9a4049234b - test: B
+  $ hg resolve -l
+  R file1
+  U file2
+
+-- flag --unresolved is passed but the top most shelve is not unresolved
+  $ hg shelve --unresolved
+  shelved as default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ echo garbage >> bug
+  $ hg st
+  ? bar
+  ? bug
+  ? file1.orig
+  ? file2.orig
+  $ hg add bug
+  $ hg shelve
+  shelved as default-01
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg unshelve --unresolved
+  unshelving change 'default-01'
+  abort: default-01 is not an unresolved shelve
+  
+  [255]
+
+-- now, unshelve default
+  $ hg unshelve -n default --unresolved
+
+-- commit the merge after completing conflict resolution
+  $ cat >> file2 <<EOF
+  > A
+  > B
+  > C
+  > EOF
+  $ hg resolve -m file2
+  (no more unresolved files)
+  $ hg ci -m merge
+  $ hg verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  checked 5 changesets with 9 changes to 3 files
+  $ hg log -G
+  @    changeset:   4:745dca2ee1f1
+  |\   tag:         tip
+  | |  parent:      2:69004294ad57
+  | |  parent:      1:fd9a4049234b
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     merge
+  | |
+  | | o  changeset:   3:a53a9a7475b3
+  | |/   user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     fix bug
+  | |
+  | o  changeset:   2:69004294ad57
+  | |  parent:      0:c32ef6121744
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     C
+  | |
+  o |  changeset:   1:fd9a4049234b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B
+  |
+  o  changeset:   0:c32ef6121744
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     A
+  
+
+-- flag --unresolved is passed but we don’t have any unresolved shelve
+  $ hg unshelve --unresolved
+  unshelving change 'default-01'
+  abort: default-01 is not an unresolved shelve
+  
+  [255]
+
+-- when working directory is dirty
+  $ addunresolvedmerge file1 file2 5
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  created new head
+  merging file1
+  merging file2
+  warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
+  warning: conflicts while merging file2! (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 or 'hg merge --abort' to abandon
+  [1]
+
+  $ hg shelve --unresolved
+  shelved as default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ echo dirt >> bar
+  $ hg add bar
+  $ hg unshelve --unresolved
+  unshelving change 'default'
+  abort: uncommitted changes
+  [255]
+
+--- unshelve --unresolved when there is another merge going on
+  $ hg ci -m dirt
+  $ hg up 7
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo foo >> bug
+  $ hg add bug
+  $ hg ci -m foo2
+  created new head
+  $ hg log -G
+  @  changeset:   9:c74a624102ed
+  |  tag:         tip
+  |  parent:      7:974ec4298b79
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     foo2
+  |
+  | o  changeset:   8:4acf09fb3a59
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     dirt
+  |
+  o  changeset:   7:974ec4298b79
+  |  parent:      5:db68c6c84fe6
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     C
+  |
+  | o  changeset:   6:e236d497f76b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B
+  |
+  o  changeset:   5:db68c6c84fe6
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A
+  |
+  o    changeset:   4:745dca2ee1f1
+  |\   parent:      2:69004294ad57
+  | |  parent:      1:fd9a4049234b
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     merge
+  | |
+  | | o  changeset:   3:a53a9a7475b3
+  | |/   user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     fix bug
+  | |
+  | o  changeset:   2:69004294ad57
+  | |  parent:      0:c32ef6121744
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     C
+  | |
+  o |  changeset:   1:fd9a4049234b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B
+  |
+  o  changeset:   0:c32ef6121744
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     A
+  
+  $ hg merge -r 8
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+
+  $ hg unshelve --unresolved
+  abort: outstanding uncommitted merge
+  (use 'hg commit' or 'hg merge --abort')
+  [255]
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -354,7 +354,7 @@ 
   tags: template
   tip: patch, git, style, template
   unbundle: update
-  unshelve: abort, continue, interactive, keep, name, tool, date
+  unshelve: abort, continue, interactive, keep, name, tool, date, unresolved
   update: clean, check, merge, date, rev, tool
   verify: full
   version: template
diff --git a/mercurial/shelve.py b/mercurial/shelve.py
--- a/mercurial/shelve.py
+++ b/mercurial/shelve.py
@@ -450,6 +450,10 @@ 
         extra['shelve_unknown'] = '\0'.join(s.unknown)
         repo[None].add(s.unknown)
 
+def _isunresolvedshelve(shelvectx):
+    """Checks whether the given shelve is unresolved or not"""
+    return shelvectx.extra().get('unresolved-merge')
+
 def _finishshelve(repo, tr):
     if phases.supportinternal(repo):
         tr.close()
@@ -735,6 +739,20 @@ 
         ui.status(_('marked working directory as branch %s\n')
                   % branchtorestore)
 
+def restoreunresolvedshelve(ui, repo, shelvectx, basename):
+    """Change the parents of the dirstate to the parents of the stored
+    unresolved shelvectx.
+
+    Rewrite the mergestate from changeset extra to restore the status
+    of the resolved files in the shelvectx.
+    """
+    p1, p2 = shelvectx.parents()
+    repo.dirstate.setparents(p1.node(), p2.node())
+
+    records = shelvectx.extra().get('mergerecords')
+    ms = merge.mergestate.clean(repo)
+    ms._writerecordsv2(_decodemergerecords(records))
+
 def unshelvecleanup(ui, repo, name, opts):
     """remove related files after an unshelve"""
     if not opts.get('keep'):
@@ -981,6 +999,7 @@ 
     abortf = opts.get('abort')
     continuef = opts.get('continue')
     interactive = opts.get('interactive')
+    unresolved = opts.get('unresolved')
     if not abortf and not continuef:
         cmdutil.checkunfinished(repo)
     shelved = list(shelved)
@@ -1018,6 +1037,8 @@ 
 
     if not shelvedfile(repo, basename, patchextension).exists():
         raise error.Abort(_("shelved change '%s' not found") % basename)
+    if unresolved:
+        cmdutil.bailifchanged(repo)
 
     repo = repo.unfiltered()
     lock = tr = None
@@ -1038,17 +1059,35 @@ 
         tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
                                                          tmpwctx)
         repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
+        unresolvedshelve = _isunresolvedshelve(shelvectx)
         _checkunshelveuntrackedproblems(ui, repo, shelvectx)
         branchtorestore = ''
         if shelvectx.branch() != shelvectx.p1().branch():
             branchtorestore = shelvectx.branch()
 
-        shelvectx, ispartialunshelve = _rebaserestoredcommit(ui, repo, opts,
-            tr, oldtiprev, basename, pctx, tmpwctx, shelvectx,
-            branchtorestore, activebookmark)
+        if unresolved:
+            ispartialunshelve = False
+            if not unresolvedshelve:
+                raise error.Abort(_('%s is not an unresolved shelve\n') %
+                                    basename)
+            p1, p2 = shelvectx.parents()
+            if pctx.node() not in [p1.node(), p2.node()]:
+                raise error.Abort(_('dirstate is not on either of the merge'
+                                    ' parents.\nuse hg update to one of the'
+                                    ' merge parents.'))
+        elif unresolvedshelve:
+            raise error.Abort(_('%s is an unresolved shelve, use'
+                                ' --unresolved to unshelve it') % basename)
+        else:
+            shelvectx, ispartialunshelve = _rebaserestoredcommit(ui, repo,
+                opts, tr, oldtiprev, basename, pctx, tmpwctx, shelvectx,
+                branchtorestore, activebookmark)
         overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
         with ui.configoverride(overrides, 'unshelve'):
             mergefiles(ui, repo, pctx, shelvectx)
+        if unresolved:
+            with repo.dirstate.parentchange():
+                restoreunresolvedshelve(ui, repo, shelvectx, basename)
         restorebranch(ui, repo, branchtorestore)
         shelvedstate.clear(repo)
         _finishunshelve(repo, oldtiprev, tr, activebookmark)
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -6176,7 +6176,9 @@ 
            _('restore shelved change with given name'), _('NAME')),
           ('t', 'tool', '', _('specify merge tool')),
           ('', 'date', '',
-           _('set date for temporary commits (DEPRECATED)'), _('DATE'))],
+           _('set date for temporary commits (DEPRECATED)'), _('DATE')),
+          ('', 'unresolved', None,
+           _('unshelve mergestate with unresolved files'))],
          _('hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
          helpcategory=command.CATEGORY_WORKING_DIRECTORY)
 def unshelve(ui, repo, *shelved, **opts):