[PATCH 2 of 2 V4] shelve: adds restoring newly created branch (issue5048) (BC)

liscju piotr.listkiewicz at gmail.com
Fri Mar 11 04:10:16 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 6d32d53697c41575d6b805037fe6ffaafe601ad1
# Parent  c0f1872014a6ce46dbcbb5627a9bb7ff5a206aaf
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, without
interactive,include and exclude option) 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 c0f1872014a6 -r 6d32d53697c4 hgext/shelve.py
--- a/hgext/shelve.py	Mon Mar 07 22:58:11 2016 +0100
+++ 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()]
+            branchtorestore = 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.branchtorestore = branchtorestore
 
         return obj
 
     @classmethod
-    def save(cls, repo, name, originalwctx, pendingctx, stripnodes):
+    def save(cls, repo, name, originalwctx, pendingctx, stripnodes,
+             branchtorestore):
         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' % branchtorestore)
         fp.close()
 
     @classmethod
@@ -532,6 +536,12 @@ def mergefiles(ui, repo, wctx, shelvectx
     finally:
         ui.quiet = oldquiet
 
+def restorebranch(ui, repo, branchtorestore):
+    if branchtorestore and branchtorestore != repo.dirstate.branch():
+        repo.dirstate.setbranch(branchtorestore)
+        ui.status(_('marked working directory as branch %s\n')
+                  % branchtorestore)
+
 def unshelvecleanup(ui, repo, name, opts):
     """remove related files after an unshelve"""
     if not opts['keep']:
@@ -571,6 +581,7 @@ def unshelvecontinue(ui, repo, state, op
             state.stripnodes.append(shelvectx.node())
 
         mergefiles(ui, repo, state.wctx, shelvectx)
+        restorebranch(ui, repo, state.branchtorestore)
 
         repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve')
         shelvedstate.clear(repo)
@@ -609,6 +620,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 are specified, without interactive,
+    include and exclude option) 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``
@@ -717,6 +732,10 @@ def _dounshelve(ui, repo, *shelved, **op
 
         shelvectx = repo['tip']
 
+        branchtorestore = ''
+        if shelvectx.branch() != shelvectx.p1().branch():
+            branchtorestore = shelvectx.branch()
+
         # 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():
@@ -733,7 +752,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,
+                                  branchtorestore)
 
                 util.rename(repo.join('rebasestate'),
                             repo.join('unshelverebasestate'))
@@ -749,6 +769,7 @@ def _dounshelve(ui, repo, *shelved, **op
                 shelvectx = tmpwctx
 
         mergefiles(ui, repo, pctx, shelvectx)
+        restorebranch(ui, repo, branchtorestore)
 
         # Forget any files that were unknown before the shelve, unknown before
         # unshelve started, but are now added.
@@ -818,6 +839,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, without interactive,
+    include and exclude option), 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 c0f1872014a6 -r 6d32d53697c4 tests/test-shelve.t
--- a/tests/test-shelve.t	Mon Mar 07 22:58:11 2016 +0100
+++ 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, without interactive, include
+      and exclude option), 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,201 @@ 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 non 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
+  marked working directory as branch default
+  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