[PATCH V2] shelve: adds restoring newly created branch (issue5048) (BC)

liscju piotr.listkiewicz at gmail.com
Tue Mar 1 10:34:48 EST 2016


# HG changeset patch
# User liscju <piotr.listkiewicz at gmail.com>
# Date 1455067407 -3600
#      Wed Feb 10 02:23:27 2016 +0100
# Node ID bb25b522b01de4954502729a22b40075d6a35f6f
# Parent  a036e1ae1fbe88ab99cb861ebfc2e4da7a3912ca
shelve: adds restoring newly created branch (issue5048) (BC)

Before this patch shelve never preserved branch information,
so after applying unshelve branch was the same as it was
on working copy no matter in which branch shelve took place.

This patch makes bare shelving(with no files specified)
remembers information if the working directory was on newly
created branch ,in other words working directory was on
different branch than its first parent. In this situation
unshelving restores branch information to the working
directory.

diff -r a036e1ae1fbe -r bb25b522b01d hgext/shelve.py
--- a/hgext/shelve.py	Sun Feb 07 00:49:31 2016 -0600
+++ b/hgext/shelve.py	Wed Feb 10 02:23:27 2016 +0100
@@ -148,6 +148,7 @@ class shelvedstate(object):
             pendingctx = fp.readline().strip()
             parents = [bin(h) for h in fp.readline().split()]
             stripnodes = [bin(h) for h in fp.readline().split()]
+            restorebranch = fp.readline().strip()
         finally:
             fp.close()
 
@@ -157,11 +158,13 @@ class shelvedstate(object):
         obj.pendingctx = repo[bin(pendingctx)]
         obj.parents = parents
         obj.stripnodes = stripnodes
+        obj.restorebranch = restorebranch
 
         return obj
 
     @classmethod
-    def save(cls, repo, name, originalwctx, pendingctx, stripnodes):
+    def save(cls, repo, name, originalwctx, pendingctx, stripnodes,
+             restorebranch):
         fp = repo.vfs(cls._filename, 'wb')
         fp.write('%i\n' % cls._version)
         fp.write('%s\n' % name)
@@ -169,6 +172,7 @@ class shelvedstate(object):
         fp.write('%s\n' % hex(pendingctx.node()))
         fp.write('%s\n' % ' '.join([hex(p) for p in repo.dirstate.parents()]))
         fp.write('%s\n' % ' '.join([hex(n) for n in stripnodes]))
+        fp.write('%s\n' % restorebranch)
         fp.close()
 
     @classmethod
@@ -312,6 +316,10 @@ def _docreatecmd(ui, repo, pats, opts):
                 extra['shelve_unknown'] = '\0'.join(s.unknown)
                 repo[None].add(s.unknown)
 
+        if pats:
+            # In non-bare shelve we don't store newly created branch
+            repo.dirstate.setbranch(repo['.'].branch())
+
         def commitfunc(ui, repo, message, match, opts):
             hasmq = util.safehasattr(repo, 'mq')
             if hasmq:
@@ -556,6 +564,11 @@ def unshelvecontinue(ui, repo, state, op
             state.stripnodes.append(shelvectx.node())
 
         mergefiles(ui, repo, state.wctx, shelvectx)
+        if (state.restorebranch and
+                state.restorebranch != repo.dirstate.branch()):
+            repo.dirstate.setbranch(state.restorebranch)
+            ui.status(_('marked working directory as branch %s\n') %
+                        state.restorebranch)
 
         repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
         shelvedstate.clear(repo)
@@ -594,6 +607,10 @@ def unshelve(ui, repo, *shelved, **opts)
     that causes a conflict. This reverts the unshelved changes, and
     leaves the bundle in place.)
 
+    If bare shelved change(when no files were specified) was done on
+    newly created branch it would restore branch information to the
+    working directory.
+
     After a successful unshelve, the shelved changes are stored in a
     backup directory. Only the N most recent backups are kept. N
     defaults to 10 but can be overridden using the ``shelve.maxbackups``
