[PATCH] rollback: only restore dirstate and branch when appropriate

Greg Ward greg-hg at gerg.ca
Sun Sep 18 19:04:05 CDT 2011


# HG changeset patch
# User Greg Ward <greg at gerg.ca>
# Date 1316390373 14400
# Node ID 429c9b431d4f2090338d460302ba34dea20f7c2e
# Parent  6348bd575fd4c439e487cf570cc2cba11de5f596
rollback: only restore dirstate and branch when appropriate.

If the working dir parent was destroyed by rollback, then the old
behaviour is perfectly reasonable: restore dirstate, branch, and
bookmarks. That way the working dir moves back to an existing
changeset rather than becoming an orphan.

But if the working dir parent was unaffected -- say, you updated to an
older changeset and then did rollback -- then it's silly to restore
dirstate and branch. So don't do that. Leave the status of the working
dir alone. (But always restore bookmarks, because that file refers to
changeset IDs that may have been destroyed.)

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -789,28 +789,35 @@
         ui.status(msg)
         if dryrun:
             return 0
+
+        parents = self.dirstate.parents()
         transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
-        util.rename(self.join('undo.dirstate'), self.join('dirstate'))
         if os.path.exists(self.join('undo.bookmarks')):
             util.rename(self.join('undo.bookmarks'),
                         self.join('bookmarks'))
-        try:
-            branch = self.opener.read('undo.branch')
-            self.dirstate.setbranch(branch)
-        except IOError:
-            ui.warn(_('named branch could not be reset: '
-                      'current branch is still \'%s\'\n')
-                    % self.dirstate.branch())
         self.invalidate()
-        self.dirstate.invalidate()
-        self.destroyed()
-        parents = tuple([p.rev() for p in self.parents()])
-        if len(parents) > 1:
-            ui.status(_('working directory now based on '
-                        'revisions %d and %d\n') % parents)
-        else:
-            ui.status(_('working directory now based on '
-                        'revision %d\n') % parents)
+
+        parentgone = (parents[0] not in self.changelog.nodemap or
+                      parents[1] not in self.changelog.nodemap)
+        if parentgone:
+            util.rename(self.join('undo.dirstate'), self.join('dirstate'))
+            try:
+                branch = self.opener.read('undo.branch')
+                self.dirstate.setbranch(branch)
+            except IOError:
+                ui.warn(_('named branch could not be reset: '
+                          'current branch is still \'%s\'\n')
+                        % self.dirstate.branch())
+
+            self.dirstate.invalidate()
+            self.destroyed()
+            parents = tuple([p.rev() for p in self.parents()])
+            if len(parents) > 1:
+                ui.status(_('working directory now based on '
+                            'revisions %d and %d\n') % parents)
+            else:
+                ui.status(_('working directory now based on '
+                            'revision %d\n') % parents)
         return 0
 
     def invalidatecaches(self):
diff --git a/tests/test-acl.t b/tests/test-acl.t
--- a/tests/test-acl.t
+++ b/tests/test-acl.t
@@ -121,7 +121,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -179,7 +178,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -247,7 +245,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -729,7 +726,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -1038,7 +1034,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -1114,7 +1109,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -1261,7 +1255,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 0 (undo push)
-  working directory now based on revision 0
   0:6675d58eff77
   
 
@@ -1456,7 +1449,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 2 (undo push)
-  working directory now based on revision 2
   2:fb35475503ef
   
 
@@ -1753,7 +1745,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 2 (undo push)
-  working directory now based on revision 2
   2:fb35475503ef
   
 
@@ -1838,7 +1829,6 @@
   updating the branch cache
   checking for updated bookmarks
   repository tip rolled back to revision 2 (undo push)
-  working directory now based on revision 2
   2:fb35475503ef
   
 Branch acl conflicting deny
diff --git a/tests/test-bundle-r.t b/tests/test-bundle-r.t
--- a/tests/test-bundle-r.t
+++ b/tests/test-bundle-r.t
@@ -154,7 +154,6 @@
   4 files, 9 changesets, 7 total revisions
   $ hg rollback
   repository tip rolled back to revision 4 (undo pull)
