##// END OF EJS Templates
strip: bring extension description in line with style and copy-edit
Kevin Bullock -
r19828:0a986233 default
parent child Browse files
Show More
@@ -1,217 +1,217 b''
1 """This extension contains the strip commands.
1 """strip changesets and their descendents from history
2 2
3 This extensions allows to strip changesets and all their descendants from the
3 This extension allows to strip changesets and all their descendants from the
4 4 repository. See the command help for details.
5 5 """
6 6 from mercurial.i18n import _
7 7 from mercurial.node import nullid
8 8 from mercurial.lock import release
9 9 from mercurial import cmdutil, hg, scmutil, util
10 10 from mercurial import repair, bookmarks
11 11
12 12 cmdtable = {}
13 13 command = cmdutil.command(cmdtable)
14 14 testedwith = 'internal'
15 15
16 16 def checksubstate(repo, baserev=None):
17 17 '''return list of subrepos at a different revision than substate.
18 18 Abort if any subrepos have uncommitted changes.'''
19 19 inclsubs = []
20 20 wctx = repo[None]
21 21 if baserev:
22 22 bctx = repo[baserev]
23 23 else:
24 24 bctx = wctx.parents()[0]
25 25 for s in sorted(wctx.substate):
26 26 if wctx.sub(s).dirty(True):
27 27 raise util.Abort(
28 28 _("uncommitted changes in subrepository %s") % s)
29 29 elif s not in bctx.substate or bctx.sub(s).dirty():
30 30 inclsubs.append(s)
31 31 return inclsubs
32 32
33 33 def checklocalchanges(repo, force=False, excsuffix=''):
34 34 cmdutil.checkunfinished(repo)
35 35 m, a, r, d = repo.status()[:4]
36 36 if not force:
37 37 if (m or a or r or d):
38 38 _("local changes found") # i18n tool detection
39 39 raise util.Abort(_("local changes found" + excsuffix))
40 40 if checksubstate(repo):
41 41 _("local changed subrepos found") # i18n tool detection
42 42 raise util.Abort(_("local changed subrepos found" + excsuffix))
43 43 return m, a, r, d
44 44
45 45 def strip(ui, repo, revs, update=True, backup="all", force=None):
46 46 wlock = lock = None
47 47 try:
48 48 wlock = repo.wlock()
49 49 lock = repo.lock()
50 50
51 51 if update:
52 52 checklocalchanges(repo, force=force)
53 53 urev, p2 = repo.changelog.parents(revs[0])
54 54 if p2 != nullid and p2 in [x.node for x in repo.mq.applied]:
55 55 urev = p2
56 56 hg.clean(repo, urev)
57 57 repo.dirstate.write()
58 58
59 59 repair.strip(ui, repo, revs, backup)
60 60 finally:
61 61 release(lock, wlock)
62 62
63 63
64 64 @command("strip",
65 65 [
66 66 ('r', 'rev', [], _('strip specified revision (optional, '
67 67 'can specify revisions without this '
68 68 'option)'), _('REV')),
69 69 ('f', 'force', None, _('force removal of changesets, discard '
70 70 'uncommitted changes (no backup)')),
71 71 ('b', 'backup', None, _('bundle only changesets with local revision'
72 72 ' number greater than REV which are not'
73 73 ' descendants of REV (DEPRECATED)')),
74 74 ('', 'no-backup', None, _('no backups')),
75 75 ('', 'nobackup', None, _('no backups (DEPRECATED)')),
76 76 ('n', '', None, _('ignored (DEPRECATED)')),
77 77 ('k', 'keep', None, _("do not modify working copy during strip")),
78 78 ('B', 'bookmark', '', _("remove revs only reachable from given"
79 79 " bookmark"))],
80 80 _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...'))
81 81 def stripcmd(ui, repo, *revs, **opts):
82 82 """strip changesets and all their descendants from the repository
83 83
84 84 The strip command removes the specified changesets and all their
85 85 descendants. If the working directory has uncommitted changes, the
86 86 operation is aborted unless the --force flag is supplied, in which
87 87 case changes will be discarded.
88 88
89 89 If a parent of the working directory is stripped, then the working
90 90 directory will automatically be updated to the most recent
91 91 available ancestor of the stripped parent after the operation
92 92 completes.
93 93
94 94 Any stripped changesets are stored in ``.hg/strip-backup`` as a
95 95 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
96 96 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
97 97 where BUNDLE is the bundle file created by the strip. Note that
98 98 the local revision numbers will in general be different after the
99 99 restore.
100 100
101 101 Use the --no-backup option to discard the backup bundle once the
102 102 operation completes.
103 103
104 104 Strip is not a history-rewriting operation and can be used on
105 105 changesets in the public phase. But if the stripped changesets have
106 106 been pushed to a remote repository you will likely pull them again.
107 107
108 108 Return 0 on success.
109 109 """
110 110 backup = 'all'
111 111 if opts.get('backup'):
112 112 backup = 'strip'
113 113 elif opts.get('no_backup') or opts.get('nobackup'):
114 114 backup = 'none'
115 115
116 116 cl = repo.changelog
117 117 revs = list(revs) + opts.get('rev')
118 118 revs = set(scmutil.revrange(repo, revs))
119 119
120 120 if opts.get('bookmark'):
121 121 mark = opts.get('bookmark')
122 122 marks = repo._bookmarks
123 123 if mark not in marks:
124 124 raise util.Abort(_("bookmark '%s' not found") % mark)
125 125
126 126 # If the requested bookmark is not the only one pointing to a
127 127 # a revision we have to only delete the bookmark and not strip
128 128 # anything. revsets cannot detect that case.
129 129 uniquebm = True
130 130 for m, n in marks.iteritems():
131 131 if m != mark and n == repo[mark].node():
132 132 uniquebm = False
133 133 break
134 134 if uniquebm:
135 135 rsrevs = repo.revs("ancestors(bookmark(%s)) - "
136 136 "ancestors(head() and not bookmark(%s)) - "
137 137 "ancestors(bookmark() and not bookmark(%s))",
138 138 mark, mark, mark)
139 139 revs.update(set(rsrevs))
140 140 if not revs:
141 141 del marks[mark]
142 142 marks.write()
143 143 ui.write(_("bookmark '%s' deleted\n") % mark)
144 144
145 145 if not revs:
146 146 raise util.Abort(_('empty revision set'))
147 147
148 148 descendants = set(cl.descendants(revs))
149 149 strippedrevs = revs.union(descendants)
150 150 roots = revs.difference(descendants)
151 151
152 152 update = False
153 153 # if one of the wdir parent is stripped we'll need
154 154 # to update away to an earlier revision
155 155 for p in repo.dirstate.parents():
156 156 if p != nullid and cl.rev(p) in strippedrevs:
157 157 update = True
158 158 break
159 159
160 160 rootnodes = set(cl.node(r) for r in roots)
161 161
162 162 q = getattr(repo, 'mq', None)
163 163 if q is not None and q.applied:
164 164 # refresh queue state if we're about to strip
165 165 # applied patches
166 166 if cl.rev(repo.lookup('qtip')) in strippedrevs:
167 167 q.applieddirty = True
168 168 start = 0
169 169 end = len(q.applied)
170 170 for i, statusentry in enumerate(q.applied):
171 171 if statusentry.node in rootnodes:
172 172 # if one of the stripped roots is an applied
173 173 # patch, only part of the queue is stripped
174 174 start = i
175 175 break
176 176 del q.applied[start:end]
177 177 q.savedirty()
178 178
179 179 revs = sorted(rootnodes)
180 180 if update and opts.get('keep'):
181 181 wlock = repo.wlock()
182 182 try:
183 183 urev, p2 = repo.changelog.parents(revs[0])
184 184 if (util.safehasattr(repo, 'mq') and p2 != nullid
185 185 and p2 in [x.node for x in repo.mq.applied]):
186 186 urev = p2
187 187 uctx = repo[urev]
188 188
189 189 # only reset the dirstate for files that would actually change
190 190 # between the working context and uctx
191 191 descendantrevs = repo.revs("%s::." % uctx.rev())
192 192 changedfiles = []
193 193 for rev in descendantrevs:
194 194 # blindly reset the files, regardless of what actually changed
195 195 changedfiles.extend(repo[rev].files())
196 196
197 197 # reset files that only changed in the dirstate too
198 198 dirstate = repo.dirstate
199 199 dirchanges = [f for f in dirstate if dirstate[f] != 'n']
200 200 changedfiles.extend(dirchanges)
201 201
202 202 repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles)
203 203 repo.dirstate.write()
204 204 update = False
205 205 finally:
206 206 wlock.release()
207 207
208 208 if opts.get('bookmark'):
209 209 if mark == repo._bookmarkcurrent:
210 210 bookmarks.setcurrent(repo, None)
211 211 del marks[mark]
212 212 marks.write()
213 213 ui.write(_("bookmark '%s' deleted\n") % mark)
214 214
215 215 strip(ui, repo, revs, backup=backup, update=update, force=opts.get('force'))
216 216
217 217 return 0
General Comments 0
You need to be logged in to leave comments. Login now