##// END OF EJS Templates
strip: move into core...
Valentin Gatien-Baron -
r46469:a46efd42 default draft
parent child Browse files
Show More
@@ -100,6 +100,7 b' from mercurial import ('
100 revsetlang,
100 revsetlang,
101 scmutil,
101 scmutil,
102 smartset,
102 smartset,
103 strip,
103 subrepoutil,
104 subrepoutil,
104 util,
105 util,
105 vfs as vfsmod,
106 vfs as vfsmod,
@@ -138,7 +139,7 b' configitem('
138
139
139 # force load strip extension formerly included in mq and import some utility
140 # force load strip extension formerly included in mq and import some utility
140 try:
141 try:
141 stripext = extensions.find(b'strip')
142 extensions.find(b'strip')
142 except KeyError:
143 except KeyError:
143 # note: load is lazy so we could avoid the try-except,
144 # note: load is lazy so we could avoid the try-except,
144 # but I (marmoute) prefer this explicit code.
145 # but I (marmoute) prefer this explicit code.
@@ -149,9 +150,9 b' except KeyError:'
149 def log(self, event, msgfmt, *msgargs, **opts):
150 def log(self, event, msgfmt, *msgargs, **opts):
150 pass
151 pass
151
152
152 stripext = extensions.load(dummyui(), b'strip', b'')
153 extensions.load(dummyui(), b'strip', b'')
153
154
154 strip = stripext.strip
155 strip = strip.strip
155
156
156
157
157 def checksubstate(repo, baserev=None):
158 def checksubstate(repo, baserev=None):
@@ -1,287 +1,24 b''
1 """strip changesets and their descendants from history
1 """strip changesets and their descendants from history (DEPRECATED)
2
3 The functionality of this extension has been included in core Mercurial
4 since version 5.7. Please use :hg:`debugstrip ...` instead.
2
5
3 This extension allows you to strip changesets and all their descendants from the
6 This extension allows you to strip changesets and all their descendants from the
4 repository. See the command help for details.
7 repository. See the command help for details.
5 """
8 """
6 from __future__ import absolute_import
9 from __future__ import absolute_import
7
10
8 from mercurial.i18n import _
9 from mercurial.pycompat import getattr
10 from mercurial import (
11 from mercurial import (
11 bookmarks as bookmarksmod,
12 commands,
12 cmdutil,
13 error,
14 hg,
15 lock as lockmod,
16 mergestate as mergestatemod,
17 node as nodemod,
18 pycompat,
19 registrar,
20 repair,
21 scmutil,
22 util,
23 )
13 )
24
14
25 nullid = nodemod.nullid
26 release = lockmod.release
27
28 cmdtable = {}
29 command = registrar.command(cmdtable)
30 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
15 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
31 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
16 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
32 # be specifying the version(s) of Mercurial they are tested with, or
17 # be specifying the version(s) of Mercurial they are tested with, or
33 # leave the attribute unspecified.
18 # leave the attribute unspecified.
34 testedwith = b'ships-with-hg-core'
19 testedwith = b'ships-with-hg-core'
35
20
36
21 # This is a bit ugly, but a uisetup function that defines strip as an
37 def checklocalchanges(repo, force=False):
22 # alias for debugstrip would override any user alias for strip,
38 s = repo.status()
23 # including aliases like "strip = strip --no-backup".
39 if not force:
24 commands.command.rename(old=b'debugstrip', new=b'debugstrip|strip')
40 cmdutil.checkunfinished(repo)
41 cmdutil.bailifchanged(repo)
42 else:
43 cmdutil.checkunfinished(repo, skipmerge=True)
44 return s
45
46
47 def _findupdatetarget(repo, nodes):
48 unode, p2 = repo.changelog.parents(nodes[0])
49 currentbranch = repo[None].branch()
50
51 if (
52 util.safehasattr(repo, b'mq')
53 and p2 != nullid
54 and p2 in [x.node for x in repo.mq.applied]
55 ):
56 unode = p2
57 elif currentbranch != repo[unode].branch():
58 pwdir = b'parents(wdir())'
59 revset = b'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))'
60 branchtarget = repo.revs(
61 revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch
62 )
63 if branchtarget:
64 cl = repo.changelog
65 unode = cl.node(branchtarget.first())
66
67 return unode
68
69
70 def strip(
71 ui,
72 repo,
73 revs,
74 update=True,
75 backup=True,
76 force=None,
77 bookmarks=None,
78 soft=False,
79 ):
80 with repo.wlock(), repo.lock():
81
82 if update:
83 checklocalchanges(repo, force=force)
84 urev = _findupdatetarget(repo, revs)
85 hg.clean(repo, urev)
86 repo.dirstate.write(repo.currenttransaction())
87
88 if soft:
89 repair.softstrip(ui, repo, revs, backup)
90 else:
91 repair.strip(ui, repo, revs, backup)
92
93 repomarks = repo._bookmarks
94 if bookmarks:
95 with repo.transaction(b'strip') as tr:
96 if repo._activebookmark in bookmarks:
97 bookmarksmod.deactivate(repo)
98 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks])
99 for bookmark in sorted(bookmarks):
100 ui.write(_(b"bookmark '%s' deleted\n") % bookmark)
101
102
103 @command(
104 b"strip",
105 [
106 (
107 b'r',
108 b'rev',
109 [],
110 _(
111 b'strip specified revision (optional, '
112 b'can specify revisions without this '
113 b'option)'
114 ),
115 _(b'REV'),
116 ),
117 (
118 b'f',
119 b'force',
120 None,
121 _(
122 b'force removal of changesets, discard '
123 b'uncommitted changes (no backup)'
124 ),
125 ),
126 (b'', b'no-backup', None, _(b'do not save backup bundle')),
127 (b'', b'nobackup', None, _(b'do not save backup bundle (DEPRECATED)'),),
128 (b'n', b'', None, _(b'ignored (DEPRECATED)')),
129 (
130 b'k',
131 b'keep',
132 None,
133 _(b"do not modify working directory during strip"),
134 ),
135 (
136 b'B',
137 b'bookmark',
138 [],
139 _(b"remove revs only reachable from given bookmark"),
140 _(b'BOOKMARK'),
141 ),
142 (
143 b'',
144 b'soft',
145 None,
146 _(b"simply drop changesets from visible history (EXPERIMENTAL)"),
147 ),
148 ],
149 _(b'hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
150 helpcategory=command.CATEGORY_MAINTENANCE,
151 )
152 def stripcmd(ui, repo, *revs, **opts):
153 """strip changesets and all their descendants from the repository
154
155 The strip command removes the specified changesets and all their
156 descendants. If the working directory has uncommitted changes, the
157 operation is aborted unless the --force flag is supplied, in which
158 case changes will be discarded.
159
160 If a parent of the working directory is stripped, then the working
161 directory will automatically be updated to the most recent
162 available ancestor of the stripped parent after the operation
163 completes.
164
165 Any stripped changesets are stored in ``.hg/strip-backup`` as a
166 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
167 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
168 where BUNDLE is the bundle file created by the strip. Note that
169 the local revision numbers will in general be different after the
170 restore.
171
172 Use the --no-backup option to discard the backup bundle once the
173 operation completes.
174
175 Strip is not a history-rewriting operation and can be used on
176 changesets in the public phase. But if the stripped changesets have
177 been pushed to a remote repository you will likely pull them again.
178
179 Return 0 on success.
180 """
181 opts = pycompat.byteskwargs(opts)
182 backup = True
183 if opts.get(b'no_backup') or opts.get(b'nobackup'):
184 backup = False
185
186 cl = repo.changelog
187 revs = list(revs) + opts.get(b'rev')
188 revs = set(scmutil.revrange(repo, revs))
189
190 with repo.wlock():
191 bookmarks = set(opts.get(b'bookmark'))
192 if bookmarks:
193 repomarks = repo._bookmarks
194 if not bookmarks.issubset(repomarks):
195 raise error.Abort(
196 _(b"bookmark '%s' not found")
197 % b','.join(sorted(bookmarks - set(repomarks.keys())))
198 )
199
200 # If the requested bookmark is not the only one pointing to a
201 # a revision we have to only delete the bookmark and not strip
202 # anything. revsets cannot detect that case.
203 nodetobookmarks = {}
204 for mark, node in pycompat.iteritems(repomarks):
205 nodetobookmarks.setdefault(node, []).append(mark)
206 for marks in nodetobookmarks.values():
207 if bookmarks.issuperset(marks):
208 rsrevs = scmutil.bookmarkrevs(repo, marks[0])
209 revs.update(set(rsrevs))
210 if not revs:
211 with repo.lock(), repo.transaction(b'bookmark') as tr:
212 bmchanges = [(b, None) for b in bookmarks]
213 repomarks.applychanges(repo, tr, bmchanges)
214 for bookmark in sorted(bookmarks):
215 ui.write(_(b"bookmark '%s' deleted\n") % bookmark)
216
217 if not revs:
218 raise error.Abort(_(b'empty revision set'))
219
220 descendants = set(cl.descendants(revs))
221 strippedrevs = revs.union(descendants)
222 roots = revs.difference(descendants)
223
224 # if one of the wdir parent is stripped we'll need
225 # to update away to an earlier revision
226 update = any(
227 p != nullid and cl.rev(p) in strippedrevs
228 for p in repo.dirstate.parents()
229 )
230
231 rootnodes = {cl.node(r) for r in roots}
232
233 q = getattr(repo, 'mq', None)
234 if q is not None and q.applied:
235 # refresh queue state if we're about to strip
236 # applied patches
237 if cl.rev(repo.lookup(b'qtip')) in strippedrevs:
238 q.applieddirty = True
239 start = 0
240 end = len(q.applied)
241 for i, statusentry in enumerate(q.applied):
242 if statusentry.node in rootnodes:
243 # if one of the stripped roots is an applied
244 # patch, only part of the queue is stripped
245 start = i
246 break
247 del q.applied[start:end]
248 q.savedirty()
249
250 revs = sorted(rootnodes)
251 if update and opts.get(b'keep'):
252 urev = _findupdatetarget(repo, revs)
253 uctx = repo[urev]
254
255 # only reset the dirstate for files that would actually change
256 # between the working context and uctx
257 descendantrevs = repo.revs(b"only(., %d)", uctx.rev())
258 changedfiles = []
259 for rev in descendantrevs:
260 # blindly reset the files, regardless of what actually changed
261 changedfiles.extend(repo[rev].files())
262
263 # reset files that only changed in the dirstate too
264 dirstate = repo.dirstate
265 dirchanges = [f for f in dirstate if dirstate[f] != b'n']
266 changedfiles.extend(dirchanges)
267
268 repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles)
269 repo.dirstate.write(repo.currenttransaction())
270
271 # clear resolve state
272 mergestatemod.mergestate.clean(repo)
273
274 update = False
275
276 strip(
277 ui,
278 repo,
279 revs,
280 backup=backup,
281 update=update,
282 force=opts.get(b'force'),
283 bookmarks=bookmarks,
284 soft=opts[b'soft'],
285 )
286
287 return 0
@@ -78,6 +78,7 b' from . import ('
78 sshpeer,
78 sshpeer,
79 sslutil,
79 sslutil,
80 streamclone,
80 streamclone,
81 strip,
81 tags as tagsmod,
82 tags as tagsmod,
82 templater,
83 templater,
83 treediscovery,
84 treediscovery,
@@ -105,8 +106,9 b' from .revlogutils import ('
105
106
106 release = lockmod.release
107 release = lockmod.release
107
108
108 command = registrar.command()
109 table = {}
109
110 table.update(strip.command._table)
111 command = registrar.command(table)
110
112
111 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
113 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
112 def debugancestor(ui, repo, *args):
114 def debugancestor(ui, repo, *args):
@@ -234,6 +234,11 b' class command(_funcregistrarbase):'
234 self._table[name] = func, list(options)
234 self._table[name] = func, list(options)
235 return func
235 return func
236
236
237 def rename(self, old, new):
238 """rename a command. Used to add aliases, debugstrip ->
239 debugstrip|strip
240 """
241 self._table[new] = self._table.pop(old)
237
242
238 INTENT_READONLY = b'readonly'
243 INTENT_READONLY = b'readonly'
239
244
@@ -1,13 +1,8 b''
1 """strip changesets and their descendants from history
2
3 This extension allows you to strip changesets and all their descendants from the
4 repository. See the command help for details.
5 """
6 from __future__ import absolute_import
1 from __future__ import absolute_import
7
2
8 from mercurial.i18n import _
3 from .i18n import _
9 from mercurial.pycompat import getattr
4 from .pycompat import getattr
10 from mercurial import (
5 from . import (
11 bookmarks as bookmarksmod,
6 bookmarks as bookmarksmod,
12 cmdutil,
7 cmdutil,
13 error,
8 error,
@@ -27,11 +22,6 b' release = lockmod.release'
27
22
28 cmdtable = {}
23 cmdtable = {}
29 command = registrar.command(cmdtable)
24 command = registrar.command(cmdtable)
30 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
31 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
32 # be specifying the version(s) of Mercurial they are tested with, or
33 # leave the attribute unspecified.
34 testedwith = b'ships-with-hg-core'
35
25
36
26
37 def checklocalchanges(repo, force=False):
27 def checklocalchanges(repo, force=False):
@@ -101,7 +91,7 b' def strip('
101
91
102
92
103 @command(
93 @command(
104 b"strip",
94 b"debugstrip",
105 [
95 [
106 (
96 (
107 b'r',
97 b'r',
@@ -146,10 +136,10 b' def strip('
146 _(b"simply drop changesets from visible history (EXPERIMENTAL)"),
136 _(b"simply drop changesets from visible history (EXPERIMENTAL)"),
147 ),
137 ),
148 ],
138 ],
149 _(b'hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
139 _(b'hg debugstrip [-k] [-f] [-B bookmark] [-r] REV...'),
150 helpcategory=command.CATEGORY_MAINTENANCE,
140 helpcategory=command.CATEGORY_MAINTENANCE,
151 )
141 )
152 def stripcmd(ui, repo, *revs, **opts):
142 def debugstrip(ui, repo, *revs, **opts):
153 """strip changesets and all their descendants from the repository
143 """strip changesets and all their descendants from the repository
154
144
155 The strip command removes the specified changesets and all their
145 The strip command removes the specified changesets and all their
@@ -2,6 +2,9 b''
2
2
3
3
4
4
5 * `hg strip`, from the strip extension, is now a core command, `hg
6 debugstrip`. The extension remains for compatibility.
7
5 == New Experimental Features ==
8 == New Experimental Features ==
6
9
7
10
@@ -131,6 +131,7 b' Show debug commands if there are no othe'
131 debugsetparents
131 debugsetparents
132 debugsidedata
132 debugsidedata
133 debugssl
133 debugssl
134 debugstrip
134 debugsub
135 debugsub
135 debugsuccessorssets
136 debugsuccessorssets
136 debugtagscache
137 debugtagscache
@@ -319,6 +320,7 b' Show all commands + options'
319 debugsetparents:
320 debugsetparents:
320 debugsidedata: changelog, manifest, dir
321 debugsidedata: changelog, manifest, dir
321 debugssl:
322 debugssl:
323 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
322 debugsub: rev
324 debugsub: rev
323 debugsuccessorssets: closest
325 debugsuccessorssets: closest
324 debugtagscache:
326 debugtagscache:
@@ -380,7 +380,6 b' Test extension help:'
380 relink recreates hardlinks between repository clones
380 relink recreates hardlinks between repository clones
381 schemes extend schemes with shortcuts to repository swarms
381 schemes extend schemes with shortcuts to repository swarms
382 share share a common history between several working directories
382 share share a common history between several working directories
383 strip strip changesets and their descendants from history
384 transplant command to transplant changesets from another branch
383 transplant command to transplant changesets from another branch
385 win32mbcs allow the use of MBCS paths with problematic encodings
384 win32mbcs allow the use of MBCS paths with problematic encodings
386 zeroconf discover and advertise repositories on the local network
385 zeroconf discover and advertise repositories on the local network
@@ -1067,6 +1066,7 b' Test list of internal help commands'
1067 debugsidedata
1066 debugsidedata
1068 dump the side data for a cl/manifest/file revision
1067 dump the side data for a cl/manifest/file revision
1069 debugssl test a secure connection to a server
1068 debugssl test a secure connection to a server
1069 debugstrip strip changesets and all their descendants from the repository
1070 debugsub (no help text available)
1070 debugsub (no help text available)
1071 debugsuccessorssets
1071 debugsuccessorssets
1072 show set of successors for revision
1072 show set of successors for revision
@@ -10,7 +10,7 b''
10 > hg up -C $1
10 > hg up -C $1
11 > echo % before update $1, strip $2
11 > echo % before update $1, strip $2
12 > hg log -G -T '{rev}:{node}'
12 > hg log -G -T '{rev}:{node}'
13 > hg --traceback strip $2
13 > hg --traceback debugstrip $2
14 > echo % after update $1, strip $2
14 > echo % after update $1, strip $2
15 > hg log -G -T '{rev}:{node}'
15 > hg log -G -T '{rev}:{node}'
16 > restore
16 > restore
@@ -765,13 +765,11 b' test hg strip -B bookmark'
765 Make sure no one adds back a -b option:
765 Make sure no one adds back a -b option:
766
766
767 $ hg strip -b tip
767 $ hg strip -b tip
768 hg strip: option -b not recognized
768 hg debugstrip: option -b not recognized
769 hg strip [-k] [-f] [-B bookmark] [-r] REV...
769 hg debugstrip [-k] [-f] [-B bookmark] [-r] REV...
770
770
771 strip changesets and all their descendants from the repository
771 strip changesets and all their descendants from the repository
772
772
773 (use 'hg help -e strip' to show help for the strip extension)
774
775 options ([+] can be repeated):
773 options ([+] can be repeated):
776
774
777 -r --rev REV [+] strip specified revision (optional, can specify
775 -r --rev REV [+] strip specified revision (optional, can specify
@@ -783,7 +781,7 b' Make sure no one adds back a -b option:'
783 -B --bookmark BOOKMARK [+] remove revs only reachable from given bookmark
781 -B --bookmark BOOKMARK [+] remove revs only reachable from given bookmark
784 --mq operate on patch repository
782 --mq operate on patch repository
785
783
786 (use 'hg strip -h' to show more help)
784 (use 'hg debugstrip -h' to show more help)
787 [255]
785 [255]
788
786
789 $ cd ..
787 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now