changeset 16430:6883c2363f44

revert: add support for reverting subrepos without --no-backup and/or --all When a subrepo is reverted but --no-backup is not set, call revert on the subrepo that is being reverted prior to updating it to the revision specified in the parent repo's .hgsubstate file. The --all flag is passed down to the subrepo when it is being reverted. If the --all flag is not set, all files that are modified on the subrepo will be reverted.
author Angel Ezquerra <angel.ezquerra@gmail.com>
date Wed, 28 Mar 2012 11:42:17 +0200
parents 71dcce391a44
children c85098cdd7df
files mercurial/cmdutil.py mercurial/subrepo.py tests/test-subrepo.t
diffstat 3 files changed, 37 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/cmdutil.py	Wed Mar 28 11:42:17 2012 +0200
+++ b/mercurial/cmdutil.py	Wed Mar 28 11:42:17 2012 +0200
@@ -1369,11 +1369,8 @@
             if abs not in names:
                 names[abs] = m.rel(abs), m.exact(abs)
 
+        # get the list of subrepos that must be reverted
         targetsubs = [s for s in repo[node].substate if m(s)]
-        if targetsubs and not opts.get('no_backup'):
-            msg = _("cannot revert subrepos without --no-backup")
-            raise util.Abort(msg)
-
         m = scmutil.matchfiles(repo, names)
         changes = repo.status(match=m)[:4]
         modified, added, removed, deleted = map(set, changes)
--- a/mercurial/subrepo.py	Wed Mar 28 11:42:17 2012 +0200
+++ b/mercurial/subrepo.py	Wed Mar 28 11:42:17 2012 +0200
@@ -577,13 +577,37 @@
                               os.path.join(prefix, self._path), True)
 
     def revert(self, ui, substate, *pats, **opts):
-        # reverting a subrepo is done by updating it to the revision
-        # specified in the corresponding substate dictionary
+        # reverting a subrepo is a 2 step process:
+        # 1. if the no_backup is not set, revert all modified
+        #    files inside the subrepo
+        # 2. update the subrepo to the revision specified in
+        #    the corresponding substate dictionary
         ui.status(_('reverting subrepo %s\n') % substate[0])
+        if not opts.get('no_backup'):
+            # Revert all files on the subrepo, creating backups
+            # Note that this will not recursively revert subrepos
+            # We could do it if there was a set:subrepos() predicate
+            opts = opts.copy()
+            opts['date'] = None
+            opts['rev'] = substate[1]
+
+            pats = []
+            if not opts['all']:
+                pats = ['set:modified()']
+            self.filerevert(ui, *pats, **opts)
 
         # Update the repo to the revision specified in the given substate
         self.get(substate, overwrite=True)
 
+    def filerevert(self, ui, *pats, **opts):
+        ctx = self._repo[opts['rev']]
+        parents = self._repo.dirstate.parents()
+        if opts['all']:
+            pats = ['set:modified()']
+        else:
+            pats = []
+        cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
+
 class svnsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state):
         self._path = path
--- a/tests/test-subrepo.t	Wed Mar 28 11:42:17 2012 +0200
+++ b/tests/test-subrepo.t	Wed Mar 28 11:42:17 2012 +0200
@@ -38,20 +38,20 @@
   update: (current)
   $ hg ci -m1
 
-Revert can't (yet) revert subrepos:
+Revert subrepo:
 
   $ echo b > s/a
   $ hg revert s
-  abort: cannot revert subrepos without --no-backup
-  [255]
-
-Revert currently ignores subrepos by default
+  reverting subrepo s
+  reverting s/a
+  $ rm s/a.orig
 
-  $ hg revert -a
-  abort: cannot revert subrepos without --no-backup
-  [255]
-  $ hg revert -R s -a -C
-  reverting s/a (glob)
+Revert subrepo with no backup. The "reverting s/a" line is gone since
+we're really running 'hg update' in the subrepo:
+
+  $ echo b > s/a
+  $ hg revert --no-backup s
+  reverting subrepo s
 
 Issue2022: update -C