##// END OF EJS Templates
add a fix for issue 1175...
add a fix for issue 1175 If we copy a file followed by an update, it's possible for the parent manifest to no longer contain the source file of the copy, which could cause commit to fail. If this happens, we search backwares from the first parent to find the most likely original revision.

File last commit:

r6750:fb42030d default
r6875:0d714a48 default
Show More
repair.py
136 lines | 4.6 KiB | text/x-python | PythonLexer
Matt Mackall
strip: move strip code to a new repair module
r4702 # repair.py - functions for repository repair for mercurial
#
# Copyright 2005, 2006 Chris Mason <mason@suse.com>
# Copyright 2007 Matt Mackall
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Alexis S. L. Carvalho
repair.py: use node.* directly
r5899 import changegroup, os
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from node import nullrev, short
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 def _bundle(repo, bases, heads, node, suffix, extranodes=None):
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 """create a bundle with the specified revisions as a backup"""
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 cg = repo.changegroupsubset(bases, heads, 'strip', extranodes)
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 backupdir = repo.join("strip-backup")
if not os.path.isdir(backupdir):
os.mkdir(backupdir)
name = os.path.join(backupdir, "%s-%s" % (short(node), suffix))
repo.ui.warn("saving bundle to %s\n" % name)
return changegroup.writebundle(cg, name, "HG10BZ")
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 def _collectfiles(repo, striprev):
"""find out the filelogs affected by the strip"""
files = {}
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 for x in xrange(striprev, repo.changelog.count()):
for name in repo.changectx(x).files():
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 if name in files:
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 continue
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 files[name] = 1
Alexis S. L. Carvalho
repair.py: split stripall into two functions; clean it up a bit
r5902
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 files = files.keys()
files.sort()
return files
Alexis S. L. Carvalho
repair.py: split stripall into two functions; clean it up a bit
r5902
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 def _collectextranodes(repo, files, link):
"""return the nodes that have to be saved before the strip"""
def collectone(revlog):
extra = []
startrev = count = revlog.count()
# find the truncation point of the revlog
for i in xrange(0, count):
node = revlog.node(i)
lrev = revlog.linkrev(node)
if lrev >= link:
startrev = i + 1
break
# see if any revision after that point has a linkrev less than link
# (we have to manually save these guys)
for i in xrange(startrev, count):
node = revlog.node(i)
lrev = revlog.linkrev(node)
if lrev < link:
extra.append((node, cl.node(lrev)))
return extra
extranodes = {}
cl = repo.changelog
extra = collectone(repo.manifest)
if extra:
extranodes[1] = extra
for fname in files:
f = repo.file(fname)
extra = collectone(f)
if extra:
extranodes[fname] = extra
return extranodes
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 def strip(ui, repo, node, backup="all"):
Alexis S. L. Carvalho
repair.py: rename chlog to cl
r5901 cl = repo.changelog
Matt Mackall
strip: move strip code to a new repair module
r4702 # TODO delete the undo files, and handle undo of merge sets
Alexis S. L. Carvalho
repair.py: rename chlog to cl
r5901 pp = cl.parents(node)
striprev = cl.rev(node)
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
repair.py: rewrite a loop, making it cleaner and faster
r6147 # Some revisions with rev > striprev may not be descendants of striprev.
# We have to find these revisions and put them in a bundle, so that
# we can restore them after the truncations.
# To create the bundle we use repo.changegroupsubset which requires
# the list of heads and bases of the set of interesting revisions.
# (head = revision in the set that has no descendant in the set;
# base = revision in the set that has no ancestor in the set)
tostrip = {striprev: 1}
saveheads = {}
savebases = []
for r in xrange(striprev + 1, cl.count()):
parents = cl.parentrevs(r)
if parents[0] in tostrip or parents[1] in tostrip:
# r is a descendant of striprev
tostrip[r] = 1
# if this is a merge and one of the parents does not descend
# from striprev, mark that parent as a savehead.
if parents[1] != nullrev:
for p in parents:
if p not in tostrip and p > striprev:
saveheads[p] = 1
else:
# if no parents of this revision will be stripped, mark it as
# a savebase
if parents[0] < striprev and parents[1] < striprev:
savebases.append(cl.node(r))
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
repair.py: rewrite a loop, making it cleaner and faster
r6147 for p in parents:
if p in saveheads:
del saveheads[p]
saveheads[r] = 1
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
repair.py: rewrite a loop, making it cleaner and faster
r6147 saveheads = [cl.node(r) for r in saveheads]
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 files = _collectfiles(repo, striprev)
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 extranodes = _collectextranodes(repo, files, striprev)
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Matt Mackall
strip: move strip code to a new repair module
r4702 # create a changegroup for all the branches we need to keep
if backup == "all":
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 _bundle(repo, [node], cl.heads(), node, 'backup')
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 if saveheads or extranodes:
Alexis S. L. Carvalho
repair.py: rewrite a loop, making it cleaner and faster
r6147 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 extranodes)
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 cl.strip(striprev)
repo.manifest.strip(striprev)
for name in files:
f = repo.file(name)
f.strip(striprev)
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 if saveheads or extranodes:
Matt Mackall
strip: move strip code to a new repair module
r4702 ui.status("adding branch\n")
Alexis S. L. Carvalho
repair.py: don't import commands.py
r5898 f = open(chgrpfile, "rb")
gen = changegroup.readbundle(f, chgrpfile)
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
Alexis S. L. Carvalho
repair.py: don't import commands.py
r5898 f.close()
Matt Mackall
strip: move strip code to a new repair module
r4702 if backup != "strip":
os.unlink(chgrpfile)