diff --git a/mercurial/repair.py b/mercurial/repair.py --- a/mercurial/repair.py +++ b/mercurial/repair.py @@ -118,11 +118,25 @@ def strip(ui, repo, node, backup="all"): chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', extranodes) - cl.strip(striprev) - repo.manifest.strip(striprev) - for name in files: - f = repo.file(name) - f.strip(striprev) + fs = [repo.file(name) for name in files] + mfst = repo.manifest + + tr = repo.transaction() + offset = len(tr.entries) + + cl.strip(striprev, tr) + mfst.strip(striprev, tr) + for f in fs: + f.strip(striprev, tr) + + try: + for i in xrange(offset, len(tr.entries)): + file, troffset, ignore = tr.entries[i] + repo.sopener(file, 'a').truncate(troffset) + tr.close() + except: + tr.abort() + raise if saveheads or extranodes: ui.status(_("adding branch\n")) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -1285,7 +1285,7 @@ class revlog(object): return node - def strip(self, minlink): + def strip(self, minlink, transaction): """truncate the revlog on the first revision with a linkrev >= minlink This function is called when we're stripping revision minlink and @@ -1314,14 +1314,12 @@ class revlog(object): # first truncate the files on disk end = self.start(rev) if not self._inline: - df = self.opener(self.datafile, "a") - df.truncate(end) + transaction.add(self.datafile, end) end = rev * self._io.size else: end += rev * self._io.size - indexf = self.opener(self.indexfile, "a") - indexf.truncate(end) + transaction.add(self.indexfile, end) # then reset internal state in memory to forget those revisions self._cache = None diff --git a/tests/test-repair-strip b/tests/test-repair-strip new file mode 100755 --- /dev/null +++ b/tests/test-repair-strip @@ -0,0 +1,36 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "mq=">> $HGRCPATH + +teststrip() { + hg -q up -C $1 + echo % before update $1, strip $2 + hg parents + chmod -$3 $4 + hg strip $2 2>&1 | sed 's/\(saving bundle to \).*/\1/' | sed 's/Permission denied.*\.hg\/store\/\(.*\)/Permission denied \.hg\/store\/\1/' + echo % after update $1, strip $2 + chmod +$3 $4 + hg verify + echo % journal contents + cat .hg/store/journal | sed 's/\.i[^\n]*/\.i/' + ls .hg/store/journal >/dev/null 2>&1 && hg recover + ls .hg/strip-backup/* >/dev/null 2>&1 && hg unbundle -q .hg/strip-backup/* + rm -rf .hg/strip-backup +} + +hg init test +cd test + +echo a > a +hg -q ci -m "a" -A + +echo b > b +hg -q ci -m "b" -A + +echo c > c +hg -q ci -m "c" -A + +teststrip 0 1 w .hg/store/data/b.i +teststrip 0 1 r .hg/store/data/b.i +teststrip 0 1 w .hg/store/00changelog.i diff --git a/tests/test-repair-strip.out b/tests/test-repair-strip.out new file mode 100644 --- /dev/null +++ b/tests/test-repair-strip.out @@ -0,0 +1,83 @@ +% before update 0, strip 1 +changeset: 0:cb9a9f314b8b +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: a + +saving bundle to +transaction abort! +failed to truncate data/b.i +rollback failed - please run hg recover +abort: Permission denied .hg/store/data/b.i +% after update 0, strip 1 +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +warning: orphan revlog 'data/b.i' +1 files, 1 changesets, 1 total revisions +1 warnings encountered! +% journal contents +00changelog.i +00manifest.i +data/b.i +data/c.i +rolling back interrupted transaction +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +1 files, 1 changesets, 1 total revisions +% before update 0, strip 1 +changeset: 0:cb9a9f314b8b +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: a + +abort: Permission denied .hg/store/data/b.i +% after update 0, strip 1 +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +3 files, 3 changesets, 3 total revisions +% journal contents +cat: .hg/store/journal: No such file or directory +% before update 0, strip 1 +changeset: 0:cb9a9f314b8b +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: a + +saving bundle to +transaction abort! +failed to truncate 00changelog.i +rollback failed - please run hg recover +abort: Permission denied .hg/store/00changelog.i +% after update 0, strip 1 +checking changesets +checking manifests +crosschecking files in changesets and manifests + 1: changeset refers to unknown manifest a539ce0c1a22 + 2: changeset refers to unknown manifest e3738bf54399 + b@1: in changeset but not in manifest + c@2: in changeset but not in manifest +checking files + data/b.i@1: missing revlog! + 0: empty or missing b + data/c.i@2: missing revlog! + 0: empty or missing c +3 files, 3 changesets, 1 total revisions +8 integrity errors encountered! +(first damaged changeset appears to be 0) +% journal contents +00changelog.i +00manifest.i +data/b.i +data/c.i +rolling back interrupted transaction +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +1 files, 1 changesets, 1 total revisions