Show More
@@ -39,6 +39,125 b' commands.norepo += " qclone qversion"' | |||
|
39 | 39 | # They must be joinable with queue directory and result in the patch path. |
|
40 | 40 | normname = util.normpath |
|
41 | 41 | |
|
42 | def _strip(ui, repo, rev, backup="all"): | |
|
43 | def limitheads(chlog, stop): | |
|
44 | """return the list of all nodes that have no children""" | |
|
45 | p = {} | |
|
46 | h = [] | |
|
47 | stoprev = 0 | |
|
48 | if stop in chlog.nodemap: | |
|
49 | stoprev = chlog.rev(stop) | |
|
50 | ||
|
51 | for r in xrange(chlog.count() - 1, -1, -1): | |
|
52 | n = chlog.node(r) | |
|
53 | if n not in p: | |
|
54 | h.append(n) | |
|
55 | if n == stop: | |
|
56 | break | |
|
57 | if r < stoprev: | |
|
58 | break | |
|
59 | for pn in chlog.parents(n): | |
|
60 | p[pn] = 1 | |
|
61 | return h | |
|
62 | ||
|
63 | def bundle(cg): | |
|
64 | backupdir = repo.join("strip-backup") | |
|
65 | if not os.path.isdir(backupdir): | |
|
66 | os.mkdir(backupdir) | |
|
67 | name = os.path.join(backupdir, "%s" % revlog.short(rev)) | |
|
68 | name = savename(name) | |
|
69 | ui.warn("saving bundle to %s\n" % name) | |
|
70 | return changegroup.writebundle(cg, name, "HG10BZ") | |
|
71 | ||
|
72 | def stripall(revnum): | |
|
73 | mm = repo.changectx(rev).manifest() | |
|
74 | seen = {} | |
|
75 | ||
|
76 | for x in xrange(revnum, repo.changelog.count()): | |
|
77 | for f in repo.changectx(x).files(): | |
|
78 | if f in seen: | |
|
79 | continue | |
|
80 | seen[f] = 1 | |
|
81 | if f in mm: | |
|
82 | filerev = mm[f] | |
|
83 | else: | |
|
84 | filerev = 0 | |
|
85 | seen[f] = filerev | |
|
86 | # we go in two steps here so the strip loop happens in a | |
|
87 | # sensible order. When stripping many files, this helps keep | |
|
88 | # our disk access patterns under control. | |
|
89 | seen_list = seen.keys() | |
|
90 | seen_list.sort() | |
|
91 | for f in seen_list: | |
|
92 | ff = repo.file(f) | |
|
93 | filerev = seen[f] | |
|
94 | if filerev != 0: | |
|
95 | if filerev in ff.nodemap: | |
|
96 | filerev = ff.rev(filerev) | |
|
97 | else: | |
|
98 | filerev = 0 | |
|
99 | ff.strip(filerev, revnum) | |
|
100 | ||
|
101 | chlog = repo.changelog | |
|
102 | # TODO delete the undo files, and handle undo of merge sets | |
|
103 | pp = chlog.parents(rev) | |
|
104 | revnum = chlog.rev(rev) | |
|
105 | ||
|
106 | # save is a list of all the branches we are truncating away | |
|
107 | # that we actually want to keep. changegroup will be used | |
|
108 | # to preserve them and add them back after the truncate | |
|
109 | saveheads = [] | |
|
110 | savebases = {} | |
|
111 | ||
|
112 | heads = limitheads(chlog, rev) | |
|
113 | seen = {} | |
|
114 | ||
|
115 | # search through all the heads, finding those where the revision | |
|
116 | # we want to strip away is an ancestor. Also look for merges | |
|
117 | # that might be turned into new heads by the strip. | |
|
118 | while heads: | |
|
119 | h = heads.pop() | |
|
120 | n = h | |
|
121 | while True: | |
|
122 | seen[n] = 1 | |
|
123 | pp = chlog.parents(n) | |
|
124 | if pp[1] != revlog.nullid: | |
|
125 | for p in pp: | |
|
126 | if chlog.rev(p) > revnum and p not in seen: | |
|
127 | heads.append(p) | |
|
128 | if pp[0] == revlog.nullid: | |
|
129 | break | |
|
130 | if chlog.rev(pp[0]) < revnum: | |
|
131 | break | |
|
132 | n = pp[0] | |
|
133 | if n == rev: | |
|
134 | break | |
|
135 | r = chlog.reachable(h, rev) | |
|
136 | if rev not in r: | |
|
137 | saveheads.append(h) | |
|
138 | for x in r: | |
|
139 | if chlog.rev(x) > revnum: | |
|
140 | savebases[x] = 1 | |
|
141 | ||
|
142 | # create a changegroup for all the branches we need to keep | |
|
143 | if backup == "all": | |
|
144 | backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') | |
|
145 | bundle(backupch) | |
|
146 | if saveheads: | |
|
147 | backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') | |
|
148 | chgrpfile = bundle(backupch) | |
|
149 | ||
|
150 | stripall(revnum) | |
|
151 | ||
|
152 | change = chlog.read(rev) | |
|
153 | chlog.strip(revnum, revnum) | |
|
154 | repo.manifest.strip(repo.manifest.rev(change[0]), revnum) | |
|
155 | if saveheads: | |
|
156 | ui.status("adding branch\n") | |
|
157 | commands.unbundle(ui, repo, "file:%s" % chgrpfile, update=False) | |
|
158 | if backup != "strip": | |
|
159 | os.unlink(chgrpfile) | |
|
160 | ||
|
42 | 161 | class statusentry: |
|
43 | 162 | def __init__(self, rev, name=None): |
|
44 | 163 | if not name: |
@@ -629,71 +748,9 b' class queue:' | |||
|
629 | 748 | self.removeundo(repo) |
|
630 | 749 | |
|
631 | 750 | def strip(self, repo, rev, update=True, backup="all", wlock=None): |
|
632 | def limitheads(chlog, stop): | |
|
633 | """return the list of all nodes that have no children""" | |
|
634 | p = {} | |
|
635 | h = [] | |
|
636 | stoprev = 0 | |
|
637 | if stop in chlog.nodemap: | |
|
638 | stoprev = chlog.rev(stop) | |
|
639 | ||
|
640 | for r in xrange(chlog.count() - 1, -1, -1): | |
|
641 | n = chlog.node(r) | |
|
642 | if n not in p: | |
|
643 | h.append(n) | |
|
644 | if n == stop: | |
|
645 | break | |
|
646 | if r < stoprev: | |
|
647 | break | |
|
648 | for pn in chlog.parents(n): | |
|
649 | p[pn] = 1 | |
|
650 | return h | |
|
651 | ||
|
652 | def bundle(cg): | |
|
653 | backupdir = repo.join("strip-backup") | |
|
654 | if not os.path.isdir(backupdir): | |
|
655 | os.mkdir(backupdir) | |
|
656 | name = os.path.join(backupdir, "%s" % revlog.short(rev)) | |
|
657 | name = savename(name) | |
|
658 | self.ui.warn("saving bundle to %s\n" % name) | |
|
659 | return changegroup.writebundle(cg, name, "HG10BZ") | |
|
660 | ||
|
661 | def stripall(revnum): | |
|
662 | mm = repo.changectx(rev).manifest() | |
|
663 | seen = {} | |
|
664 | ||
|
665 | for x in xrange(revnum, repo.changelog.count()): | |
|
666 | for f in repo.changectx(x).files(): | |
|
667 | if f in seen: | |
|
668 | continue | |
|
669 | seen[f] = 1 | |
|
670 | if f in mm: | |
|
671 | filerev = mm[f] | |
|
672 | else: | |
|
673 | filerev = 0 | |
|
674 | seen[f] = filerev | |
|
675 | # we go in two steps here so the strip loop happens in a | |
|
676 | # sensible order. When stripping many files, this helps keep | |
|
677 | # our disk access patterns under control. | |
|
678 | seen_list = seen.keys() | |
|
679 | seen_list.sort() | |
|
680 | for f in seen_list: | |
|
681 | ff = repo.file(f) | |
|
682 | filerev = seen[f] | |
|
683 | if filerev != 0: | |
|
684 | if filerev in ff.nodemap: | |
|
685 | filerev = ff.rev(filerev) | |
|
686 | else: | |
|
687 | filerev = 0 | |
|
688 | ff.strip(filerev, revnum) | |
|
689 | ||
|
690 | 751 | if not wlock: |
|
691 | 752 | wlock = repo.wlock() |
|
692 | 753 | lock = repo.lock() |
|
693 | chlog = repo.changelog | |
|
694 | # TODO delete the undo files, and handle undo of merge sets | |
|
695 | pp = chlog.parents(rev) | |
|
696 | revnum = chlog.rev(rev) | |
|
697 | 754 | |
|
698 | 755 | if update: |
|
699 | 756 | self.check_localchanges(repo, refresh=False) |
@@ -701,62 +758,8 b' class queue:' | |||
|
701 | 758 | hg.clean(repo, urev, wlock=wlock) |
|
702 | 759 | repo.dirstate.write() |
|
703 | 760 | |
|
704 | # save is a list of all the branches we are truncating away | |
|
705 | # that we actually want to keep. changegroup will be used | |
|
706 | # to preserve them and add them back after the truncate | |
|
707 | saveheads = [] | |
|
708 | savebases = {} | |
|
709 | ||
|
710 | heads = limitheads(chlog, rev) | |
|
711 | seen = {} | |
|
712 | ||
|
713 | # search through all the heads, finding those where the revision | |
|
714 | # we want to strip away is an ancestor. Also look for merges | |
|
715 | # that might be turned into new heads by the strip. | |
|
716 | while heads: | |
|
717 | h = heads.pop() | |
|
718 | n = h | |
|
719 | while True: | |
|
720 | seen[n] = 1 | |
|
721 | pp = chlog.parents(n) | |
|
722 | if pp[1] != revlog.nullid: | |
|
723 | for p in pp: | |
|
724 | if chlog.rev(p) > revnum and p not in seen: | |
|
725 | heads.append(p) | |
|
726 | if pp[0] == revlog.nullid: | |
|
727 | break | |
|
728 | if chlog.rev(pp[0]) < revnum: | |
|
729 | break | |
|
730 | n = pp[0] | |
|
731 | if n == rev: | |
|
732 | break | |
|
733 | r = chlog.reachable(h, rev) | |
|
734 | if rev not in r: | |
|
735 | saveheads.append(h) | |
|
736 | for x in r: | |
|
737 | if chlog.rev(x) > revnum: | |
|
738 | savebases[x] = 1 | |
|
739 | ||
|
740 | # create a changegroup for all the branches we need to keep | |
|
741 | if backup == "all": | |
|
742 | backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') | |
|
743 | bundle(backupch) | |
|
744 | if saveheads: | |
|
745 | backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') | |
|
746 | chgrpfile = bundle(backupch) | |
|
747 | ||
|
748 | stripall(revnum) | |
|
749 | ||
|
750 | change = chlog.read(rev) | |
|
751 | chlog.strip(revnum, revnum) | |
|
752 | repo.manifest.strip(repo.manifest.rev(change[0]), revnum) | |
|
753 | 761 | self.removeundo(repo) |
|
754 | if saveheads: | |
|
755 | self.ui.status("adding branch\n") | |
|
756 | commands.unbundle(self.ui, repo, "file:%s" % chgrpfile, | |
|
757 | update=False) | |
|
758 | if backup != "strip": | |
|
759 | os.unlink(chgrpfile) | |
|
762 | _strip(self.ui, repo, rev, backup) | |
|
760 | 763 | |
|
761 | 764 | def isapplied(self, patch): |
|
762 | 765 | """returns (index, rev, patch)""" |
General Comments 0
You need to be logged in to leave comments.
Login now