diff mercurial/repair.py @ 23835:aa4a1672583e

bundles: do not overwrite existing backup bundles (BC) Previously, a backup bundle could overwrite an existing bundle and cause user data loss. For instance, if you have A<-B<-C and strip B, it produces backup bundle B-backup.hg. If you then hg pull -r B B-backup.hg and strip it again, it overwrites the existing B-backup.hg and C is lost. The fix is to add a hash of all the nodes inside that bundle to the filename. Fixed up existing tests and added a new test in test-strip.t
author Durham Goode <durham@fb.com>
date Fri, 09 Jan 2015 10:52:14 -0800
parents d7b114493315
children 37a92908a382
line wrap: on
line diff
--- a/mercurial/repair.py	Mon Jan 12 18:01:20 2015 -0700
+++ b/mercurial/repair.py	Fri Jan 09 10:52:14 2015 -0800
@@ -6,8 +6,8 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from mercurial import changegroup, exchange
-from mercurial.node import short
+from mercurial import changegroup, exchange, util
+from mercurial.node import short, hex
 from mercurial.i18n import _
 import errno
 
@@ -18,7 +18,15 @@
     vfs = repo.vfs
     if not vfs.isdir(backupdir):
         vfs.mkdir(backupdir)
-    name = "%s/%s-%s.hg" % (backupdir, short(node), suffix)
+
+    # Include a hash of all the nodes in the filename for uniqueness
+    hexbases = (hex(n) for n in bases)
+    hexheads = (hex(n) for n in heads)
+    allcommits = repo.set('%ls::%ls', hexbases, hexheads)
+    allhashes = sorted(c.hex() for c in allcommits)
+    totalhash = util.sha1(''.join(allhashes)).hexdigest()
+    name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix)
+
     if compress:
         bundletype = "HG10BZ"
     else: