52 for fname in files: |
52 for fname in files: |
53 collectone(repo.file(fname)) |
53 collectone(repo.file(fname)) |
54 |
54 |
55 return s |
55 return s |
56 |
56 |
57 def strip(ui, repo, node, backup="all"): |
57 def strip(ui, repo, nodelist, backup="all"): |
58 cl = repo.changelog |
58 cl = repo.changelog |
59 # TODO delete the undo files, and handle undo of merge sets |
59 # TODO delete the undo files, and handle undo of merge sets |
60 striprev = cl.rev(node) |
60 if isinstance(nodelist, str): |
|
61 nodelist = [nodelist] |
|
62 striplist = [cl.rev(node) for node in nodelist] |
|
63 striprev = min(striplist) |
61 |
64 |
62 keeppartialbundle = backup == 'strip' |
65 keeppartialbundle = backup == 'strip' |
63 |
66 |
64 # Some revisions with rev > striprev may not be descendants of striprev. |
67 # Some revisions with rev > striprev may not be descendants of striprev. |
65 # We have to find these revisions and put them in a bundle, so that |
68 # We have to find these revisions and put them in a bundle, so that |
66 # we can restore them after the truncations. |
69 # we can restore them after the truncations. |
67 # To create the bundle we use repo.changegroupsubset which requires |
70 # To create the bundle we use repo.changegroupsubset which requires |
68 # the list of heads and bases of the set of interesting revisions. |
71 # the list of heads and bases of the set of interesting revisions. |
69 # (head = revision in the set that has no descendant in the set; |
72 # (head = revision in the set that has no descendant in the set; |
70 # base = revision in the set that has no ancestor in the set) |
73 # base = revision in the set that has no ancestor in the set) |
71 tostrip = set(cl.descendants(striprev)) |
74 tostrip = set(striplist) |
72 tostrip.add(striprev) |
75 for rev in striplist: |
|
76 for desc in cl.descendants(rev): |
|
77 tostrip.add(desc) |
73 |
78 |
74 files = _collectfiles(repo, striprev) |
79 files = _collectfiles(repo, striprev) |
75 saverevs = _collectbrokencsets(repo, files, striprev) |
80 saverevs = _collectbrokencsets(repo, files, striprev) |
76 |
81 |
77 # compute heads |
82 # compute heads |
86 # compute base nodes |
91 # compute base nodes |
87 if saverevs: |
92 if saverevs: |
88 descendants = set(cl.descendants(*saverevs)) |
93 descendants = set(cl.descendants(*saverevs)) |
89 saverevs.difference_update(descendants) |
94 saverevs.difference_update(descendants) |
90 savebases = [cl.node(r) for r in saverevs] |
95 savebases = [cl.node(r) for r in saverevs] |
|
96 stripbases = [cl.node(r) for r in tostrip] |
91 |
97 |
92 bm = repo._bookmarks |
98 bm = repo._bookmarks |
93 updatebm = [] |
99 updatebm = [] |
94 for m in bm: |
100 for m in bm: |
95 rev = repo[bm[m]].rev() |
101 rev = repo[bm[m]].rev() |
97 updatebm.append(m) |
103 updatebm.append(m) |
98 |
104 |
99 # create a changegroup for all the branches we need to keep |
105 # create a changegroup for all the branches we need to keep |
100 backupfile = None |
106 backupfile = None |
101 if backup == "all": |
107 if backup == "all": |
102 backupfile = _bundle(repo, [node], cl.heads(), node, 'backup') |
108 backupfile = _bundle(repo, stripbases, cl.heads(), node, 'backup') |
103 repo.ui.status(_("saved backup bundle to %s\n") % backupfile) |
109 repo.ui.status(_("saved backup bundle to %s\n") % backupfile) |
104 if saveheads or savebases: |
110 if saveheads or savebases: |
105 # do not compress partial bundle if we remove it from disk later |
111 # do not compress partial bundle if we remove it from disk later |
106 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', |
112 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', |
107 compress=keeppartialbundle) |
113 compress=keeppartialbundle) |