@@ -702,6 +719,11 @@ def _dounshelve(ui, repo, *shelved, **op
 
         shelvectx = repo['tip']
 
+        if shelvectx.branch() != shelvectx.p1().branch():
+            restorebranch = shelvectx.branch()
+        else:
+            restorebranch = ''
+
         # If the shelve is not immediately on top of the commit
         # we'll be merging with, rebase it to be on top.
         if tmpwctx.node() != shelvectx.parents()[0].node():
@@ -718,7 +740,8 @@ def _dounshelve(ui, repo, *shelved, **op
 
                 stripnodes = [repo.changelog.node(rev)
                               for rev in xrange(oldtiprev, len(repo))]
-                shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes)
+                shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes,
+                                  restorebranch)
 
                 util.rename(repo.join('rebasestate'),
                             repo.join('unshelverebasestate'))
@@ -734,6 +757,11 @@ def _dounshelve(ui, repo, *shelved, **op
                 shelvectx = tmpwctx
 
         mergefiles(ui, repo, pctx, shelvectx)
+        if (restorebranch and
+                restorebranch != repo.dirstate.branch()):
+            repo.dirstate.setbranch(restorebranch)
+            ui.status(_('marked working directory as branch %s\n') %
+                        restorebranch)
 
         # Forget any files that were unknown before the shelve, unknown before
         # unshelve started, but are now added.
@@ -803,6 +831,12 @@ def shelvecmd(ui, repo, *pats, **opts):
     files. If specific files or directories are named, only changes to
     those files are shelved.
 
+    In bare shelve(when no files are specified), shelving remembers
+    information if the working directory was on newly created branch,
+    in other words working directory was on different branch than its
+    first parent. In this situation unshelving restores branch
+    information to the working directory.
+
     Each shelved change has a name that makes it easier to find later.
     The name of a shelved change defaults to being based on the active
     bookmark, or if there is no active bookmark, the current named
diff -r a036e1ae1fbe -r bb25b522b01d tests/test-shelve.t
--- a/tests/test-shelve.t	Sun Feb 07 00:49:31 2016 -0600
+++ b/tests/test-shelve.t	Wed Feb 10 02:23:27 2016 +0100
@@ -36,6 +36,12 @@ shelve has a help message
       specific files or directories are named, only changes to those files are
       shelved.
   
+      In bare shelve(when no files are specified), shelving remembers
+      information if the working directory was on newly created branch, in other
+      words working directory was on different branch than its first parent. In
+      this situation unshelving restores branch information to the working
+      directory.
+  
       Each shelved change has a name that makes it easier to find later. The
       name of a shelved change defaults to being based on the active bookmark,
       or if there is no active bookmark, the current named branch.  To specify a
@@ -1314,3 +1320,200 @@ And if I shelve, commit, then unshelve, 
   $ hg commit -qm "Remove unknown"
 
   $ cd ..
+
+When i shelve commit on newly created branch i expect
+that after unshelve newly created branch will be preserved.
+
+  $ hg init shelve_on_new_branch_simple
+  $ cd shelve_on_new_branch_simple
+  $ echo "aaa" >> a
+  $ hg commit -A -m "a"
+  adding a
+  $ hg branch
+  default
+  $ hg branch test
+  marked working directory as branch test
+  (branches are permanent and global, did you want a bookmark?)
+  $ echo "bbb" >> a
+  $ hg status
+  M a
+  $ hg shelve
+  shelved as default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch
+  default
+  $ echo "bbb" >> b
+  $ hg status
+  ? b
+  $ hg unshelve
+  unshelving change 'default'
+  marked working directory as branch test
+  $ hg status
+  M a
+  ? b
+  $ hg branch
+  test
+
+When i shelve commit on newly created branch, make
+some changes, unshelve it and running into merge
+conflicts i expect that after fixing them and
+running unshelve --continue newly created branch
+will be preserved.
+
+  $ hg init shelve_on_new_branch_conflict
+  $ cd shelve_on_new_branch_conflict
+  $ echo "aaa" >> a
+  $ hg commit -A -m "a"
+  adding a
+  $ hg branch
+  default
+  $ hg branch test
+  marked working directory as branch test
+  (branches are permanent and global, did you want a bookmark?)
+  $ echo "bbb" >> a
+  $ hg status
+  M a
+  $ hg shelve
+  shelved as default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch
+  default
+  $ echo "ccc" >> a
+  $ hg status
+  M a
+  $ hg unshelve
+  unshelving change 'default'
+  temporarily committing pending changes (restore with 'hg unshelve --abort')
+  rebasing shelved changes
+  rebasing 2:425c97ef07f3 "changes to: a" (tip)
+  merging a
+  warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
+  [1]
+  $ echo "aaabbbccc" > a
+  $ rm a.orig
+  $ hg resolve --mark a
+  (no more unresolved files)
+  continue: hg unshelve --continue
+  $ hg unshelve --continue
+  rebasing 2:425c97ef07f3 "changes to: a" (tip)
+  marked working directory as branch test
+  unshelve of 'default' complete
+  $ cat a
+  aaabbbccc
+  $ hg status
+  M a
+  $ hg branch
+  test
+  $ hg commit -m "test-commit"
+
+When i shelve on test branch, update to default branch
+and unshelve i expect that it will not preserve previous
+test branch.
+
+  $ echo "xxx" > b
+  $ hg add b
+  $ hg shelve
+  shelved as test
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg update -r default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg unshelve
+  unshelving change 'test'
+  rebasing shelved changes
+  rebasing 2:357525f34729 "changes to: test-commit" (tip)
+  $ hg status
+  A b
+  $ hg branch
+  default
+
+When i unshelve resulting in merge conflicts and makes saved
+file shelvedstate looks like in previous versions in
+mercurial(without restore branch information in 7th line) i
+expect that after resolving conflicts and succesfully
+running 'shelve --continue' the branch information won't be
+restored and branch will be unchanged.
+
+  $ hg init shelve_on_new_branch_conflict_with_previous_shelvedstate
+  $ cd shelve_on_new_branch_conflict_with_previous_shelvedstate
+  $ echo "aaa" >> a
+  $ hg commit -A -m "a"
+  adding a
+  $ hg branch
+  default
+  $ hg branch test
+  marked working directory as branch test
+  (branches are permanent and global, did you want a bookmark?)
+  $ echo "bbb" >> a
+  $ hg status
+  M a
+  $ hg shelve
+  shelved as default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch
+  default
+  $ echo "ccc" >> a
+  $ hg status
+  M a
+  $ hg unshelve
+  unshelving change 'default'
+  temporarily committing pending changes (restore with 'hg unshelve --abort')
+  rebasing shelved changes
+  rebasing 2:425c97ef07f3 "changes to: a" (tip)
+  merging a
+  warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
+  [1]
+
+Removing restore branch information from shelvedstate file(making it looks like
+in previous versions) and running unshelve --continue
+
+  $ head -n 6 < .hg/shelvedstate > .hg/shelvedstate_oldformat
+  $ rm .hg/shelvedstate
+  $ mv .hg/shelvedstate_oldformat .hg/shelvedstate
+
+  $ echo "aaabbbccc" > a
+  $ rm a.orig
+  $ hg resolve --mark a
+  (no more unresolved files)
+  continue: hg unshelve --continue
+  $ hg unshelve --continue
+  rebasing 2:425c97ef07f3 "changes to: a" (tip)
+  unshelve of 'default' complete
+  $ cat a
+  aaabbbccc
+  $ hg status
+  M a
+  $ hg branch
+  default
+
+On bare shelve the branch information shouldn't be restored
+
+  $ hg init bare_shelve_on_new_branch
+  $ cd bare_shelve_on_new_branch
+  $ echo "aaa" >> a
+  $ hg commit -A -m "a"
+  adding a
+  $ hg branch
+  default
+  $ hg branch test
+  marked working directory as branch test
+  (branches are permanent and global, did you want a bookmark?)
+  $ echo "bbb" >> a
+  $ hg status
+  M a
+  $ hg shelve a
+  shelved as default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg branch
+  default
+  $ echo "bbb" >> b
+  $ hg status
+  ? b
+  $ hg unshelve
+  unshelving change 'default'
+  $ hg status
+  M a
+  ? b
+  $ hg branch
+  default


More information about the Mercurial-devel mailing list