28 command = registrar.command(cmdtable) |
28 command = registrar.command(cmdtable) |
29 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
29 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
30 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
30 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
31 # be specifying the version(s) of Mercurial they are tested with, or |
31 # be specifying the version(s) of Mercurial they are tested with, or |
32 # leave the attribute unspecified. |
32 # leave the attribute unspecified. |
33 testedwith = 'ships-with-hg-core' |
33 testedwith = b'ships-with-hg-core' |
34 |
34 |
35 |
35 |
36 def checklocalchanges(repo, force=False): |
36 def checklocalchanges(repo, force=False): |
37 s = repo.status() |
37 s = repo.status() |
38 if not force: |
38 if not force: |
46 def _findupdatetarget(repo, nodes): |
46 def _findupdatetarget(repo, nodes): |
47 unode, p2 = repo.changelog.parents(nodes[0]) |
47 unode, p2 = repo.changelog.parents(nodes[0]) |
48 currentbranch = repo[None].branch() |
48 currentbranch = repo[None].branch() |
49 |
49 |
50 if ( |
50 if ( |
51 util.safehasattr(repo, 'mq') |
51 util.safehasattr(repo, b'mq') |
52 and p2 != nullid |
52 and p2 != nullid |
53 and p2 in [x.node for x in repo.mq.applied] |
53 and p2 in [x.node for x in repo.mq.applied] |
54 ): |
54 ): |
55 unode = p2 |
55 unode = p2 |
56 elif currentbranch != repo[unode].branch(): |
56 elif currentbranch != repo[unode].branch(): |
57 pwdir = 'parents(wdir())' |
57 pwdir = b'parents(wdir())' |
58 revset = 'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))' |
58 revset = b'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))' |
59 branchtarget = repo.revs( |
59 branchtarget = repo.revs( |
60 revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch |
60 revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch |
61 ) |
61 ) |
62 if branchtarget: |
62 if branchtarget: |
63 cl = repo.changelog |
63 cl = repo.changelog |
89 else: |
89 else: |
90 repair.strip(ui, repo, revs, backup) |
90 repair.strip(ui, repo, revs, backup) |
91 |
91 |
92 repomarks = repo._bookmarks |
92 repomarks = repo._bookmarks |
93 if bookmarks: |
93 if bookmarks: |
94 with repo.transaction('strip') as tr: |
94 with repo.transaction(b'strip') as tr: |
95 if repo._activebookmark in bookmarks: |
95 if repo._activebookmark in bookmarks: |
96 bookmarksmod.deactivate(repo) |
96 bookmarksmod.deactivate(repo) |
97 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks]) |
97 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks]) |
98 for bookmark in sorted(bookmarks): |
98 for bookmark in sorted(bookmarks): |
99 ui.write(_("bookmark '%s' deleted\n") % bookmark) |
99 ui.write(_(b"bookmark '%s' deleted\n") % bookmark) |
100 |
100 |
101 |
101 |
102 @command( |
102 @command( |
103 "strip", |
103 b"strip", |
104 [ |
104 [ |
105 ( |
105 ( |
106 'r', |
106 b'r', |
107 'rev', |
107 b'rev', |
108 [], |
108 [], |
109 _( |
109 _( |
110 'strip specified revision (optional, ' |
110 b'strip specified revision (optional, ' |
111 'can specify revisions without this ' |
111 b'can specify revisions without this ' |
112 'option)' |
112 b'option)' |
113 ), |
113 ), |
114 _('REV'), |
114 _(b'REV'), |
115 ), |
115 ), |
116 ( |
116 ( |
117 'f', |
117 b'f', |
118 'force', |
118 b'force', |
119 None, |
119 None, |
120 _( |
120 _( |
121 'force removal of changesets, discard ' |
121 b'force removal of changesets, discard ' |
122 'uncommitted changes (no backup)' |
122 b'uncommitted changes (no backup)' |
123 ), |
123 ), |
124 ), |
124 ), |
125 ('', 'no-backup', None, _('do not save backup bundle')), |
125 (b'', b'no-backup', None, _(b'do not save backup bundle')), |
126 ('', 'nobackup', None, _('do not save backup bundle ' '(DEPRECATED)')), |
126 ( |
127 ('n', '', None, _('ignored (DEPRECATED)')), |
127 b'', |
128 ( |
128 b'nobackup', |
129 'k', |
129 None, |
130 'keep', |
130 _(b'do not save backup bundle ' b'(DEPRECATED)'), |
131 None, |
131 ), |
132 _("do not modify working directory during " "strip"), |
132 (b'n', b'', None, _(b'ignored (DEPRECATED)')), |
133 ), |
133 ( |
134 ( |
134 b'k', |
135 'B', |
135 b'keep', |
136 'bookmark', |
136 None, |
|
137 _(b"do not modify working directory during " b"strip"), |
|
138 ), |
|
139 ( |
|
140 b'B', |
|
141 b'bookmark', |
137 [], |
142 [], |
138 _("remove revs only reachable from given" " bookmark"), |
143 _(b"remove revs only reachable from given" b" bookmark"), |
139 _('BOOKMARK'), |
144 _(b'BOOKMARK'), |
140 ), |
145 ), |
141 ( |
146 ( |
142 '', |
147 b'', |
143 'soft', |
148 b'soft', |
144 None, |
149 None, |
145 _("simply drop changesets from visible history (EXPERIMENTAL)"), |
150 _(b"simply drop changesets from visible history (EXPERIMENTAL)"), |
146 ), |
151 ), |
147 ], |
152 ], |
148 _('hg strip [-k] [-f] [-B bookmark] [-r] REV...'), |
153 _(b'hg strip [-k] [-f] [-B bookmark] [-r] REV...'), |
149 helpcategory=command.CATEGORY_MAINTENANCE, |
154 helpcategory=command.CATEGORY_MAINTENANCE, |
150 ) |
155 ) |
151 def stripcmd(ui, repo, *revs, **opts): |
156 def stripcmd(ui, repo, *revs, **opts): |
152 """strip changesets and all their descendants from the repository |
157 """strip changesets and all their descendants from the repository |
153 |
158 |
177 |
182 |
178 Return 0 on success. |
183 Return 0 on success. |
179 """ |
184 """ |
180 opts = pycompat.byteskwargs(opts) |
185 opts = pycompat.byteskwargs(opts) |
181 backup = True |
186 backup = True |
182 if opts.get('no_backup') or opts.get('nobackup'): |
187 if opts.get(b'no_backup') or opts.get(b'nobackup'): |
183 backup = False |
188 backup = False |
184 |
189 |
185 cl = repo.changelog |
190 cl = repo.changelog |
186 revs = list(revs) + opts.get('rev') |
191 revs = list(revs) + opts.get(b'rev') |
187 revs = set(scmutil.revrange(repo, revs)) |
192 revs = set(scmutil.revrange(repo, revs)) |
188 |
193 |
189 with repo.wlock(): |
194 with repo.wlock(): |
190 bookmarks = set(opts.get('bookmark')) |
195 bookmarks = set(opts.get(b'bookmark')) |
191 if bookmarks: |
196 if bookmarks: |
192 repomarks = repo._bookmarks |
197 repomarks = repo._bookmarks |
193 if not bookmarks.issubset(repomarks): |
198 if not bookmarks.issubset(repomarks): |
194 raise error.Abort( |
199 raise error.Abort( |
195 _("bookmark '%s' not found") |
200 _(b"bookmark '%s' not found") |
196 % ','.join(sorted(bookmarks - set(repomarks.keys()))) |
201 % b','.join(sorted(bookmarks - set(repomarks.keys()))) |
197 ) |
202 ) |
198 |
203 |
199 # If the requested bookmark is not the only one pointing to a |
204 # If the requested bookmark is not the only one pointing to a |
200 # a revision we have to only delete the bookmark and not strip |
205 # a revision we have to only delete the bookmark and not strip |
201 # anything. revsets cannot detect that case. |
206 # anything. revsets cannot detect that case. |
205 for marks in nodetobookmarks.values(): |
210 for marks in nodetobookmarks.values(): |
206 if bookmarks.issuperset(marks): |
211 if bookmarks.issuperset(marks): |
207 rsrevs = scmutil.bookmarkrevs(repo, marks[0]) |
212 rsrevs = scmutil.bookmarkrevs(repo, marks[0]) |
208 revs.update(set(rsrevs)) |
213 revs.update(set(rsrevs)) |
209 if not revs: |
214 if not revs: |
210 with repo.lock(), repo.transaction('bookmark') as tr: |
215 with repo.lock(), repo.transaction(b'bookmark') as tr: |
211 bmchanges = [(b, None) for b in bookmarks] |
216 bmchanges = [(b, None) for b in bookmarks] |
212 repomarks.applychanges(repo, tr, bmchanges) |
217 repomarks.applychanges(repo, tr, bmchanges) |
213 for bookmark in sorted(bookmarks): |
218 for bookmark in sorted(bookmarks): |
214 ui.write(_("bookmark '%s' deleted\n") % bookmark) |
219 ui.write(_(b"bookmark '%s' deleted\n") % bookmark) |
215 |
220 |
216 if not revs: |
221 if not revs: |
217 raise error.Abort(_('empty revision set')) |
222 raise error.Abort(_(b'empty revision set')) |
218 |
223 |
219 descendants = set(cl.descendants(revs)) |
224 descendants = set(cl.descendants(revs)) |
220 strippedrevs = revs.union(descendants) |
225 strippedrevs = revs.union(descendants) |
221 roots = revs.difference(descendants) |
226 roots = revs.difference(descendants) |
222 |
227 |
231 |
236 |
232 q = getattr(repo, 'mq', None) |
237 q = getattr(repo, 'mq', None) |
233 if q is not None and q.applied: |
238 if q is not None and q.applied: |
234 # refresh queue state if we're about to strip |
239 # refresh queue state if we're about to strip |
235 # applied patches |
240 # applied patches |
236 if cl.rev(repo.lookup('qtip')) in strippedrevs: |
241 if cl.rev(repo.lookup(b'qtip')) in strippedrevs: |
237 q.applieddirty = True |
242 q.applieddirty = True |
238 start = 0 |
243 start = 0 |
239 end = len(q.applied) |
244 end = len(q.applied) |
240 for i, statusentry in enumerate(q.applied): |
245 for i, statusentry in enumerate(q.applied): |
241 if statusentry.node in rootnodes: |
246 if statusentry.node in rootnodes: |
259 # blindly reset the files, regardless of what actually changed |
264 # blindly reset the files, regardless of what actually changed |
260 changedfiles.extend(repo[rev].files()) |
265 changedfiles.extend(repo[rev].files()) |
261 |
266 |
262 # reset files that only changed in the dirstate too |
267 # reset files that only changed in the dirstate too |
263 dirstate = repo.dirstate |
268 dirstate = repo.dirstate |
264 dirchanges = [f for f in dirstate if dirstate[f] != 'n'] |
269 dirchanges = [f for f in dirstate if dirstate[f] != b'n'] |
265 changedfiles.extend(dirchanges) |
270 changedfiles.extend(dirchanges) |
266 |
271 |
267 repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) |
272 repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) |
268 repo.dirstate.write(repo.currenttransaction()) |
273 repo.dirstate.write(repo.currenttransaction()) |
269 |
274 |
270 # clear resolve state |
275 # clear resolve state |
271 merge.mergestate.clean(repo, repo['.'].node()) |
276 merge.mergestate.clean(repo, repo[b'.'].node()) |
272 |
277 |
273 update = False |
278 update = False |
274 |
279 |
275 strip( |
280 strip( |
276 ui, |
281 ui, |
277 repo, |
282 repo, |
278 revs, |
283 revs, |
279 backup=backup, |
284 backup=backup, |
280 update=update, |
285 update=update, |
281 force=opts.get('force'), |
286 force=opts.get(b'force'), |
282 bookmarks=bookmarks, |
287 bookmarks=bookmarks, |
283 soft=opts['soft'], |
288 soft=opts[b'soft'], |
284 ) |
289 ) |
285 |
290 |
286 return 0 |
291 return 0 |