-  working directory now based on revision -1
   $ cd ..
 
 should fail
@@ -232,7 +231,6 @@
   4 files, 9 changesets, 7 total revisions
   $ hg rollback
   repository tip rolled back to revision 2 (undo unbundle)
-  working directory now based on revision 2
 
 revision 2
 
@@ -257,7 +255,6 @@
   2 files, 5 changesets, 5 total revisions
   $ hg rollback
   repository tip rolled back to revision 2 (undo unbundle)
-  working directory now based on revision 2
   $ hg unbundle ../test-bundle-branch2.hg
   adding changesets
   adding manifests
@@ -277,7 +274,6 @@
   3 files, 7 changesets, 6 total revisions
   $ hg rollback
   repository tip rolled back to revision 2 (undo unbundle)
-  working directory now based on revision 2
   $ hg unbundle ../test-bundle-cset-7.hg
   adding changesets
   adding manifests
diff --git a/tests/test-bundle.t b/tests/test-bundle.t
--- a/tests/test-bundle.t
+++ b/tests/test-bundle.t
@@ -90,7 +90,6 @@
 
   $ hg -R empty rollback
   repository tip rolled back to revision -1 (undo pull)
-  working directory now based on revision -1
 
 Pull full.hg into empty again (using --cwd)
 
@@ -121,7 +120,6 @@
 
   $ hg -R empty rollback
   repository tip rolled back to revision -1 (undo pull)
-  working directory now based on revision -1
 
 Pull full.hg into empty again (using -R)
 
@@ -219,7 +217,6 @@
 
   $ hg rollback
   repository tip rolled back to revision -1 (undo pull)
-  working directory now based on revision -1
   $ cd ..
 
 Log -R bundle:empty+full.hg
diff --git a/tests/test-eol-hook.t b/tests/test-eol-hook.t
--- a/tests/test-eol-hook.t
+++ b/tests/test-eol-hook.t
@@ -161,7 +161,6 @@
   added 3 changesets with 3 changes to 2 files (+1 heads)
   $ hg -R ../main rollback
   repository tip rolled back to revision 5 (undo push)
-  working directory now based on revision -1
 
 Test it still fails with checkallhook
 
diff --git a/tests/test-hook.t b/tests/test-hook.t
--- a/tests/test-hook.t
+++ b/tests/test-hook.t
@@ -277,7 +277,6 @@
   (run 'hg update' to get a working copy)
   $ hg rollback
   repository tip rolled back to revision 3 (undo pull)
-  working directory now based on revision 0
 
 preoutgoing hook can prevent outgoing changes
 
diff --git a/tests/test-import-bypass.t b/tests/test-import-bypass.t
--- a/tests/test-import-bypass.t
+++ b/tests/test-import-bypass.t
@@ -62,7 +62,6 @@
   
   $ hg rollback
   repository tip rolled back to revision 1 (undo commit)
-  working directory now based on revision 0
 
 Test --import-branch
 
@@ -75,7 +74,6 @@
   
   $ hg rollback
   repository tip rolled back to revision 1 (undo commit)
-  working directory now based on revision 0
 
 Test --strip
 
@@ -98,7 +96,6 @@
   applying patch from stdin
   $ hg rollback
   repository tip rolled back to revision 1 (undo commit)
-  working directory now based on revision 0
 
 Test unsupported combinations
 
diff --git a/tests/test-notify-changegroup.t b/tests/test-notify-changegroup.t
--- a/tests/test-notify-changegroup.t
+++ b/tests/test-notify-changegroup.t
@@ -74,7 +74,6 @@
   +a
   $ hg --cwd a rollback
   repository tip rolled back to revision -1 (undo push)
-  working directory now based on revision -1
 
 unbundle with unrelated source
 
@@ -89,7 +88,6 @@
   (run 'hg update' to get a working copy)
   $ hg --cwd a rollback
   repository tip rolled back to revision -1 (undo unbundle)
-  working directory now based on revision -1
 
 unbundle with correct source
 
