--- a/hgext/mq.py Sun Jun 24 10:08:38 2007 -0500
+++ b/hgext/mq.py Sun Jun 24 18:22:40 2007 -0500
@@ -39,6 +39,125 @@
# They must be joinable with queue directory and result in the patch path.
normname = util.normpath
+def _strip(ui, repo, rev, backup="all"):
+ def limitheads(chlog, stop):
+ """return the list of all nodes that have no children"""
+ p = {}
+ h = []
+ stoprev = 0
+ if stop in chlog.nodemap:
+ stoprev = chlog.rev(stop)
+
+ for r in xrange(chlog.count() - 1, -1, -1):
+ n = chlog.node(r)
+ if n not in p:
+ h.append(n)
+ if n == stop:
+ break
+ if r < stoprev:
+ break
+ for pn in chlog.parents(n):
+ p[pn] = 1
+ return h
+
+ def bundle(cg):
+ backupdir = repo.join("strip-backup")
+ if not os.path.isdir(backupdir):
+ os.mkdir(backupdir)
+ name = os.path.join(backupdir, "%s" % revlog.short(rev))
+ name = savename(name)
+ ui.warn("saving bundle to %s\n" % name)
+ return changegroup.writebundle(cg, name, "HG10BZ")
+
+ def stripall(revnum):
+ mm = repo.changectx(rev).manifest()
+ seen = {}
+
+ for x in xrange(revnum, repo.changelog.count()):
+ for f in repo.changectx(x).files():
+ if f in seen:
+ continue
+ seen[f] = 1
+ if f in mm:
+ filerev = mm[f]
+ else:
+ filerev = 0
+ seen[f] = filerev
+ # we go in two steps here so the strip loop happens in a
+ # sensible order. When stripping many files, this helps keep
+ # our disk access patterns under control.
+ seen_list = seen.keys()
+ seen_list.sort()
+ for f in seen_list:
+ ff = repo.file(f)
+ filerev = seen[f]
+ if filerev != 0:
+ if filerev in ff.nodemap:
+ filerev = ff.rev(filerev)
+ else:
+ filerev = 0
+ ff.strip(filerev, revnum)
+
+ chlog = repo.changelog
+ # TODO delete the undo files, and handle undo of merge sets
+ pp = chlog.parents(rev)
+ revnum = chlog.rev(rev)
+
+ # save is a list of all the branches we are truncating away
+ # that we actually want to keep. changegroup will be used
+ # to preserve them and add them back after the truncate
+ saveheads = []
+ savebases = {}
+
+ heads = limitheads(chlog, rev)
+ seen = {}
+
+ # search through all the heads, finding those where the revision
+ # we want to strip away is an ancestor. Also look for merges
+ # that might be turned into new heads by the strip.
+ while heads:
+ h = heads.pop()
+ n = h
+ while True:
+ seen[n] = 1
+ pp = chlog.parents(n)
+ if pp[1] != revlog.nullid:
+ for p in pp:
+ if chlog.rev(p) > revnum and p not in seen:
+ heads.append(p)
+ if pp[0] == revlog.nullid:
+ break
+ if chlog.rev(pp[0]) < revnum:
+ break
+ n = pp[0]
+ if n == rev:
+ break
+ r = chlog.reachable(h, rev)
+ if rev not in r:
+ saveheads.append(h)
+ for x in r:
+ if chlog.rev(x) > revnum:
+ savebases[x] = 1
+
+ # create a changegroup for all the branches we need to keep
+ if backup == "all":
+ backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
+ bundle(backupch)
+ if saveheads:
+ backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
+ chgrpfile = bundle(backupch)
+
+ stripall(revnum)
+
+ change = chlog.read(rev)
+ chlog.strip(revnum, revnum)
+ repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
+ if saveheads:
+ ui.status("adding branch\n")
+ commands.unbundle(ui, repo, "file:%s" % chgrpfile, update=False)
+ if backup != "strip":
+ os.unlink(chgrpfile)
+
class statusentry:
def __init__(self, rev, name=None):
if not name:
@@ -629,71 +748,9 @@
self.removeundo(repo)
def strip(self, repo, rev, update=True, backup="all", wlock=None):
- def limitheads(chlog, stop):
- """return the list of all nodes that have no children"""
- p = {}
- h = []
- stoprev = 0
- if stop in chlog.nodemap:
- stoprev = chlog.rev(stop)
-
- for r in xrange(chlog.count() - 1, -1, -1):
- n = chlog.node(r)
- if n not in p:
- h.append(n)
- if n == stop:
- break
- if r < stoprev:
- break
- for pn in chlog.parents(n):
- p[pn] = 1
- return h
-
- def bundle(cg):
- backupdir = repo.join("strip-backup")
- if not os.path.isdir(backupdir):
- os.mkdir(backupdir)
- name = os.path.join(backupdir, "%s" % revlog.short(rev))
- name = savename(name)
- self.ui.warn("saving bundle to %s\n" % name)
- return changegroup.writebundle(cg, name, "HG10BZ")
-
- def stripall(revnum):
- mm = repo.changectx(rev).manifest()
- seen = {}
-
- for x in xrange(revnum, repo.changelog.count()):
- for f in repo.changectx(x).files():
- if f in seen:
- continue
- seen[f] = 1
- if f in mm:
- filerev = mm[f]
- else:
- filerev = 0
- seen[f] = filerev
- # we go in two steps here so the strip loop happens in a
- # sensible order. When stripping many files, this helps keep
- # our disk access patterns under control.
- seen_list = seen.keys()
- seen_list.sort()
- for f in seen_list:
- ff = repo.file(f)
- filerev = seen[f]
- if filerev != 0:
- if filerev in ff.nodemap:
- filerev = ff.rev(filerev)
- else:
- filerev = 0
- ff.strip(filerev, revnum)
-
if not wlock:
wlock = repo.wlock()
lock = repo.lock()
- chlog = repo.changelog
- # TODO delete the undo files, and handle undo of merge sets
- pp = chlog.parents(rev)
- revnum = chlog.rev(rev)
if update:
self.check_localchanges(repo, refresh=False)
@@ -701,62 +758,8 @@
hg.clean(repo, urev, wlock=wlock)
repo.dirstate.write()
- # save is a list of all the branches we are truncating away
- # that we actually want to keep. changegroup will be used
- # to preserve them and add them back after the truncate
- saveheads = []
- savebases = {}
-
- heads = limitheads(chlog, rev)
- seen = {}
-
- # search through all the heads, finding those where the revision
- # we want to strip away is an ancestor. Also look for merges
- # that might be turned into new heads by the strip.
- while heads:
- h = heads.pop()
- n = h
- while True:
- seen[n] = 1
- pp = chlog.parents(n)
- if pp[1] != revlog.nullid:
- for p in pp:
- if chlog.rev(p) > revnum and p not in seen:
- heads.append(p)
- if pp[0] == revlog.nullid:
- break
- if chlog.rev(pp[0]) < revnum:
- break
- n = pp[0]
- if n == rev:
- break
- r = chlog.reachable(h, rev)
- if rev not in r:
- saveheads.append(h)
- for x in r:
- if chlog.rev(x) > revnum:
- savebases[x] = 1
-
- # create a changegroup for all the branches we need to keep
- if backup == "all":
- backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
- bundle(backupch)
- if saveheads:
- backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
- chgrpfile = bundle(backupch)
-
- stripall(revnum)
-
- change = chlog.read(rev)
- chlog.strip(revnum, revnum)
- repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
self.removeundo(repo)
- if saveheads:
- self.ui.status("adding branch\n")
- commands.unbundle(self.ui, repo, "file:%s" % chgrpfile,
- update=False)
- if backup != "strip":
- os.unlink(chgrpfile)
+ _strip(self.ui, repo, rev, backup)
def isapplied(self, patch):
"""returns (index, rev, patch)"""