comparison 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
comparison
equal deleted inserted replaced
23834:bf07c19b4c82 23835:aa4a1672583e
4 # Copyright 2007 Matt Mackall 4 # Copyright 2007 Matt Mackall
5 # 5 #
6 # This software may be used and distributed according to the terms of the 6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version. 7 # GNU General Public License version 2 or any later version.
8 8
9 from mercurial import changegroup, exchange 9 from mercurial import changegroup, exchange, util
10 from mercurial.node import short 10 from mercurial.node import short, hex
11 from mercurial.i18n import _ 11 from mercurial.i18n import _
12 import errno 12 import errno
13 13
14 def _bundle(repo, bases, heads, node, suffix, compress=True): 14 def _bundle(repo, bases, heads, node, suffix, compress=True):
15 """create a bundle with the specified revisions as a backup""" 15 """create a bundle with the specified revisions as a backup"""
16 cg = changegroup.changegroupsubset(repo, bases, heads, 'strip') 16 cg = changegroup.changegroupsubset(repo, bases, heads, 'strip')
17 backupdir = "strip-backup" 17 backupdir = "strip-backup"
18 vfs = repo.vfs 18 vfs = repo.vfs
19 if not vfs.isdir(backupdir): 19 if not vfs.isdir(backupdir):
20 vfs.mkdir(backupdir) 20 vfs.mkdir(backupdir)
21 name = "%s/%s-%s.hg" % (backupdir, short(node), suffix) 21
22 # Include a hash of all the nodes in the filename for uniqueness
23 hexbases = (hex(n) for n in bases)
24 hexheads = (hex(n) for n in heads)
25 allcommits = repo.set('%ls::%ls', hexbases, hexheads)
26 allhashes = sorted(c.hex() for c in allcommits)
27 totalhash = util.sha1(''.join(allhashes)).hexdigest()
28 name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix)
29
22 if compress: 30 if compress:
23 bundletype = "HG10BZ" 31 bundletype = "HG10BZ"
24 else: 32 else:
25 bundletype = "HG10UN" 33 bundletype = "HG10UN"
26 return changegroup.writebundle(cg, name, bundletype, vfs) 34 return changegroup.writebundle(cg, name, bundletype, vfs)