changeset 25713:2ca116614cfc

shelve: only keep the latest N shelve backups This will keep the backup directory from growing indefinitely. The number of backups to keep can be set using the shelve.maxbackups config option (defaults to 10 backups).
author Colin Chan <colinchan@fb.com>
date Wed, 01 Jul 2015 13:14:03 -0700
parents 8a6264a2ee60
children d50677c3bf44
files hgext/shelve.py tests/test-shelve.t
diffstat 2 files changed, 35 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/shelve.py	Wed Jul 01 13:13:02 2015 -0700
+++ b/hgext/shelve.py	Wed Jul 01 13:14:03 2015 -0700
@@ -40,6 +40,8 @@
 # leave the attribute unspecified.
 testedwith = 'internal'
 
+backupdir = 'shelve-backup'
+
 class shelvedfile(object):
     """Helper for the file storing a single shelve
 
@@ -49,7 +51,7 @@
         self.repo = repo
         self.name = name
         self.vfs = scmutil.vfs(repo.join('shelved'))
-        self.backupvfs = scmutil.vfs(repo.join('shelve-backup'))
+        self.backupvfs = scmutil.vfs(repo.join(backupdir))
         self.ui = self.repo.ui
         if filetype:
             self.fname = name + '.' + filetype
@@ -156,6 +158,20 @@
     def clear(cls, repo):
         util.unlinkpath(repo.join(cls._filename), ignoremissing=True)
 
+def cleanupoldbackups(repo):
+    vfs = scmutil.vfs(repo.join(backupdir))
+    maxbackups = repo.ui.configint('shelve', 'maxbackups', 10)
+    hgfiles = [f for f in vfs.listdir() if f.endswith('.hg')]
+    hgfiles = sorted([(vfs.stat(f).st_mtime, f) for f in hgfiles])
+    for mtime, f in hgfiles[:len(hgfiles) - maxbackups]:
+        base = f[:-3]
+        for ext in 'hg patch'.split():
+            try:
+                vfs.unlink(base + '.' + ext)
+            except OSError as err:
+                if err.errno != errno.ENOENT:
+                    raise
+
 def createcmd(ui, repo, pats, opts):
     """subcommand that creates a new shelve"""
 
@@ -298,6 +314,7 @@
             suffix = name.rsplit('.', 1)[-1]
             if suffix in ('hg', 'patch'):
                 shelvedfile(repo, name).movetobackup()
+            cleanupoldbackups(repo)
     finally:
         lockmod.release(wlock)
 
@@ -310,6 +327,7 @@
         for name in pats:
             for suffix in 'hg patch'.split():
                 shelvedfile(repo, name, suffix).movetobackup()
+        cleanupoldbackups(repo)
     except OSError as err:
         if err.errno != errno.ENOENT:
             raise
@@ -459,6 +477,7 @@
     if not opts['keep']:
         for filetype in 'hg patch'.split():
             shelvedfile(repo, name, filetype).movetobackup()
+        cleanupoldbackups(repo)
 
 def unshelvecontinue(ui, repo, state, opts):
     """subcommand to continue an in-progress unshelve"""
@@ -534,6 +553,11 @@
     (Alternatively, you can use ``--abort`` to abandon an unshelve
     that causes a conflict. This reverts the unshelved changes, and
     leaves the bundle in place.)
+
+    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
+    configuration option.
     """
     abortf = opts['abort']
     continuef = opts['continue']
--- a/tests/test-shelve.t	Wed Jul 01 13:13:02 2015 -0700
+++ b/tests/test-shelve.t	Wed Jul 01 13:14:03 2015 -0700
@@ -5,6 +5,8 @@
   > [defaults]
   > diff = --nodates --git
   > qnew = --date '0 0'
+  > [shelve]
+  > maxbackups = 2
   > EOF
 
   $ hg init repo
@@ -248,6 +250,14 @@
     c
   R b/b
 
+ensure old shelve backups are being deleted automatically
+
+  $ ls .hg/shelve-backup/
+  default-01.hg
+  default-01.patch
+  wibble.hg
+  wibble.patch
+
 cause unshelving to result in a merge with 'a' conflicting
 
   $ hg shelve -q