diff --git a/tests/test-notify.t b/tests/test-notify.t
--- a/tests/test-notify.t
+++ b/tests/test-notify.t
@@ -200,7 +200,6 @@
 
   $ hg --cwd b rollback
   repository tip rolled back to revision 0 (undo pull)
-  working directory now based on revision 0
   $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
   pull failed
   $ touch ".notify.conf"
@@ -209,7 +208,6 @@
 
   $ hg --cwd b rollback
   repository tip rolled back to revision 0 (undo pull)
-  working directory now based on revision 0
   $ hg --traceback --cwd b pull ../a  | \
   >   python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
   pulling from ../a
@@ -254,7 +252,6 @@
 
   $ hg --cwd b rollback
   repository tip rolled back to revision 0 (undo pull)
-  working directory now based on revision 0
   $ hg --traceback --cwd b pull ../a | \
   >   python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
   pulling from ../a
diff --git a/tests/test-push-http.t b/tests/test-push-http.t
--- a/tests/test-push-http.t
+++ b/tests/test-push-http.t
@@ -64,7 +64,6 @@
   % serve errors
   $ hg rollback
   repository tip rolled back to revision 0 (undo serve)
-  working directory now based on revision 0
 
 expect success, server lacks the httpheader capability
 
@@ -81,7 +80,6 @@
   % serve errors
   $ hg rollback
   repository tip rolled back to revision 0 (undo serve)
-  working directory now based on revision 0
 
 expect success, server lacks the unbundlehash capability
 
@@ -98,7 +96,6 @@
   % serve errors
   $ hg rollback
   repository tip rolled back to revision 0 (undo serve)
-  working directory now based on revision 0
 
 expect authorization error: all users denied
 
diff --git a/tests/test-rollback.t b/tests/test-rollback.t
--- a/tests/test-rollback.t
+++ b/tests/test-rollback.t
@@ -64,6 +64,35 @@
   $ hg branch
   test
 
+working dir unaffected by rollback: do not restore dirstate et. al.
+  $ hg log --template '{rev}  {branch}  {desc|firstline}\n'
+  0  default  add a again
+  $ hg status
+  M a
+  $ hg bookmark foo
+  $ hg commit -m'modify a again'
+  $ echo b > b
+  $ hg commit -Am'add b'
+  adding b
+  $ hg log --template '{rev}  {branch}  {desc|firstline}\n'
+  2  test  add b
+  1  test  modify a again
+  0  default  add a again
+  $ hg update default
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg bookmark bar
+  $ cat .hg/undo.branch ; echo
+  test
+  $ hg rollback
+  repository tip rolled back to revision 1 (undo commit)
+  $ hg id -n
+  0
+  $ hg branch
+  default
+  $ cat .hg/bookmarks.current ; echo
+  bar
+  $ hg bookmark --delete foo
+
 rollback by pretxncommit saves commit message (issue 1635)
 
   $ echo a >> a
@@ -102,18 +131,18 @@
   adding changesets
   adding manifests
   adding file changes
-  added 2 changesets with 2 changes to 1 files
+  added 3 changesets with 2 changes to 1 files (+1 heads)
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd u
   $ hg id default
-  8902593132ae
+  068774709090
 
 now rollback and observe that 'hg serve' reloads the repository and
 presents the correct tip changeset:
 
   $ hg -R ../t rollback
-  repository tip rolled back to revision 0 (undo commit)
+  repository tip rolled back to revision 1 (undo commit)
   working directory now based on revision 0
   $ hg id default
-  23b0221f3370
+  791dd2169706
diff --git a/tests/test-url-rev.t b/tests/test-url-rev.t
--- a/tests/test-url-rev.t
+++ b/tests/test-url-rev.t
@@ -102,7 +102,6 @@
   $ cd clone
   $ hg rollback
   repository tip rolled back to revision 1 (undo push)
-  working directory now based on revision 1
 
   $ hg -q incoming
   2:faba9097cad4
@@ -147,10 +146,6 @@
 
   $ hg rollback
   repository tip rolled back to revision 1 (undo pull)
-  working directory now based on revision 1
-
-  $ hg up -C 0
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
   $ hg parents -q
   0:1f0dee641bb7


More information about the Mercurial-devel mailing list