# HG changeset patch # User FUJIWARA Katsunori # Date 1436798052 -32400 # Node ID 4f8c20fe66f03f3e69fea62f364ebff33c9aa51c # Parent de654a83fe1c95949effe7e6e7598d60364d8b3a shelve: keep old backups if timestamp can't decide exact order of them Before this patch, backups to be discarded are decided by steps below at 'hg unshelve' or so: 1. list '(st_mtime, filename)' tuples of each backups up 2. sort list of these tuples, and 3. discard backups other than 'maxbackups' ones at the end of list This doesn't work well in the case below: - "sort by name" order differs from actual backup-ing order, and - some of backups have same timestamp For example, 'test-shelve.t' satisfies the former condition: - 'default-01' < 'default-1' in "sort by name" order - 'default-1' < 'default-01' in actual backup-ing order Then, 'default-01' is discarded instead of 'default-1' unexpectedly, if they have same timestamp. This failure appears occasionally, because the most important condition "same timestamp" is timing critical. To avoid such unexpected discarding, this patch keeps old backups if timestamp can't decide exact order of them. Timestamp of the border backup (= the oldest one of recent 'maxbackups' ones) as 'bordermtime' is used to examine whether timestamp can decide exact order of backups. diff -r de654a83fe1c -r 4f8c20fe66f0 hgext/shelve.py --- a/hgext/shelve.py Fri Jul 10 00:59:51 2015 +0900 +++ b/hgext/shelve.py Mon Jul 13 23:34:12 2015 +0900 @@ -163,7 +163,14 @@ 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]) + if 0 < maxbackups and maxbackups < len(hgfiles): + bordermtime = hgfiles[-maxbackups][0] + else: + bordermtime = None for mtime, f in hgfiles[:len(hgfiles) - maxbackups]: + if mtime == bordermtime: + # keep it, because timestamp can't decide exact order of backups + continue base = f[:-3] for ext in 'hg patch'.split(): try: @@ -558,6 +565,12 @@ backup directory. Only the N most recent backups are kept. N defaults to 10 but can be overridden using the shelve.maxbackups configuration option. + + .. container:: verbose + + Timestamp in seconds is used to decide order of backups. More + than ``maxbackups`` backups are kept, if same timestamp + prevents from deciding exact order of them, for safety. """ abortf = opts['abort'] continuef = opts['continue'] diff -r de654a83fe1c -r 4f8c20fe66f0 tests/test-shelve.t --- a/tests/test-shelve.t Fri Jul 10 00:59:51 2015 +0900 +++ b/tests/test-shelve.t Mon Jul 13 23:34:12 2015 +0900 @@ -185,6 +185,16 @@ apply it and make sure our state is as expected +(this also tests that same timestamp prevents backups from being +removed, even though there are more than 'maxbackups' backups) + + $ f -t .hg/shelve-backup/default.hg + .hg/shelve-backup/default.hg: file + $ touch -t 200001010000 .hg/shelve-backup/default.hg + $ f -t .hg/shelve-backup/default-1.hg + .hg/shelve-backup/default-1.hg: file + $ touch -t 200001010000 .hg/shelve-backup/default-1.hg + $ hg unshelve unshelving change 'default-01' $ hg status -C @@ -196,6 +206,17 @@ R b/b $ hg shelve -l +(both of default.hg and default-1.hg should be still kept, because it +is difficult to decide actual order of them from same timestamp) + + $ ls .hg/shelve-backup/ + default-01.hg + default-01.patch + default-1.hg + default-1.patch + default.hg + default.patch + $ hg unshelve abort: no shelved changes to apply! [255]