##// END OF EJS Templates
mq: backup local changes in qpop --force (issue3433)
Patrick Mezard -
r16633:b2ca2f40 stable
parent child Browse files
Show More
@@ -1,3419 +1,3434 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''manage a stack of patches
8 '''manage a stack of patches
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use :hg:`help command` for more details)::
17 Common tasks (use :hg:`help command` for more details)::
18
18
19 create new patch qnew
19 create new patch qnew
20 import existing patch qimport
20 import existing patch qimport
21
21
22 print patch series qseries
22 print patch series qseries
23 print applied patches qapplied
23 print applied patches qapplied
24
24
25 add known patch to applied stack qpush
25 add known patch to applied stack qpush
26 remove patch from applied stack qpop
26 remove patch from applied stack qpop
27 refresh contents of top applied patch qrefresh
27 refresh contents of top applied patch qrefresh
28
28
29 By default, mq will automatically use git patches when required to
29 By default, mq will automatically use git patches when required to
30 avoid losing file mode changes, copy records, binary files or empty
30 avoid losing file mode changes, copy records, binary files or empty
31 files creations or deletions. This behaviour can be configured with::
31 files creations or deletions. This behaviour can be configured with::
32
32
33 [mq]
33 [mq]
34 git = auto/keep/yes/no
34 git = auto/keep/yes/no
35
35
36 If set to 'keep', mq will obey the [diff] section configuration while
36 If set to 'keep', mq will obey the [diff] section configuration while
37 preserving existing git patches upon qrefresh. If set to 'yes' or
37 preserving existing git patches upon qrefresh. If set to 'yes' or
38 'no', mq will override the [diff] section and always generate git or
38 'no', mq will override the [diff] section and always generate git or
39 regular patches, possibly losing data in the second case.
39 regular patches, possibly losing data in the second case.
40
40
41 It may be desirable for mq changesets to be kept in the secret phase (see
41 It may be desirable for mq changesets to be kept in the secret phase (see
42 :hg:`help phases`), which can be enabled with the following setting::
42 :hg:`help phases`), which can be enabled with the following setting::
43
43
44 [mq]
44 [mq]
45 secret = True
45 secret = True
46
46
47 You will by default be managing a patch queue named "patches". You can
47 You will by default be managing a patch queue named "patches". You can
48 create other, independent patch queues with the :hg:`qqueue` command.
48 create other, independent patch queues with the :hg:`qqueue` command.
49 '''
49 '''
50
50
51 from mercurial.i18n import _
51 from mercurial.i18n import _
52 from mercurial.node import bin, hex, short, nullid, nullrev
52 from mercurial.node import bin, hex, short, nullid, nullrev
53 from mercurial.lock import release
53 from mercurial.lock import release
54 from mercurial import commands, cmdutil, hg, scmutil, util, revset
54 from mercurial import commands, cmdutil, hg, scmutil, util, revset
55 from mercurial import repair, extensions, url, error, phases
55 from mercurial import repair, extensions, url, error, phases
56 from mercurial import patch as patchmod
56 from mercurial import patch as patchmod
57 import os, re, errno, shutil
57 import os, re, errno, shutil
58
58
59 commands.norepo += " qclone"
59 commands.norepo += " qclone"
60
60
61 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
61 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
62
62
63 cmdtable = {}
63 cmdtable = {}
64 command = cmdutil.command(cmdtable)
64 command = cmdutil.command(cmdtable)
65
65
66 # Patch names looks like unix-file names.
66 # Patch names looks like unix-file names.
67 # They must be joinable with queue directory and result in the patch path.
67 # They must be joinable with queue directory and result in the patch path.
68 normname = util.normpath
68 normname = util.normpath
69
69
70 class statusentry(object):
70 class statusentry(object):
71 def __init__(self, node, name):
71 def __init__(self, node, name):
72 self.node, self.name = node, name
72 self.node, self.name = node, name
73 def __repr__(self):
73 def __repr__(self):
74 return hex(self.node) + ':' + self.name
74 return hex(self.node) + ':' + self.name
75
75
76 class patchheader(object):
76 class patchheader(object):
77 def __init__(self, pf, plainmode=False):
77 def __init__(self, pf, plainmode=False):
78 def eatdiff(lines):
78 def eatdiff(lines):
79 while lines:
79 while lines:
80 l = lines[-1]
80 l = lines[-1]
81 if (l.startswith("diff -") or
81 if (l.startswith("diff -") or
82 l.startswith("Index:") or
82 l.startswith("Index:") or
83 l.startswith("===========")):
83 l.startswith("===========")):
84 del lines[-1]
84 del lines[-1]
85 else:
85 else:
86 break
86 break
87 def eatempty(lines):
87 def eatempty(lines):
88 while lines:
88 while lines:
89 if not lines[-1].strip():
89 if not lines[-1].strip():
90 del lines[-1]
90 del lines[-1]
91 else:
91 else:
92 break
92 break
93
93
94 message = []
94 message = []
95 comments = []
95 comments = []
96 user = None
96 user = None
97 date = None
97 date = None
98 parent = None
98 parent = None
99 format = None
99 format = None
100 subject = None
100 subject = None
101 branch = None
101 branch = None
102 nodeid = None
102 nodeid = None
103 diffstart = 0
103 diffstart = 0
104
104
105 for line in file(pf):
105 for line in file(pf):
106 line = line.rstrip()
106 line = line.rstrip()
107 if (line.startswith('diff --git')
107 if (line.startswith('diff --git')
108 or (diffstart and line.startswith('+++ '))):
108 or (diffstart and line.startswith('+++ '))):
109 diffstart = 2
109 diffstart = 2
110 break
110 break
111 diffstart = 0 # reset
111 diffstart = 0 # reset
112 if line.startswith("--- "):
112 if line.startswith("--- "):
113 diffstart = 1
113 diffstart = 1
114 continue
114 continue
115 elif format == "hgpatch":
115 elif format == "hgpatch":
116 # parse values when importing the result of an hg export
116 # parse values when importing the result of an hg export
117 if line.startswith("# User "):
117 if line.startswith("# User "):
118 user = line[7:]
118 user = line[7:]
119 elif line.startswith("# Date "):
119 elif line.startswith("# Date "):
120 date = line[7:]
120 date = line[7:]
121 elif line.startswith("# Parent "):
121 elif line.startswith("# Parent "):
122 parent = line[9:].lstrip()
122 parent = line[9:].lstrip()
123 elif line.startswith("# Branch "):
123 elif line.startswith("# Branch "):
124 branch = line[9:]
124 branch = line[9:]
125 elif line.startswith("# Node ID "):
125 elif line.startswith("# Node ID "):
126 nodeid = line[10:]
126 nodeid = line[10:]
127 elif not line.startswith("# ") and line:
127 elif not line.startswith("# ") and line:
128 message.append(line)
128 message.append(line)
129 format = None
129 format = None
130 elif line == '# HG changeset patch':
130 elif line == '# HG changeset patch':
131 message = []
131 message = []
132 format = "hgpatch"
132 format = "hgpatch"
133 elif (format != "tagdone" and (line.startswith("Subject: ") or
133 elif (format != "tagdone" and (line.startswith("Subject: ") or
134 line.startswith("subject: "))):
134 line.startswith("subject: "))):
135 subject = line[9:]
135 subject = line[9:]
136 format = "tag"
136 format = "tag"
137 elif (format != "tagdone" and (line.startswith("From: ") or
137 elif (format != "tagdone" and (line.startswith("From: ") or
138 line.startswith("from: "))):
138 line.startswith("from: "))):
139 user = line[6:]
139 user = line[6:]
140 format = "tag"
140 format = "tag"
141 elif (format != "tagdone" and (line.startswith("Date: ") or
141 elif (format != "tagdone" and (line.startswith("Date: ") or
142 line.startswith("date: "))):
142 line.startswith("date: "))):
143 date = line[6:]
143 date = line[6:]
144 format = "tag"
144 format = "tag"
145 elif format == "tag" and line == "":
145 elif format == "tag" and line == "":
146 # when looking for tags (subject: from: etc) they
146 # when looking for tags (subject: from: etc) they
147 # end once you find a blank line in the source
147 # end once you find a blank line in the source
148 format = "tagdone"
148 format = "tagdone"
149 elif message or line:
149 elif message or line:
150 message.append(line)
150 message.append(line)
151 comments.append(line)
151 comments.append(line)
152
152
153 eatdiff(message)
153 eatdiff(message)
154 eatdiff(comments)
154 eatdiff(comments)
155 # Remember the exact starting line of the patch diffs before consuming
155 # Remember the exact starting line of the patch diffs before consuming
156 # empty lines, for external use by TortoiseHg and others
156 # empty lines, for external use by TortoiseHg and others
157 self.diffstartline = len(comments)
157 self.diffstartline = len(comments)
158 eatempty(message)
158 eatempty(message)
159 eatempty(comments)
159 eatempty(comments)
160
160
161 # make sure message isn't empty
161 # make sure message isn't empty
162 if format and format.startswith("tag") and subject:
162 if format and format.startswith("tag") and subject:
163 message.insert(0, "")
163 message.insert(0, "")
164 message.insert(0, subject)
164 message.insert(0, subject)
165
165
166 self.message = message
166 self.message = message
167 self.comments = comments
167 self.comments = comments
168 self.user = user
168 self.user = user
169 self.date = date
169 self.date = date
170 self.parent = parent
170 self.parent = parent
171 # nodeid and branch are for external use by TortoiseHg and others
171 # nodeid and branch are for external use by TortoiseHg and others
172 self.nodeid = nodeid
172 self.nodeid = nodeid
173 self.branch = branch
173 self.branch = branch
174 self.haspatch = diffstart > 1
174 self.haspatch = diffstart > 1
175 self.plainmode = plainmode
175 self.plainmode = plainmode
176
176
177 def setuser(self, user):
177 def setuser(self, user):
178 if not self.updateheader(['From: ', '# User '], user):
178 if not self.updateheader(['From: ', '# User '], user):
179 try:
179 try:
180 patchheaderat = self.comments.index('# HG changeset patch')
180 patchheaderat = self.comments.index('# HG changeset patch')
181 self.comments.insert(patchheaderat + 1, '# User ' + user)
181 self.comments.insert(patchheaderat + 1, '# User ' + user)
182 except ValueError:
182 except ValueError:
183 if self.plainmode or self._hasheader(['Date: ']):
183 if self.plainmode or self._hasheader(['Date: ']):
184 self.comments = ['From: ' + user] + self.comments
184 self.comments = ['From: ' + user] + self.comments
185 else:
185 else:
186 tmp = ['# HG changeset patch', '# User ' + user, '']
186 tmp = ['# HG changeset patch', '# User ' + user, '']
187 self.comments = tmp + self.comments
187 self.comments = tmp + self.comments
188 self.user = user
188 self.user = user
189
189
190 def setdate(self, date):
190 def setdate(self, date):
191 if not self.updateheader(['Date: ', '# Date '], date):
191 if not self.updateheader(['Date: ', '# Date '], date):
192 try:
192 try:
193 patchheaderat = self.comments.index('# HG changeset patch')
193 patchheaderat = self.comments.index('# HG changeset patch')
194 self.comments.insert(patchheaderat + 1, '# Date ' + date)
194 self.comments.insert(patchheaderat + 1, '# Date ' + date)
195 except ValueError:
195 except ValueError:
196 if self.plainmode or self._hasheader(['From: ']):
196 if self.plainmode or self._hasheader(['From: ']):
197 self.comments = ['Date: ' + date] + self.comments
197 self.comments = ['Date: ' + date] + self.comments
198 else:
198 else:
199 tmp = ['# HG changeset patch', '# Date ' + date, '']
199 tmp = ['# HG changeset patch', '# Date ' + date, '']
200 self.comments = tmp + self.comments
200 self.comments = tmp + self.comments
201 self.date = date
201 self.date = date
202
202
203 def setparent(self, parent):
203 def setparent(self, parent):
204 if not self.updateheader(['# Parent '], parent):
204 if not self.updateheader(['# Parent '], parent):
205 try:
205 try:
206 patchheaderat = self.comments.index('# HG changeset patch')
206 patchheaderat = self.comments.index('# HG changeset patch')
207 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
207 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
208 except ValueError:
208 except ValueError:
209 pass
209 pass
210 self.parent = parent
210 self.parent = parent
211
211
212 def setmessage(self, message):
212 def setmessage(self, message):
213 if self.comments:
213 if self.comments:
214 self._delmsg()
214 self._delmsg()
215 self.message = [message]
215 self.message = [message]
216 self.comments += self.message
216 self.comments += self.message
217
217
218 def updateheader(self, prefixes, new):
218 def updateheader(self, prefixes, new):
219 '''Update all references to a field in the patch header.
219 '''Update all references to a field in the patch header.
220 Return whether the field is present.'''
220 Return whether the field is present.'''
221 res = False
221 res = False
222 for prefix in prefixes:
222 for prefix in prefixes:
223 for i in xrange(len(self.comments)):
223 for i in xrange(len(self.comments)):
224 if self.comments[i].startswith(prefix):
224 if self.comments[i].startswith(prefix):
225 self.comments[i] = prefix + new
225 self.comments[i] = prefix + new
226 res = True
226 res = True
227 break
227 break
228 return res
228 return res
229
229
230 def _hasheader(self, prefixes):
230 def _hasheader(self, prefixes):
231 '''Check if a header starts with any of the given prefixes.'''
231 '''Check if a header starts with any of the given prefixes.'''
232 for prefix in prefixes:
232 for prefix in prefixes:
233 for comment in self.comments:
233 for comment in self.comments:
234 if comment.startswith(prefix):
234 if comment.startswith(prefix):
235 return True
235 return True
236 return False
236 return False
237
237
238 def __str__(self):
238 def __str__(self):
239 if not self.comments:
239 if not self.comments:
240 return ''
240 return ''
241 return '\n'.join(self.comments) + '\n\n'
241 return '\n'.join(self.comments) + '\n\n'
242
242
243 def _delmsg(self):
243 def _delmsg(self):
244 '''Remove existing message, keeping the rest of the comments fields.
244 '''Remove existing message, keeping the rest of the comments fields.
245 If comments contains 'subject: ', message will prepend
245 If comments contains 'subject: ', message will prepend
246 the field and a blank line.'''
246 the field and a blank line.'''
247 if self.message:
247 if self.message:
248 subj = 'subject: ' + self.message[0].lower()
248 subj = 'subject: ' + self.message[0].lower()
249 for i in xrange(len(self.comments)):
249 for i in xrange(len(self.comments)):
250 if subj == self.comments[i].lower():
250 if subj == self.comments[i].lower():
251 del self.comments[i]
251 del self.comments[i]
252 self.message = self.message[2:]
252 self.message = self.message[2:]
253 break
253 break
254 ci = 0
254 ci = 0
255 for mi in self.message:
255 for mi in self.message:
256 while mi != self.comments[ci]:
256 while mi != self.comments[ci]:
257 ci += 1
257 ci += 1
258 del self.comments[ci]
258 del self.comments[ci]
259
259
260 def newcommit(repo, phase, *args, **kwargs):
260 def newcommit(repo, phase, *args, **kwargs):
261 """helper dedicated to ensure a commit respect mq.secret setting
261 """helper dedicated to ensure a commit respect mq.secret setting
262
262
263 It should be used instead of repo.commit inside the mq source for operation
263 It should be used instead of repo.commit inside the mq source for operation
264 creating new changeset.
264 creating new changeset.
265 """
265 """
266 if phase is None:
266 if phase is None:
267 if repo.ui.configbool('mq', 'secret', False):
267 if repo.ui.configbool('mq', 'secret', False):
268 phase = phases.secret
268 phase = phases.secret
269 if phase is not None:
269 if phase is not None:
270 backup = repo.ui.backupconfig('phases', 'new-commit')
270 backup = repo.ui.backupconfig('phases', 'new-commit')
271 # Marking the repository as committing an mq patch can be used
271 # Marking the repository as committing an mq patch can be used
272 # to optimize operations like _branchtags().
272 # to optimize operations like _branchtags().
273 repo._committingpatch = True
273 repo._committingpatch = True
274 try:
274 try:
275 if phase is not None:
275 if phase is not None:
276 repo.ui.setconfig('phases', 'new-commit', phase)
276 repo.ui.setconfig('phases', 'new-commit', phase)
277 return repo.commit(*args, **kwargs)
277 return repo.commit(*args, **kwargs)
278 finally:
278 finally:
279 repo._committingpatch = False
279 repo._committingpatch = False
280 if phase is not None:
280 if phase is not None:
281 repo.ui.restoreconfig(backup)
281 repo.ui.restoreconfig(backup)
282
282
283 class queue(object):
283 class queue(object):
284 def __init__(self, ui, path, patchdir=None):
284 def __init__(self, ui, path, patchdir=None):
285 self.basepath = path
285 self.basepath = path
286 try:
286 try:
287 fh = open(os.path.join(path, 'patches.queue'))
287 fh = open(os.path.join(path, 'patches.queue'))
288 cur = fh.read().rstrip()
288 cur = fh.read().rstrip()
289 fh.close()
289 fh.close()
290 if not cur:
290 if not cur:
291 curpath = os.path.join(path, 'patches')
291 curpath = os.path.join(path, 'patches')
292 else:
292 else:
293 curpath = os.path.join(path, 'patches-' + cur)
293 curpath = os.path.join(path, 'patches-' + cur)
294 except IOError:
294 except IOError:
295 curpath = os.path.join(path, 'patches')
295 curpath = os.path.join(path, 'patches')
296 self.path = patchdir or curpath
296 self.path = patchdir or curpath
297 self.opener = scmutil.opener(self.path)
297 self.opener = scmutil.opener(self.path)
298 self.ui = ui
298 self.ui = ui
299 self.applieddirty = False
299 self.applieddirty = False
300 self.seriesdirty = False
300 self.seriesdirty = False
301 self.added = []
301 self.added = []
302 self.seriespath = "series"
302 self.seriespath = "series"
303 self.statuspath = "status"
303 self.statuspath = "status"
304 self.guardspath = "guards"
304 self.guardspath = "guards"
305 self.activeguards = None
305 self.activeguards = None
306 self.guardsdirty = False
306 self.guardsdirty = False
307 # Handle mq.git as a bool with extended values
307 # Handle mq.git as a bool with extended values
308 try:
308 try:
309 gitmode = ui.configbool('mq', 'git', None)
309 gitmode = ui.configbool('mq', 'git', None)
310 if gitmode is None:
310 if gitmode is None:
311 raise error.ConfigError()
311 raise error.ConfigError()
312 self.gitmode = gitmode and 'yes' or 'no'
312 self.gitmode = gitmode and 'yes' or 'no'
313 except error.ConfigError:
313 except error.ConfigError:
314 self.gitmode = ui.config('mq', 'git', 'auto').lower()
314 self.gitmode = ui.config('mq', 'git', 'auto').lower()
315 self.plainmode = ui.configbool('mq', 'plain', False)
315 self.plainmode = ui.configbool('mq', 'plain', False)
316
316
317 @util.propertycache
317 @util.propertycache
318 def applied(self):
318 def applied(self):
319 def parselines(lines):
319 def parselines(lines):
320 for l in lines:
320 for l in lines:
321 entry = l.split(':', 1)
321 entry = l.split(':', 1)
322 if len(entry) > 1:
322 if len(entry) > 1:
323 n, name = entry
323 n, name = entry
324 yield statusentry(bin(n), name)
324 yield statusentry(bin(n), name)
325 elif l.strip():
325 elif l.strip():
326 self.ui.warn(_('malformated mq status line: %s\n') % entry)
326 self.ui.warn(_('malformated mq status line: %s\n') % entry)
327 # else we ignore empty lines
327 # else we ignore empty lines
328 try:
328 try:
329 lines = self.opener.read(self.statuspath).splitlines()
329 lines = self.opener.read(self.statuspath).splitlines()
330 return list(parselines(lines))
330 return list(parselines(lines))
331 except IOError, e:
331 except IOError, e:
332 if e.errno == errno.ENOENT:
332 if e.errno == errno.ENOENT:
333 return []
333 return []
334 raise
334 raise
335
335
336 @util.propertycache
336 @util.propertycache
337 def fullseries(self):
337 def fullseries(self):
338 try:
338 try:
339 return self.opener.read(self.seriespath).splitlines()
339 return self.opener.read(self.seriespath).splitlines()
340 except IOError, e:
340 except IOError, e:
341 if e.errno == errno.ENOENT:
341 if e.errno == errno.ENOENT:
342 return []
342 return []
343 raise
343 raise
344
344
345 @util.propertycache
345 @util.propertycache
346 def series(self):
346 def series(self):
347 self.parseseries()
347 self.parseseries()
348 return self.series
348 return self.series
349
349
350 @util.propertycache
350 @util.propertycache
351 def seriesguards(self):
351 def seriesguards(self):
352 self.parseseries()
352 self.parseseries()
353 return self.seriesguards
353 return self.seriesguards
354
354
355 def invalidate(self):
355 def invalidate(self):
356 for a in 'applied fullseries series seriesguards'.split():
356 for a in 'applied fullseries series seriesguards'.split():
357 if a in self.__dict__:
357 if a in self.__dict__:
358 delattr(self, a)
358 delattr(self, a)
359 self.applieddirty = False
359 self.applieddirty = False
360 self.seriesdirty = False
360 self.seriesdirty = False
361 self.guardsdirty = False
361 self.guardsdirty = False
362 self.activeguards = None
362 self.activeguards = None
363
363
364 def diffopts(self, opts={}, patchfn=None):
364 def diffopts(self, opts={}, patchfn=None):
365 diffopts = patchmod.diffopts(self.ui, opts)
365 diffopts = patchmod.diffopts(self.ui, opts)
366 if self.gitmode == 'auto':
366 if self.gitmode == 'auto':
367 diffopts.upgrade = True
367 diffopts.upgrade = True
368 elif self.gitmode == 'keep':
368 elif self.gitmode == 'keep':
369 pass
369 pass
370 elif self.gitmode in ('yes', 'no'):
370 elif self.gitmode in ('yes', 'no'):
371 diffopts.git = self.gitmode == 'yes'
371 diffopts.git = self.gitmode == 'yes'
372 else:
372 else:
373 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
373 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
374 ' got %s') % self.gitmode)
374 ' got %s') % self.gitmode)
375 if patchfn:
375 if patchfn:
376 diffopts = self.patchopts(diffopts, patchfn)
376 diffopts = self.patchopts(diffopts, patchfn)
377 return diffopts
377 return diffopts
378
378
379 def patchopts(self, diffopts, *patches):
379 def patchopts(self, diffopts, *patches):
380 """Return a copy of input diff options with git set to true if
380 """Return a copy of input diff options with git set to true if
381 referenced patch is a git patch and should be preserved as such.
381 referenced patch is a git patch and should be preserved as such.
382 """
382 """
383 diffopts = diffopts.copy()
383 diffopts = diffopts.copy()
384 if not diffopts.git and self.gitmode == 'keep':
384 if not diffopts.git and self.gitmode == 'keep':
385 for patchfn in patches:
385 for patchfn in patches:
386 patchf = self.opener(patchfn, 'r')
386 patchf = self.opener(patchfn, 'r')
387 # if the patch was a git patch, refresh it as a git patch
387 # if the patch was a git patch, refresh it as a git patch
388 for line in patchf:
388 for line in patchf:
389 if line.startswith('diff --git'):
389 if line.startswith('diff --git'):
390 diffopts.git = True
390 diffopts.git = True
391 break
391 break
392 patchf.close()
392 patchf.close()
393 return diffopts
393 return diffopts
394
394
395 def join(self, *p):
395 def join(self, *p):
396 return os.path.join(self.path, *p)
396 return os.path.join(self.path, *p)
397
397
398 def findseries(self, patch):
398 def findseries(self, patch):
399 def matchpatch(l):
399 def matchpatch(l):
400 l = l.split('#', 1)[0]
400 l = l.split('#', 1)[0]
401 return l.strip() == patch
401 return l.strip() == patch
402 for index, l in enumerate(self.fullseries):
402 for index, l in enumerate(self.fullseries):
403 if matchpatch(l):
403 if matchpatch(l):
404 return index
404 return index
405 return None
405 return None
406
406
407 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
407 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
408
408
409 def parseseries(self):
409 def parseseries(self):
410 self.series = []
410 self.series = []
411 self.seriesguards = []
411 self.seriesguards = []
412 for l in self.fullseries:
412 for l in self.fullseries:
413 h = l.find('#')
413 h = l.find('#')
414 if h == -1:
414 if h == -1:
415 patch = l
415 patch = l
416 comment = ''
416 comment = ''
417 elif h == 0:
417 elif h == 0:
418 continue
418 continue
419 else:
419 else:
420 patch = l[:h]
420 patch = l[:h]
421 comment = l[h:]
421 comment = l[h:]
422 patch = patch.strip()
422 patch = patch.strip()
423 if patch:
423 if patch:
424 if patch in self.series:
424 if patch in self.series:
425 raise util.Abort(_('%s appears more than once in %s') %
425 raise util.Abort(_('%s appears more than once in %s') %
426 (patch, self.join(self.seriespath)))
426 (patch, self.join(self.seriespath)))
427 self.series.append(patch)
427 self.series.append(patch)
428 self.seriesguards.append(self.guard_re.findall(comment))
428 self.seriesguards.append(self.guard_re.findall(comment))
429
429
430 def checkguard(self, guard):
430 def checkguard(self, guard):
431 if not guard:
431 if not guard:
432 return _('guard cannot be an empty string')
432 return _('guard cannot be an empty string')
433 bad_chars = '# \t\r\n\f'
433 bad_chars = '# \t\r\n\f'
434 first = guard[0]
434 first = guard[0]
435 if first in '-+':
435 if first in '-+':
436 return (_('guard %r starts with invalid character: %r') %
436 return (_('guard %r starts with invalid character: %r') %
437 (guard, first))
437 (guard, first))
438 for c in bad_chars:
438 for c in bad_chars:
439 if c in guard:
439 if c in guard:
440 return _('invalid character in guard %r: %r') % (guard, c)
440 return _('invalid character in guard %r: %r') % (guard, c)
441
441
442 def setactive(self, guards):
442 def setactive(self, guards):
443 for guard in guards:
443 for guard in guards:
444 bad = self.checkguard(guard)
444 bad = self.checkguard(guard)
445 if bad:
445 if bad:
446 raise util.Abort(bad)
446 raise util.Abort(bad)
447 guards = sorted(set(guards))
447 guards = sorted(set(guards))
448 self.ui.debug('active guards: %s\n' % ' '.join(guards))
448 self.ui.debug('active guards: %s\n' % ' '.join(guards))
449 self.activeguards = guards
449 self.activeguards = guards
450 self.guardsdirty = True
450 self.guardsdirty = True
451
451
452 def active(self):
452 def active(self):
453 if self.activeguards is None:
453 if self.activeguards is None:
454 self.activeguards = []
454 self.activeguards = []
455 try:
455 try:
456 guards = self.opener.read(self.guardspath).split()
456 guards = self.opener.read(self.guardspath).split()
457 except IOError, err:
457 except IOError, err:
458 if err.errno != errno.ENOENT:
458 if err.errno != errno.ENOENT:
459 raise
459 raise
460 guards = []
460 guards = []
461 for i, guard in enumerate(guards):
461 for i, guard in enumerate(guards):
462 bad = self.checkguard(guard)
462 bad = self.checkguard(guard)
463 if bad:
463 if bad:
464 self.ui.warn('%s:%d: %s\n' %
464 self.ui.warn('%s:%d: %s\n' %
465 (self.join(self.guardspath), i + 1, bad))
465 (self.join(self.guardspath), i + 1, bad))
466 else:
466 else:
467 self.activeguards.append(guard)
467 self.activeguards.append(guard)
468 return self.activeguards
468 return self.activeguards
469
469
470 def setguards(self, idx, guards):
470 def setguards(self, idx, guards):
471 for g in guards:
471 for g in guards:
472 if len(g) < 2:
472 if len(g) < 2:
473 raise util.Abort(_('guard %r too short') % g)
473 raise util.Abort(_('guard %r too short') % g)
474 if g[0] not in '-+':
474 if g[0] not in '-+':
475 raise util.Abort(_('guard %r starts with invalid char') % g)
475 raise util.Abort(_('guard %r starts with invalid char') % g)
476 bad = self.checkguard(g[1:])
476 bad = self.checkguard(g[1:])
477 if bad:
477 if bad:
478 raise util.Abort(bad)
478 raise util.Abort(bad)
479 drop = self.guard_re.sub('', self.fullseries[idx])
479 drop = self.guard_re.sub('', self.fullseries[idx])
480 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
480 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
481 self.parseseries()
481 self.parseseries()
482 self.seriesdirty = True
482 self.seriesdirty = True
483
483
484 def pushable(self, idx):
484 def pushable(self, idx):
485 if isinstance(idx, str):
485 if isinstance(idx, str):
486 idx = self.series.index(idx)
486 idx = self.series.index(idx)
487 patchguards = self.seriesguards[idx]
487 patchguards = self.seriesguards[idx]
488 if not patchguards:
488 if not patchguards:
489 return True, None
489 return True, None
490 guards = self.active()
490 guards = self.active()
491 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
491 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
492 if exactneg:
492 if exactneg:
493 return False, repr(exactneg[0])
493 return False, repr(exactneg[0])
494 pos = [g for g in patchguards if g[0] == '+']
494 pos = [g for g in patchguards if g[0] == '+']
495 exactpos = [g for g in pos if g[1:] in guards]
495 exactpos = [g for g in pos if g[1:] in guards]
496 if pos:
496 if pos:
497 if exactpos:
497 if exactpos:
498 return True, repr(exactpos[0])
498 return True, repr(exactpos[0])
499 return False, ' '.join(map(repr, pos))
499 return False, ' '.join(map(repr, pos))
500 return True, ''
500 return True, ''
501
501
502 def explainpushable(self, idx, all_patches=False):
502 def explainpushable(self, idx, all_patches=False):
503 write = all_patches and self.ui.write or self.ui.warn
503 write = all_patches and self.ui.write or self.ui.warn
504 if all_patches or self.ui.verbose:
504 if all_patches or self.ui.verbose:
505 if isinstance(idx, str):
505 if isinstance(idx, str):
506 idx = self.series.index(idx)
506 idx = self.series.index(idx)
507 pushable, why = self.pushable(idx)
507 pushable, why = self.pushable(idx)
508 if all_patches and pushable:
508 if all_patches and pushable:
509 if why is None:
509 if why is None:
510 write(_('allowing %s - no guards in effect\n') %
510 write(_('allowing %s - no guards in effect\n') %
511 self.series[idx])
511 self.series[idx])
512 else:
512 else:
513 if not why:
513 if not why:
514 write(_('allowing %s - no matching negative guards\n') %
514 write(_('allowing %s - no matching negative guards\n') %
515 self.series[idx])
515 self.series[idx])
516 else:
516 else:
517 write(_('allowing %s - guarded by %s\n') %
517 write(_('allowing %s - guarded by %s\n') %
518 (self.series[idx], why))
518 (self.series[idx], why))
519 if not pushable:
519 if not pushable:
520 if why:
520 if why:
521 write(_('skipping %s - guarded by %s\n') %
521 write(_('skipping %s - guarded by %s\n') %
522 (self.series[idx], why))
522 (self.series[idx], why))
523 else:
523 else:
524 write(_('skipping %s - no matching guards\n') %
524 write(_('skipping %s - no matching guards\n') %
525 self.series[idx])
525 self.series[idx])
526
526
527 def savedirty(self):
527 def savedirty(self):
528 def writelist(items, path):
528 def writelist(items, path):
529 fp = self.opener(path, 'w')
529 fp = self.opener(path, 'w')
530 for i in items:
530 for i in items:
531 fp.write("%s\n" % i)
531 fp.write("%s\n" % i)
532 fp.close()
532 fp.close()
533 if self.applieddirty:
533 if self.applieddirty:
534 writelist(map(str, self.applied), self.statuspath)
534 writelist(map(str, self.applied), self.statuspath)
535 self.applieddirty = False
535 self.applieddirty = False
536 if self.seriesdirty:
536 if self.seriesdirty:
537 writelist(self.fullseries, self.seriespath)
537 writelist(self.fullseries, self.seriespath)
538 self.seriesdirty = False
538 self.seriesdirty = False
539 if self.guardsdirty:
539 if self.guardsdirty:
540 writelist(self.activeguards, self.guardspath)
540 writelist(self.activeguards, self.guardspath)
541 self.guardsdirty = False
541 self.guardsdirty = False
542 if self.added:
542 if self.added:
543 qrepo = self.qrepo()
543 qrepo = self.qrepo()
544 if qrepo:
544 if qrepo:
545 qrepo[None].add(f for f in self.added if f not in qrepo[None])
545 qrepo[None].add(f for f in self.added if f not in qrepo[None])
546 self.added = []
546 self.added = []
547
547
548 def removeundo(self, repo):
548 def removeundo(self, repo):
549 undo = repo.sjoin('undo')
549 undo = repo.sjoin('undo')
550 if not os.path.exists(undo):
550 if not os.path.exists(undo):
551 return
551 return
552 try:
552 try:
553 os.unlink(undo)
553 os.unlink(undo)
554 except OSError, inst:
554 except OSError, inst:
555 self.ui.warn(_('error removing undo: %s\n') % str(inst))
555 self.ui.warn(_('error removing undo: %s\n') % str(inst))
556
556
557 def backup(self, repo, files):
558 # backup local changes in --force case
559 for f in sorted(files):
560 absf = repo.wjoin(f)
561 if os.path.lexists(absf):
562 self.ui.note(_('saving current version of %s as %s\n') %
563 (f, f + '.orig'))
564 util.rename(absf, absf + '.orig')
565
557 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
566 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
558 fp=None, changes=None, opts={}):
567 fp=None, changes=None, opts={}):
559 stat = opts.get('stat')
568 stat = opts.get('stat')
560 m = scmutil.match(repo[node1], files, opts)
569 m = scmutil.match(repo[node1], files, opts)
561 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
570 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
562 changes, stat, fp)
571 changes, stat, fp)
563
572
564 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
573 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
565 # first try just applying the patch
574 # first try just applying the patch
566 (err, n) = self.apply(repo, [patch], update_status=False,
575 (err, n) = self.apply(repo, [patch], update_status=False,
567 strict=True, merge=rev)
576 strict=True, merge=rev)
568
577
569 if err == 0:
578 if err == 0:
570 return (err, n)
579 return (err, n)
571
580
572 if n is None:
581 if n is None:
573 raise util.Abort(_("apply failed for patch %s") % patch)
582 raise util.Abort(_("apply failed for patch %s") % patch)
574
583
575 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
584 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
576
585
577 # apply failed, strip away that rev and merge.
586 # apply failed, strip away that rev and merge.
578 hg.clean(repo, head)
587 hg.clean(repo, head)
579 self.strip(repo, [n], update=False, backup='strip')
588 self.strip(repo, [n], update=False, backup='strip')
580
589
581 ctx = repo[rev]
590 ctx = repo[rev]
582 ret = hg.merge(repo, rev)
591 ret = hg.merge(repo, rev)
583 if ret:
592 if ret:
584 raise util.Abort(_("update returned %d") % ret)
593 raise util.Abort(_("update returned %d") % ret)
585 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
594 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
586 if n is None:
595 if n is None:
587 raise util.Abort(_("repo commit failed"))
596 raise util.Abort(_("repo commit failed"))
588 try:
597 try:
589 ph = patchheader(mergeq.join(patch), self.plainmode)
598 ph = patchheader(mergeq.join(patch), self.plainmode)
590 except:
599 except:
591 raise util.Abort(_("unable to read %s") % patch)
600 raise util.Abort(_("unable to read %s") % patch)
592
601
593 diffopts = self.patchopts(diffopts, patch)
602 diffopts = self.patchopts(diffopts, patch)
594 patchf = self.opener(patch, "w")
603 patchf = self.opener(patch, "w")
595 comments = str(ph)
604 comments = str(ph)
596 if comments:
605 if comments:
597 patchf.write(comments)
606 patchf.write(comments)
598 self.printdiff(repo, diffopts, head, n, fp=patchf)
607 self.printdiff(repo, diffopts, head, n, fp=patchf)
599 patchf.close()
608 patchf.close()
600 self.removeundo(repo)
609 self.removeundo(repo)
601 return (0, n)
610 return (0, n)
602
611
603 def qparents(self, repo, rev=None):
612 def qparents(self, repo, rev=None):
604 if rev is None:
613 if rev is None:
605 (p1, p2) = repo.dirstate.parents()
614 (p1, p2) = repo.dirstate.parents()
606 if p2 == nullid:
615 if p2 == nullid:
607 return p1
616 return p1
608 if not self.applied:
617 if not self.applied:
609 return None
618 return None
610 return self.applied[-1].node
619 return self.applied[-1].node
611 p1, p2 = repo.changelog.parents(rev)
620 p1, p2 = repo.changelog.parents(rev)
612 if p2 != nullid and p2 in [x.node for x in self.applied]:
621 if p2 != nullid and p2 in [x.node for x in self.applied]:
613 return p2
622 return p2
614 return p1
623 return p1
615
624
616 def mergepatch(self, repo, mergeq, series, diffopts):
625 def mergepatch(self, repo, mergeq, series, diffopts):
617 if not self.applied:
626 if not self.applied:
618 # each of the patches merged in will have two parents. This
627 # each of the patches merged in will have two parents. This
619 # can confuse the qrefresh, qdiff, and strip code because it
628 # can confuse the qrefresh, qdiff, and strip code because it
620 # needs to know which parent is actually in the patch queue.
629 # needs to know which parent is actually in the patch queue.
621 # so, we insert a merge marker with only one parent. This way
630 # so, we insert a merge marker with only one parent. This way
622 # the first patch in the queue is never a merge patch
631 # the first patch in the queue is never a merge patch
623 #
632 #
624 pname = ".hg.patches.merge.marker"
633 pname = ".hg.patches.merge.marker"
625 n = newcommit(repo, None, '[mq]: merge marker', force=True)
634 n = newcommit(repo, None, '[mq]: merge marker', force=True)
626 self.removeundo(repo)
635 self.removeundo(repo)
627 self.applied.append(statusentry(n, pname))
636 self.applied.append(statusentry(n, pname))
628 self.applieddirty = True
637 self.applieddirty = True
629
638
630 head = self.qparents(repo)
639 head = self.qparents(repo)
631
640
632 for patch in series:
641 for patch in series:
633 patch = mergeq.lookup(patch, strict=True)
642 patch = mergeq.lookup(patch, strict=True)
634 if not patch:
643 if not patch:
635 self.ui.warn(_("patch %s does not exist\n") % patch)
644 self.ui.warn(_("patch %s does not exist\n") % patch)
636 return (1, None)
645 return (1, None)
637 pushable, reason = self.pushable(patch)
646 pushable, reason = self.pushable(patch)
638 if not pushable:
647 if not pushable:
639 self.explainpushable(patch, all_patches=True)
648 self.explainpushable(patch, all_patches=True)
640 continue
649 continue
641 info = mergeq.isapplied(patch)
650 info = mergeq.isapplied(patch)
642 if not info:
651 if not info:
643 self.ui.warn(_("patch %s is not applied\n") % patch)
652 self.ui.warn(_("patch %s is not applied\n") % patch)
644 return (1, None)
653 return (1, None)
645 rev = info[1]
654 rev = info[1]
646 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
655 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
647 if head:
656 if head:
648 self.applied.append(statusentry(head, patch))
657 self.applied.append(statusentry(head, patch))
649 self.applieddirty = True
658 self.applieddirty = True
650 if err:
659 if err:
651 return (err, head)
660 return (err, head)
652 self.savedirty()
661 self.savedirty()
653 return (0, head)
662 return (0, head)
654
663
655 def patch(self, repo, patchfile):
664 def patch(self, repo, patchfile):
656 '''Apply patchfile to the working directory.
665 '''Apply patchfile to the working directory.
657 patchfile: name of patch file'''
666 patchfile: name of patch file'''
658 files = set()
667 files = set()
659 try:
668 try:
660 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
669 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
661 files=files, eolmode=None)
670 files=files, eolmode=None)
662 return (True, list(files), fuzz)
671 return (True, list(files), fuzz)
663 except Exception, inst:
672 except Exception, inst:
664 self.ui.note(str(inst) + '\n')
673 self.ui.note(str(inst) + '\n')
665 if not self.ui.verbose:
674 if not self.ui.verbose:
666 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
675 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
667 self.ui.traceback()
676 self.ui.traceback()
668 return (False, list(files), False)
677 return (False, list(files), False)
669
678
670 def apply(self, repo, series, list=False, update_status=True,
679 def apply(self, repo, series, list=False, update_status=True,
671 strict=False, patchdir=None, merge=None, all_files=None):
680 strict=False, patchdir=None, merge=None, all_files=None):
672 wlock = lock = tr = None
681 wlock = lock = tr = None
673 try:
682 try:
674 wlock = repo.wlock()
683 wlock = repo.wlock()
675 lock = repo.lock()
684 lock = repo.lock()
676 tr = repo.transaction("qpush")
685 tr = repo.transaction("qpush")
677 try:
686 try:
678 ret = self._apply(repo, series, list, update_status,
687 ret = self._apply(repo, series, list, update_status,
679 strict, patchdir, merge, all_files=all_files)
688 strict, patchdir, merge, all_files=all_files)
680 tr.close()
689 tr.close()
681 self.savedirty()
690 self.savedirty()
682 return ret
691 return ret
683 except:
692 except:
684 try:
693 try:
685 tr.abort()
694 tr.abort()
686 finally:
695 finally:
687 repo.invalidate()
696 repo.invalidate()
688 repo.dirstate.invalidate()
697 repo.dirstate.invalidate()
689 self.invalidate()
698 self.invalidate()
690 raise
699 raise
691 finally:
700 finally:
692 release(tr, lock, wlock)
701 release(tr, lock, wlock)
693 self.removeundo(repo)
702 self.removeundo(repo)
694
703
695 def _apply(self, repo, series, list=False, update_status=True,
704 def _apply(self, repo, series, list=False, update_status=True,
696 strict=False, patchdir=None, merge=None, all_files=None):
705 strict=False, patchdir=None, merge=None, all_files=None):
697 '''returns (error, hash)
706 '''returns (error, hash)
698 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
707 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
699 # TODO unify with commands.py
708 # TODO unify with commands.py
700 if not patchdir:
709 if not patchdir:
701 patchdir = self.path
710 patchdir = self.path
702 err = 0
711 err = 0
703 n = None
712 n = None
704 for patchname in series:
713 for patchname in series:
705 pushable, reason = self.pushable(patchname)
714 pushable, reason = self.pushable(patchname)
706 if not pushable:
715 if not pushable:
707 self.explainpushable(patchname, all_patches=True)
716 self.explainpushable(patchname, all_patches=True)
708 continue
717 continue
709 self.ui.status(_("applying %s\n") % patchname)
718 self.ui.status(_("applying %s\n") % patchname)
710 pf = os.path.join(patchdir, patchname)
719 pf = os.path.join(patchdir, patchname)
711
720
712 try:
721 try:
713 ph = patchheader(self.join(patchname), self.plainmode)
722 ph = patchheader(self.join(patchname), self.plainmode)
714 except IOError:
723 except IOError:
715 self.ui.warn(_("unable to read %s\n") % patchname)
724 self.ui.warn(_("unable to read %s\n") % patchname)
716 err = 1
725 err = 1
717 break
726 break
718
727
719 message = ph.message
728 message = ph.message
720 if not message:
729 if not message:
721 # The commit message should not be translated
730 # The commit message should not be translated
722 message = "imported patch %s\n" % patchname
731 message = "imported patch %s\n" % patchname
723 else:
732 else:
724 if list:
733 if list:
725 # The commit message should not be translated
734 # The commit message should not be translated
726 message.append("\nimported patch %s" % patchname)
735 message.append("\nimported patch %s" % patchname)
727 message = '\n'.join(message)
736 message = '\n'.join(message)
728
737
729 if ph.haspatch:
738 if ph.haspatch:
730 (patcherr, files, fuzz) = self.patch(repo, pf)
739 (patcherr, files, fuzz) = self.patch(repo, pf)
731 if all_files is not None:
740 if all_files is not None:
732 all_files.update(files)
741 all_files.update(files)
733 patcherr = not patcherr
742 patcherr = not patcherr
734 else:
743 else:
735 self.ui.warn(_("patch %s is empty\n") % patchname)
744 self.ui.warn(_("patch %s is empty\n") % patchname)
736 patcherr, files, fuzz = 0, [], 0
745 patcherr, files, fuzz = 0, [], 0
737
746
738 if merge and files:
747 if merge and files:
739 # Mark as removed/merged and update dirstate parent info
748 # Mark as removed/merged and update dirstate parent info
740 removed = []
749 removed = []
741 merged = []
750 merged = []
742 for f in files:
751 for f in files:
743 if os.path.lexists(repo.wjoin(f)):
752 if os.path.lexists(repo.wjoin(f)):
744 merged.append(f)
753 merged.append(f)
745 else:
754 else:
746 removed.append(f)
755 removed.append(f)
747 for f in removed:
756 for f in removed:
748 repo.dirstate.remove(f)
757 repo.dirstate.remove(f)
749 for f in merged:
758 for f in merged:
750 repo.dirstate.merge(f)
759 repo.dirstate.merge(f)
751 p1, p2 = repo.dirstate.parents()
760 p1, p2 = repo.dirstate.parents()
752 repo.setparents(p1, merge)
761 repo.setparents(p1, merge)
753
762
754 match = scmutil.matchfiles(repo, files or [])
763 match = scmutil.matchfiles(repo, files or [])
755 oldtip = repo['tip']
764 oldtip = repo['tip']
756 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
765 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
757 force=True)
766 force=True)
758 if repo['tip'] == oldtip:
767 if repo['tip'] == oldtip:
759 raise util.Abort(_("qpush exactly duplicates child changeset"))
768 raise util.Abort(_("qpush exactly duplicates child changeset"))
760 if n is None:
769 if n is None:
761 raise util.Abort(_("repository commit failed"))
770 raise util.Abort(_("repository commit failed"))
762
771
763 if update_status:
772 if update_status:
764 self.applied.append(statusentry(n, patchname))
773 self.applied.append(statusentry(n, patchname))
765
774
766 if patcherr:
775 if patcherr:
767 self.ui.warn(_("patch failed, rejects left in working dir\n"))
776 self.ui.warn(_("patch failed, rejects left in working dir\n"))
768 err = 2
777 err = 2
769 break
778 break
770
779
771 if fuzz and strict:
780 if fuzz and strict:
772 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
781 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
773 err = 3
782 err = 3
774 break
783 break
775 return (err, n)
784 return (err, n)
776
785
777 def _cleanup(self, patches, numrevs, keep=False):
786 def _cleanup(self, patches, numrevs, keep=False):
778 if not keep:
787 if not keep:
779 r = self.qrepo()
788 r = self.qrepo()
780 if r:
789 if r:
781 r[None].forget(patches)
790 r[None].forget(patches)
782 for p in patches:
791 for p in patches:
783 os.unlink(self.join(p))
792 os.unlink(self.join(p))
784
793
785 qfinished = []
794 qfinished = []
786 if numrevs:
795 if numrevs:
787 qfinished = self.applied[:numrevs]
796 qfinished = self.applied[:numrevs]
788 del self.applied[:numrevs]
797 del self.applied[:numrevs]
789 self.applieddirty = True
798 self.applieddirty = True
790
799
791 unknown = []
800 unknown = []
792
801
793 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
802 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
794 reverse=True):
803 reverse=True):
795 if i is not None:
804 if i is not None:
796 del self.fullseries[i]
805 del self.fullseries[i]
797 else:
806 else:
798 unknown.append(p)
807 unknown.append(p)
799
808
800 if unknown:
809 if unknown:
801 if numrevs:
810 if numrevs:
802 rev = dict((entry.name, entry.node) for entry in qfinished)
811 rev = dict((entry.name, entry.node) for entry in qfinished)
803 for p in unknown:
812 for p in unknown:
804 msg = _('revision %s refers to unknown patches: %s\n')
813 msg = _('revision %s refers to unknown patches: %s\n')
805 self.ui.warn(msg % (short(rev[p]), p))
814 self.ui.warn(msg % (short(rev[p]), p))
806 else:
815 else:
807 msg = _('unknown patches: %s\n')
816 msg = _('unknown patches: %s\n')
808 raise util.Abort(''.join(msg % p for p in unknown))
817 raise util.Abort(''.join(msg % p for p in unknown))
809
818
810 self.parseseries()
819 self.parseseries()
811 self.seriesdirty = True
820 self.seriesdirty = True
812 return [entry.node for entry in qfinished]
821 return [entry.node for entry in qfinished]
813
822
814 def _revpatches(self, repo, revs):
823 def _revpatches(self, repo, revs):
815 firstrev = repo[self.applied[0].node].rev()
824 firstrev = repo[self.applied[0].node].rev()
816 patches = []
825 patches = []
817 for i, rev in enumerate(revs):
826 for i, rev in enumerate(revs):
818
827
819 if rev < firstrev:
828 if rev < firstrev:
820 raise util.Abort(_('revision %d is not managed') % rev)
829 raise util.Abort(_('revision %d is not managed') % rev)
821
830
822 ctx = repo[rev]
831 ctx = repo[rev]
823 base = self.applied[i].node
832 base = self.applied[i].node
824 if ctx.node() != base:
833 if ctx.node() != base:
825 msg = _('cannot delete revision %d above applied patches')
834 msg = _('cannot delete revision %d above applied patches')
826 raise util.Abort(msg % rev)
835 raise util.Abort(msg % rev)
827
836
828 patch = self.applied[i].name
837 patch = self.applied[i].name
829 for fmt in ('[mq]: %s', 'imported patch %s'):
838 for fmt in ('[mq]: %s', 'imported patch %s'):
830 if ctx.description() == fmt % patch:
839 if ctx.description() == fmt % patch:
831 msg = _('patch %s finalized without changeset message\n')
840 msg = _('patch %s finalized without changeset message\n')
832 repo.ui.status(msg % patch)
841 repo.ui.status(msg % patch)
833 break
842 break
834
843
835 patches.append(patch)
844 patches.append(patch)
836 return patches
845 return patches
837
846
838 def finish(self, repo, revs):
847 def finish(self, repo, revs):
839 # Manually trigger phase computation to ensure phasedefaults is
848 # Manually trigger phase computation to ensure phasedefaults is
840 # executed before we remove the patches.
849 # executed before we remove the patches.
841 repo._phaserev
850 repo._phaserev
842 patches = self._revpatches(repo, sorted(revs))
851 patches = self._revpatches(repo, sorted(revs))
843 qfinished = self._cleanup(patches, len(patches))
852 qfinished = self._cleanup(patches, len(patches))
844 if qfinished and repo.ui.configbool('mq', 'secret', False):
853 if qfinished and repo.ui.configbool('mq', 'secret', False):
845 # only use this logic when the secret option is added
854 # only use this logic when the secret option is added
846 oldqbase = repo[qfinished[0]]
855 oldqbase = repo[qfinished[0]]
847 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
856 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
848 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
857 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
849 phases.advanceboundary(repo, tphase, qfinished)
858 phases.advanceboundary(repo, tphase, qfinished)
850
859
851 def delete(self, repo, patches, opts):
860 def delete(self, repo, patches, opts):
852 if not patches and not opts.get('rev'):
861 if not patches and not opts.get('rev'):
853 raise util.Abort(_('qdelete requires at least one revision or '
862 raise util.Abort(_('qdelete requires at least one revision or '
854 'patch name'))
863 'patch name'))
855
864
856 realpatches = []
865 realpatches = []
857 for patch in patches:
866 for patch in patches:
858 patch = self.lookup(patch, strict=True)
867 patch = self.lookup(patch, strict=True)
859 info = self.isapplied(patch)
868 info = self.isapplied(patch)
860 if info:
869 if info:
861 raise util.Abort(_("cannot delete applied patch %s") % patch)
870 raise util.Abort(_("cannot delete applied patch %s") % patch)
862 if patch not in self.series:
871 if patch not in self.series:
863 raise util.Abort(_("patch %s not in series file") % patch)
872 raise util.Abort(_("patch %s not in series file") % patch)
864 if patch not in realpatches:
873 if patch not in realpatches:
865 realpatches.append(patch)
874 realpatches.append(patch)
866
875
867 numrevs = 0
876 numrevs = 0
868 if opts.get('rev'):
877 if opts.get('rev'):
869 if not self.applied:
878 if not self.applied:
870 raise util.Abort(_('no patches applied'))
879 raise util.Abort(_('no patches applied'))
871 revs = scmutil.revrange(repo, opts.get('rev'))
880 revs = scmutil.revrange(repo, opts.get('rev'))
872 if len(revs) > 1 and revs[0] > revs[1]:
881 if len(revs) > 1 and revs[0] > revs[1]:
873 revs.reverse()
882 revs.reverse()
874 revpatches = self._revpatches(repo, revs)
883 revpatches = self._revpatches(repo, revs)
875 realpatches += revpatches
884 realpatches += revpatches
876 numrevs = len(revpatches)
885 numrevs = len(revpatches)
877
886
878 self._cleanup(realpatches, numrevs, opts.get('keep'))
887 self._cleanup(realpatches, numrevs, opts.get('keep'))
879
888
880 def checktoppatch(self, repo):
889 def checktoppatch(self, repo):
881 if self.applied:
890 if self.applied:
882 top = self.applied[-1].node
891 top = self.applied[-1].node
883 patch = self.applied[-1].name
892 patch = self.applied[-1].name
884 pp = repo.dirstate.parents()
893 pp = repo.dirstate.parents()
885 if top not in pp:
894 if top not in pp:
886 raise util.Abort(_("working directory revision is not qtip"))
895 raise util.Abort(_("working directory revision is not qtip"))
887 return top, patch
896 return top, patch
888 return None, None
897 return None, None
889
898
890 def checksubstate(self, repo):
899 def checksubstate(self, repo):
891 '''return list of subrepos at a different revision than substate.
900 '''return list of subrepos at a different revision than substate.
892 Abort if any subrepos have uncommitted changes.'''
901 Abort if any subrepos have uncommitted changes.'''
893 inclsubs = []
902 inclsubs = []
894 wctx = repo[None]
903 wctx = repo[None]
895 for s in wctx.substate:
904 for s in wctx.substate:
896 if wctx.sub(s).dirty(True):
905 if wctx.sub(s).dirty(True):
897 raise util.Abort(
906 raise util.Abort(
898 _("uncommitted changes in subrepository %s") % s)
907 _("uncommitted changes in subrepository %s") % s)
899 elif wctx.sub(s).dirty():
908 elif wctx.sub(s).dirty():
900 inclsubs.append(s)
909 inclsubs.append(s)
901 return inclsubs
910 return inclsubs
902
911
903 def localchangesfound(self, refresh=True):
912 def localchangesfound(self, refresh=True):
904 if refresh:
913 if refresh:
905 raise util.Abort(_("local changes found, refresh first"))
914 raise util.Abort(_("local changes found, refresh first"))
906 else:
915 else:
907 raise util.Abort(_("local changes found"))
916 raise util.Abort(_("local changes found"))
908
917
909 def checklocalchanges(self, repo, force=False, refresh=True):
918 def checklocalchanges(self, repo, force=False, refresh=True):
910 m, a, r, d = repo.status()[:4]
919 m, a, r, d = repo.status()[:4]
911 if (m or a or r or d) and not force:
920 if (m or a or r or d) and not force:
912 self.localchangesfound(refresh)
921 self.localchangesfound(refresh)
913 return m, a, r, d
922 return m, a, r, d
914
923
915 _reserved = ('series', 'status', 'guards', '.', '..')
924 _reserved = ('series', 'status', 'guards', '.', '..')
916 def checkreservedname(self, name):
925 def checkreservedname(self, name):
917 if name in self._reserved:
926 if name in self._reserved:
918 raise util.Abort(_('"%s" cannot be used as the name of a patch')
927 raise util.Abort(_('"%s" cannot be used as the name of a patch')
919 % name)
928 % name)
920 for prefix in ('.hg', '.mq'):
929 for prefix in ('.hg', '.mq'):
921 if name.startswith(prefix):
930 if name.startswith(prefix):
922 raise util.Abort(_('patch name cannot begin with "%s"')
931 raise util.Abort(_('patch name cannot begin with "%s"')
923 % prefix)
932 % prefix)
924 for c in ('#', ':'):
933 for c in ('#', ':'):
925 if c in name:
934 if c in name:
926 raise util.Abort(_('"%s" cannot be used in the name of a patch')
935 raise util.Abort(_('"%s" cannot be used in the name of a patch')
927 % c)
936 % c)
928
937
929 def checkpatchname(self, name, force=False):
938 def checkpatchname(self, name, force=False):
930 self.checkreservedname(name)
939 self.checkreservedname(name)
931 if not force and os.path.exists(self.join(name)):
940 if not force and os.path.exists(self.join(name)):
932 if os.path.isdir(self.join(name)):
941 if os.path.isdir(self.join(name)):
933 raise util.Abort(_('"%s" already exists as a directory')
942 raise util.Abort(_('"%s" already exists as a directory')
934 % name)
943 % name)
935 else:
944 else:
936 raise util.Abort(_('patch "%s" already exists') % name)
945 raise util.Abort(_('patch "%s" already exists') % name)
937
946
938 def new(self, repo, patchfn, *pats, **opts):
947 def new(self, repo, patchfn, *pats, **opts):
939 """options:
948 """options:
940 msg: a string or a no-argument function returning a string
949 msg: a string or a no-argument function returning a string
941 """
950 """
942 msg = opts.get('msg')
951 msg = opts.get('msg')
943 user = opts.get('user')
952 user = opts.get('user')
944 date = opts.get('date')
953 date = opts.get('date')
945 if date:
954 if date:
946 date = util.parsedate(date)
955 date = util.parsedate(date)
947 diffopts = self.diffopts({'git': opts.get('git')})
956 diffopts = self.diffopts({'git': opts.get('git')})
948 if opts.get('checkname', True):
957 if opts.get('checkname', True):
949 self.checkpatchname(patchfn)
958 self.checkpatchname(patchfn)
950 inclsubs = self.checksubstate(repo)
959 inclsubs = self.checksubstate(repo)
951 if inclsubs:
960 if inclsubs:
952 inclsubs.append('.hgsubstate')
961 inclsubs.append('.hgsubstate')
953 substatestate = repo.dirstate['.hgsubstate']
962 substatestate = repo.dirstate['.hgsubstate']
954 if opts.get('include') or opts.get('exclude') or pats:
963 if opts.get('include') or opts.get('exclude') or pats:
955 if inclsubs:
964 if inclsubs:
956 pats = list(pats or []) + inclsubs
965 pats = list(pats or []) + inclsubs
957 match = scmutil.match(repo[None], pats, opts)
966 match = scmutil.match(repo[None], pats, opts)
958 # detect missing files in pats
967 # detect missing files in pats
959 def badfn(f, msg):
968 def badfn(f, msg):
960 if f != '.hgsubstate': # .hgsubstate is auto-created
969 if f != '.hgsubstate': # .hgsubstate is auto-created
961 raise util.Abort('%s: %s' % (f, msg))
970 raise util.Abort('%s: %s' % (f, msg))
962 match.bad = badfn
971 match.bad = badfn
963 changes = repo.status(match=match)
972 changes = repo.status(match=match)
964 m, a, r, d = changes[:4]
973 m, a, r, d = changes[:4]
965 else:
974 else:
966 changes = self.checklocalchanges(repo, force=True)
975 changes = self.checklocalchanges(repo, force=True)
967 m, a, r, d = changes
976 m, a, r, d = changes
968 match = scmutil.matchfiles(repo, m + a + r + inclsubs)
977 match = scmutil.matchfiles(repo, m + a + r + inclsubs)
969 if len(repo[None].parents()) > 1:
978 if len(repo[None].parents()) > 1:
970 raise util.Abort(_('cannot manage merge changesets'))
979 raise util.Abort(_('cannot manage merge changesets'))
971 commitfiles = m + a + r
980 commitfiles = m + a + r
972 self.checktoppatch(repo)
981 self.checktoppatch(repo)
973 insert = self.fullseriesend()
982 insert = self.fullseriesend()
974 wlock = repo.wlock()
983 wlock = repo.wlock()
975 try:
984 try:
976 try:
985 try:
977 # if patch file write fails, abort early
986 # if patch file write fails, abort early
978 p = self.opener(patchfn, "w")
987 p = self.opener(patchfn, "w")
979 except IOError, e:
988 except IOError, e:
980 raise util.Abort(_('cannot write patch "%s": %s')
989 raise util.Abort(_('cannot write patch "%s": %s')
981 % (patchfn, e.strerror))
990 % (patchfn, e.strerror))
982 try:
991 try:
983 if self.plainmode:
992 if self.plainmode:
984 if user:
993 if user:
985 p.write("From: " + user + "\n")
994 p.write("From: " + user + "\n")
986 if not date:
995 if not date:
987 p.write("\n")
996 p.write("\n")
988 if date:
997 if date:
989 p.write("Date: %d %d\n\n" % date)
998 p.write("Date: %d %d\n\n" % date)
990 else:
999 else:
991 p.write("# HG changeset patch\n")
1000 p.write("# HG changeset patch\n")
992 p.write("# Parent "
1001 p.write("# Parent "
993 + hex(repo[None].p1().node()) + "\n")
1002 + hex(repo[None].p1().node()) + "\n")
994 if user:
1003 if user:
995 p.write("# User " + user + "\n")
1004 p.write("# User " + user + "\n")
996 if date:
1005 if date:
997 p.write("# Date %s %s\n\n" % date)
1006 p.write("# Date %s %s\n\n" % date)
998 if util.safehasattr(msg, '__call__'):
1007 if util.safehasattr(msg, '__call__'):
999 msg = msg()
1008 msg = msg()
1000 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
1009 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
1001 n = newcommit(repo, None, commitmsg, user, date, match=match,
1010 n = newcommit(repo, None, commitmsg, user, date, match=match,
1002 force=True)
1011 force=True)
1003 if n is None:
1012 if n is None:
1004 raise util.Abort(_("repo commit failed"))
1013 raise util.Abort(_("repo commit failed"))
1005 try:
1014 try:
1006 self.fullseries[insert:insert] = [patchfn]
1015 self.fullseries[insert:insert] = [patchfn]
1007 self.applied.append(statusentry(n, patchfn))
1016 self.applied.append(statusentry(n, patchfn))
1008 self.parseseries()
1017 self.parseseries()
1009 self.seriesdirty = True
1018 self.seriesdirty = True
1010 self.applieddirty = True
1019 self.applieddirty = True
1011 if msg:
1020 if msg:
1012 msg = msg + "\n\n"
1021 msg = msg + "\n\n"
1013 p.write(msg)
1022 p.write(msg)
1014 if commitfiles:
1023 if commitfiles:
1015 parent = self.qparents(repo, n)
1024 parent = self.qparents(repo, n)
1016 if inclsubs:
1025 if inclsubs:
1017 if substatestate in 'a?':
1026 if substatestate in 'a?':
1018 changes[1].append('.hgsubstate')
1027 changes[1].append('.hgsubstate')
1019 elif substatestate in 'r':
1028 elif substatestate in 'r':
1020 changes[2].append('.hgsubstate')
1029 changes[2].append('.hgsubstate')
1021 else: # modified
1030 else: # modified
1022 changes[0].append('.hgsubstate')
1031 changes[0].append('.hgsubstate')
1023 chunks = patchmod.diff(repo, node1=parent, node2=n,
1032 chunks = patchmod.diff(repo, node1=parent, node2=n,
1024 changes=changes, opts=diffopts)
1033 changes=changes, opts=diffopts)
1025 for chunk in chunks:
1034 for chunk in chunks:
1026 p.write(chunk)
1035 p.write(chunk)
1027 p.close()
1036 p.close()
1028 r = self.qrepo()
1037 r = self.qrepo()
1029 if r:
1038 if r:
1030 r[None].add([patchfn])
1039 r[None].add([patchfn])
1031 except:
1040 except:
1032 repo.rollback()
1041 repo.rollback()
1033 raise
1042 raise
1034 except Exception:
1043 except Exception:
1035 patchpath = self.join(patchfn)
1044 patchpath = self.join(patchfn)
1036 try:
1045 try:
1037 os.unlink(patchpath)
1046 os.unlink(patchpath)
1038 except:
1047 except:
1039 self.ui.warn(_('error unlinking %s\n') % patchpath)
1048 self.ui.warn(_('error unlinking %s\n') % patchpath)
1040 raise
1049 raise
1041 self.removeundo(repo)
1050 self.removeundo(repo)
1042 finally:
1051 finally:
1043 release(wlock)
1052 release(wlock)
1044
1053
1045 def strip(self, repo, revs, update=True, backup="all", force=None):
1054 def strip(self, repo, revs, update=True, backup="all", force=None):
1046 wlock = lock = None
1055 wlock = lock = None
1047 try:
1056 try:
1048 wlock = repo.wlock()
1057 wlock = repo.wlock()
1049 lock = repo.lock()
1058 lock = repo.lock()
1050
1059
1051 if update:
1060 if update:
1052 self.checklocalchanges(repo, force=force, refresh=False)
1061 self.checklocalchanges(repo, force=force, refresh=False)
1053 urev = self.qparents(repo, revs[0])
1062 urev = self.qparents(repo, revs[0])
1054 hg.clean(repo, urev)
1063 hg.clean(repo, urev)
1055 repo.dirstate.write()
1064 repo.dirstate.write()
1056
1065
1057 repair.strip(self.ui, repo, revs, backup)
1066 repair.strip(self.ui, repo, revs, backup)
1058 finally:
1067 finally:
1059 release(lock, wlock)
1068 release(lock, wlock)
1060
1069
1061 def isapplied(self, patch):
1070 def isapplied(self, patch):
1062 """returns (index, rev, patch)"""
1071 """returns (index, rev, patch)"""
1063 for i, a in enumerate(self.applied):
1072 for i, a in enumerate(self.applied):
1064 if a.name == patch:
1073 if a.name == patch:
1065 return (i, a.node, a.name)
1074 return (i, a.node, a.name)
1066 return None
1075 return None
1067
1076
1068 # if the exact patch name does not exist, we try a few
1077 # if the exact patch name does not exist, we try a few
1069 # variations. If strict is passed, we try only #1
1078 # variations. If strict is passed, we try only #1
1070 #
1079 #
1071 # 1) a number (as string) to indicate an offset in the series file
1080 # 1) a number (as string) to indicate an offset in the series file
1072 # 2) a unique substring of the patch name was given
1081 # 2) a unique substring of the patch name was given
1073 # 3) patchname[-+]num to indicate an offset in the series file
1082 # 3) patchname[-+]num to indicate an offset in the series file
1074 def lookup(self, patch, strict=False):
1083 def lookup(self, patch, strict=False):
1075 def partialname(s):
1084 def partialname(s):
1076 if s in self.series:
1085 if s in self.series:
1077 return s
1086 return s
1078 matches = [x for x in self.series if s in x]
1087 matches = [x for x in self.series if s in x]
1079 if len(matches) > 1:
1088 if len(matches) > 1:
1080 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1089 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1081 for m in matches:
1090 for m in matches:
1082 self.ui.warn(' %s\n' % m)
1091 self.ui.warn(' %s\n' % m)
1083 return None
1092 return None
1084 if matches:
1093 if matches:
1085 return matches[0]
1094 return matches[0]
1086 if self.series and self.applied:
1095 if self.series and self.applied:
1087 if s == 'qtip':
1096 if s == 'qtip':
1088 return self.series[self.seriesend(True)-1]
1097 return self.series[self.seriesend(True)-1]
1089 if s == 'qbase':
1098 if s == 'qbase':
1090 return self.series[0]
1099 return self.series[0]
1091 return None
1100 return None
1092
1101
1093 if patch in self.series:
1102 if patch in self.series:
1094 return patch
1103 return patch
1095
1104
1096 if not os.path.isfile(self.join(patch)):
1105 if not os.path.isfile(self.join(patch)):
1097 try:
1106 try:
1098 sno = int(patch)
1107 sno = int(patch)
1099 except (ValueError, OverflowError):
1108 except (ValueError, OverflowError):
1100 pass
1109 pass
1101 else:
1110 else:
1102 if -len(self.series) <= sno < len(self.series):
1111 if -len(self.series) <= sno < len(self.series):
1103 return self.series[sno]
1112 return self.series[sno]
1104
1113
1105 if not strict:
1114 if not strict:
1106 res = partialname(patch)
1115 res = partialname(patch)
1107 if res:
1116 if res:
1108 return res
1117 return res
1109 minus = patch.rfind('-')
1118 minus = patch.rfind('-')
1110 if minus >= 0:
1119 if minus >= 0:
1111 res = partialname(patch[:minus])
1120 res = partialname(patch[:minus])
1112 if res:
1121 if res:
1113 i = self.series.index(res)
1122 i = self.series.index(res)
1114 try:
1123 try:
1115 off = int(patch[minus + 1:] or 1)
1124 off = int(patch[minus + 1:] or 1)
1116 except (ValueError, OverflowError):
1125 except (ValueError, OverflowError):
1117 pass
1126 pass
1118 else:
1127 else:
1119 if i - off >= 0:
1128 if i - off >= 0:
1120 return self.series[i - off]
1129 return self.series[i - off]
1121 plus = patch.rfind('+')
1130 plus = patch.rfind('+')
1122 if plus >= 0:
1131 if plus >= 0:
1123 res = partialname(patch[:plus])
1132 res = partialname(patch[:plus])
1124 if res:
1133 if res:
1125 i = self.series.index(res)
1134 i = self.series.index(res)
1126 try:
1135 try:
1127 off = int(patch[plus + 1:] or 1)
1136 off = int(patch[plus + 1:] or 1)
1128 except (ValueError, OverflowError):
1137 except (ValueError, OverflowError):
1129 pass
1138 pass
1130 else:
1139 else:
1131 if i + off < len(self.series):
1140 if i + off < len(self.series):
1132 return self.series[i + off]
1141 return self.series[i + off]
1133 raise util.Abort(_("patch %s not in series") % patch)
1142 raise util.Abort(_("patch %s not in series") % patch)
1134
1143
1135 def push(self, repo, patch=None, force=False, list=False,
1144 def push(self, repo, patch=None, force=False, list=False,
1136 mergeq=None, all=False, move=False, exact=False):
1145 mergeq=None, all=False, move=False, exact=False):
1137 diffopts = self.diffopts()
1146 diffopts = self.diffopts()
1138 wlock = repo.wlock()
1147 wlock = repo.wlock()
1139 try:
1148 try:
1140 heads = []
1149 heads = []
1141 for b, ls in repo.branchmap().iteritems():
1150 for b, ls in repo.branchmap().iteritems():
1142 heads += ls
1151 heads += ls
1143 if not heads:
1152 if not heads:
1144 heads = [nullid]
1153 heads = [nullid]
1145 if repo.dirstate.p1() not in heads and not exact:
1154 if repo.dirstate.p1() not in heads and not exact:
1146 self.ui.status(_("(working directory not at a head)\n"))
1155 self.ui.status(_("(working directory not at a head)\n"))
1147
1156
1148 if not self.series:
1157 if not self.series:
1149 self.ui.warn(_('no patches in series\n'))
1158 self.ui.warn(_('no patches in series\n'))
1150 return 0
1159 return 0
1151
1160
1152 # Suppose our series file is: A B C and the current 'top'
1161 # Suppose our series file is: A B C and the current 'top'
1153 # patch is B. qpush C should be performed (moving forward)
1162 # patch is B. qpush C should be performed (moving forward)
1154 # qpush B is a NOP (no change) qpush A is an error (can't
1163 # qpush B is a NOP (no change) qpush A is an error (can't
1155 # go backwards with qpush)
1164 # go backwards with qpush)
1156 if patch:
1165 if patch:
1157 patch = self.lookup(patch)
1166 patch = self.lookup(patch)
1158 info = self.isapplied(patch)
1167 info = self.isapplied(patch)
1159 if info and info[0] >= len(self.applied) - 1:
1168 if info and info[0] >= len(self.applied) - 1:
1160 self.ui.warn(
1169 self.ui.warn(
1161 _('qpush: %s is already at the top\n') % patch)
1170 _('qpush: %s is already at the top\n') % patch)
1162 return 0
1171 return 0
1163
1172
1164 pushable, reason = self.pushable(patch)
1173 pushable, reason = self.pushable(patch)
1165 if pushable:
1174 if pushable:
1166 if self.series.index(patch) < self.seriesend():
1175 if self.series.index(patch) < self.seriesend():
1167 raise util.Abort(
1176 raise util.Abort(
1168 _("cannot push to a previous patch: %s") % patch)
1177 _("cannot push to a previous patch: %s") % patch)
1169 else:
1178 else:
1170 if reason:
1179 if reason:
1171 reason = _('guarded by %s') % reason
1180 reason = _('guarded by %s') % reason
1172 else:
1181 else:
1173 reason = _('no matching guards')
1182 reason = _('no matching guards')
1174 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1183 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1175 return 1
1184 return 1
1176 elif all:
1185 elif all:
1177 patch = self.series[-1]
1186 patch = self.series[-1]
1178 if self.isapplied(patch):
1187 if self.isapplied(patch):
1179 self.ui.warn(_('all patches are currently applied\n'))
1188 self.ui.warn(_('all patches are currently applied\n'))
1180 return 0
1189 return 0
1181
1190
1182 # Following the above example, starting at 'top' of B:
1191 # Following the above example, starting at 'top' of B:
1183 # qpush should be performed (pushes C), but a subsequent
1192 # qpush should be performed (pushes C), but a subsequent
1184 # qpush without an argument is an error (nothing to
1193 # qpush without an argument is an error (nothing to
1185 # apply). This allows a loop of "...while hg qpush..." to
1194 # apply). This allows a loop of "...while hg qpush..." to
1186 # work as it detects an error when done
1195 # work as it detects an error when done
1187 start = self.seriesend()
1196 start = self.seriesend()
1188 if start == len(self.series):
1197 if start == len(self.series):
1189 self.ui.warn(_('patch series already fully applied\n'))
1198 self.ui.warn(_('patch series already fully applied\n'))
1190 return 1
1199 return 1
1191 if not force:
1200 if not force:
1192 self.checklocalchanges(repo, refresh=self.applied)
1201 self.checklocalchanges(repo, refresh=self.applied)
1193
1202
1194 if exact:
1203 if exact:
1195 if move:
1204 if move:
1196 raise util.Abort(_("cannot use --exact and --move together"))
1205 raise util.Abort(_("cannot use --exact and --move together"))
1197 if self.applied:
1206 if self.applied:
1198 raise util.Abort(_("cannot push --exact with applied patches"))
1207 raise util.Abort(_("cannot push --exact with applied patches"))
1199 root = self.series[start]
1208 root = self.series[start]
1200 target = patchheader(self.join(root), self.plainmode).parent
1209 target = patchheader(self.join(root), self.plainmode).parent
1201 if not target:
1210 if not target:
1202 raise util.Abort(
1211 raise util.Abort(
1203 _("%s does not have a parent recorded") % root)
1212 _("%s does not have a parent recorded") % root)
1204 if not repo[target] == repo['.']:
1213 if not repo[target] == repo['.']:
1205 hg.update(repo, target)
1214 hg.update(repo, target)
1206
1215
1207 if move:
1216 if move:
1208 if not patch:
1217 if not patch:
1209 raise util.Abort(_("please specify the patch to move"))
1218 raise util.Abort(_("please specify the patch to move"))
1210 for fullstart, rpn in enumerate(self.fullseries):
1219 for fullstart, rpn in enumerate(self.fullseries):
1211 # strip markers for patch guards
1220 # strip markers for patch guards
1212 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1221 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1213 break
1222 break
1214 for i, rpn in enumerate(self.fullseries[fullstart:]):
1223 for i, rpn in enumerate(self.fullseries[fullstart:]):
1215 # strip markers for patch guards
1224 # strip markers for patch guards
1216 if self.guard_re.split(rpn, 1)[0] == patch:
1225 if self.guard_re.split(rpn, 1)[0] == patch:
1217 break
1226 break
1218 index = fullstart + i
1227 index = fullstart + i
1219 assert index < len(self.fullseries)
1228 assert index < len(self.fullseries)
1220 fullpatch = self.fullseries[index]
1229 fullpatch = self.fullseries[index]
1221 del self.fullseries[index]
1230 del self.fullseries[index]
1222 self.fullseries.insert(fullstart, fullpatch)
1231 self.fullseries.insert(fullstart, fullpatch)
1223 self.parseseries()
1232 self.parseseries()
1224 self.seriesdirty = True
1233 self.seriesdirty = True
1225
1234
1226 self.applieddirty = True
1235 self.applieddirty = True
1227 if start > 0:
1236 if start > 0:
1228 self.checktoppatch(repo)
1237 self.checktoppatch(repo)
1229 if not patch:
1238 if not patch:
1230 patch = self.series[start]
1239 patch = self.series[start]
1231 end = start + 1
1240 end = start + 1
1232 else:
1241 else:
1233 end = self.series.index(patch, start) + 1
1242 end = self.series.index(patch, start) + 1
1234
1243
1235 s = self.series[start:end]
1244 s = self.series[start:end]
1236 all_files = set()
1245 all_files = set()
1237 try:
1246 try:
1238 if mergeq:
1247 if mergeq:
1239 ret = self.mergepatch(repo, mergeq, s, diffopts)
1248 ret = self.mergepatch(repo, mergeq, s, diffopts)
1240 else:
1249 else:
1241 ret = self.apply(repo, s, list, all_files=all_files)
1250 ret = self.apply(repo, s, list, all_files=all_files)
1242 except:
1251 except:
1243 self.ui.warn(_('cleaning up working directory...'))
1252 self.ui.warn(_('cleaning up working directory...'))
1244 node = repo.dirstate.p1()
1253 node = repo.dirstate.p1()
1245 hg.revert(repo, node, None)
1254 hg.revert(repo, node, None)
1246 # only remove unknown files that we know we touched or
1255 # only remove unknown files that we know we touched or
1247 # created while patching
1256 # created while patching
1248 for f in all_files:
1257 for f in all_files:
1249 if f not in repo.dirstate:
1258 if f not in repo.dirstate:
1250 try:
1259 try:
1251 util.unlinkpath(repo.wjoin(f))
1260 util.unlinkpath(repo.wjoin(f))
1252 except OSError, inst:
1261 except OSError, inst:
1253 if inst.errno != errno.ENOENT:
1262 if inst.errno != errno.ENOENT:
1254 raise
1263 raise
1255 self.ui.warn(_('done\n'))
1264 self.ui.warn(_('done\n'))
1256 raise
1265 raise
1257
1266
1258 if not self.applied:
1267 if not self.applied:
1259 return ret[0]
1268 return ret[0]
1260 top = self.applied[-1].name
1269 top = self.applied[-1].name
1261 if ret[0] and ret[0] > 1:
1270 if ret[0] and ret[0] > 1:
1262 msg = _("errors during apply, please fix and refresh %s\n")
1271 msg = _("errors during apply, please fix and refresh %s\n")
1263 self.ui.write(msg % top)
1272 self.ui.write(msg % top)
1264 else:
1273 else:
1265 self.ui.write(_("now at: %s\n") % top)
1274 self.ui.write(_("now at: %s\n") % top)
1266 return ret[0]
1275 return ret[0]
1267
1276
1268 finally:
1277 finally:
1269 wlock.release()
1278 wlock.release()
1270
1279
1271 def pop(self, repo, patch=None, force=False, update=True, all=False):
1280 def pop(self, repo, patch=None, force=False, update=True, all=False):
1272 wlock = repo.wlock()
1281 wlock = repo.wlock()
1273 try:
1282 try:
1274 if patch:
1283 if patch:
1275 # index, rev, patch
1284 # index, rev, patch
1276 info = self.isapplied(patch)
1285 info = self.isapplied(patch)
1277 if not info:
1286 if not info:
1278 patch = self.lookup(patch)
1287 patch = self.lookup(patch)
1279 info = self.isapplied(patch)
1288 info = self.isapplied(patch)
1280 if not info:
1289 if not info:
1281 raise util.Abort(_("patch %s is not applied") % patch)
1290 raise util.Abort(_("patch %s is not applied") % patch)
1282
1291
1283 if not self.applied:
1292 if not self.applied:
1284 # Allow qpop -a to work repeatedly,
1293 # Allow qpop -a to work repeatedly,
1285 # but not qpop without an argument
1294 # but not qpop without an argument
1286 self.ui.warn(_("no patches applied\n"))
1295 self.ui.warn(_("no patches applied\n"))
1287 return not all
1296 return not all
1288
1297
1289 if all:
1298 if all:
1290 start = 0
1299 start = 0
1291 elif patch:
1300 elif patch:
1292 start = info[0] + 1
1301 start = info[0] + 1
1293 else:
1302 else:
1294 start = len(self.applied) - 1
1303 start = len(self.applied) - 1
1295
1304
1296 if start >= len(self.applied):
1305 if start >= len(self.applied):
1297 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1306 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1298 return
1307 return
1299
1308
1300 if not update:
1309 if not update:
1301 parents = repo.dirstate.parents()
1310 parents = repo.dirstate.parents()
1302 rr = [x.node for x in self.applied]
1311 rr = [x.node for x in self.applied]
1303 for p in parents:
1312 for p in parents:
1304 if p in rr:
1313 if p in rr:
1305 self.ui.warn(_("qpop: forcing dirstate update\n"))
1314 self.ui.warn(_("qpop: forcing dirstate update\n"))
1306 update = True
1315 update = True
1307 else:
1316 else:
1308 parents = [p.node() for p in repo[None].parents()]
1317 parents = [p.node() for p in repo[None].parents()]
1309 needupdate = False
1318 needupdate = False
1310 for entry in self.applied[start:]:
1319 for entry in self.applied[start:]:
1311 if entry.node in parents:
1320 if entry.node in parents:
1312 needupdate = True
1321 needupdate = True
1313 break
1322 break
1314 update = needupdate
1323 update = needupdate
1315
1324
1316 if not force and update:
1325 tobackup = set()
1317 self.checklocalchanges(repo)
1326 if update:
1327 m, a, r, d = self.checklocalchanges(repo, force=force)
1328 tobackup.update(m + a)
1318
1329
1319 self.applieddirty = True
1330 self.applieddirty = True
1320 end = len(self.applied)
1331 end = len(self.applied)
1321 rev = self.applied[start].node
1332 rev = self.applied[start].node
1322 if update:
1333 if update:
1323 top = self.checktoppatch(repo)[0]
1334 top = self.checktoppatch(repo)[0]
1324
1335
1325 try:
1336 try:
1326 heads = repo.changelog.heads(rev)
1337 heads = repo.changelog.heads(rev)
1327 except error.LookupError:
1338 except error.LookupError:
1328 node = short(rev)
1339 node = short(rev)
1329 raise util.Abort(_('trying to pop unknown node %s') % node)
1340 raise util.Abort(_('trying to pop unknown node %s') % node)
1330
1341
1331 if heads != [self.applied[-1].node]:
1342 if heads != [self.applied[-1].node]:
1332 raise util.Abort(_("popping would remove a revision not "
1343 raise util.Abort(_("popping would remove a revision not "
1333 "managed by this patch queue"))
1344 "managed by this patch queue"))
1334 if not repo[self.applied[-1].node].mutable():
1345 if not repo[self.applied[-1].node].mutable():
1335 raise util.Abort(
1346 raise util.Abort(
1336 _("popping would remove an immutable revision"),
1347 _("popping would remove an immutable revision"),
1337 hint=_('see "hg help phases" for details'))
1348 hint=_('see "hg help phases" for details'))
1338
1349
1339 # we know there are no local changes, so we can make a simplified
1350 # we know there are no local changes, so we can make a simplified
1340 # form of hg.update.
1351 # form of hg.update.
1341 if update:
1352 if update:
1342 qp = self.qparents(repo, rev)
1353 qp = self.qparents(repo, rev)
1343 ctx = repo[qp]
1354 ctx = repo[qp]
1344 m, a, r, d = repo.status(qp, top)[:4]
1355 m, a, r, d = repo.status(qp, top)[:4]
1345 if d:
1356 if d:
1346 raise util.Abort(_("deletions found between repo revs"))
1357 raise util.Abort(_("deletions found between repo revs"))
1358
1359 # backup local changes in --force case
1360 self.backup(repo, set(a + m + r) & tobackup)
1361
1347 for f in a:
1362 for f in a:
1348 try:
1363 try:
1349 util.unlinkpath(repo.wjoin(f))
1364 util.unlinkpath(repo.wjoin(f))
1350 except OSError, e:
1365 except OSError, e:
1351 if e.errno != errno.ENOENT:
1366 if e.errno != errno.ENOENT:
1352 raise
1367 raise
1353 repo.dirstate.drop(f)
1368 repo.dirstate.drop(f)
1354 for f in m + r:
1369 for f in m + r:
1355 fctx = ctx[f]
1370 fctx = ctx[f]
1356 repo.wwrite(f, fctx.data(), fctx.flags())
1371 repo.wwrite(f, fctx.data(), fctx.flags())
1357 repo.dirstate.normal(f)
1372 repo.dirstate.normal(f)
1358 repo.setparents(qp, nullid)
1373 repo.setparents(qp, nullid)
1359 for patch in reversed(self.applied[start:end]):
1374 for patch in reversed(self.applied[start:end]):
1360 self.ui.status(_("popping %s\n") % patch.name)
1375 self.ui.status(_("popping %s\n") % patch.name)
1361 del self.applied[start:end]
1376 del self.applied[start:end]
1362 self.strip(repo, [rev], update=False, backup='strip')
1377 self.strip(repo, [rev], update=False, backup='strip')
1363 if self.applied:
1378 if self.applied:
1364 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1379 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1365 else:
1380 else:
1366 self.ui.write(_("patch queue now empty\n"))
1381 self.ui.write(_("patch queue now empty\n"))
1367 finally:
1382 finally:
1368 wlock.release()
1383 wlock.release()
1369
1384
1370 def diff(self, repo, pats, opts):
1385 def diff(self, repo, pats, opts):
1371 top, patch = self.checktoppatch(repo)
1386 top, patch = self.checktoppatch(repo)
1372 if not top:
1387 if not top:
1373 self.ui.write(_("no patches applied\n"))
1388 self.ui.write(_("no patches applied\n"))
1374 return
1389 return
1375 qp = self.qparents(repo, top)
1390 qp = self.qparents(repo, top)
1376 if opts.get('reverse'):
1391 if opts.get('reverse'):
1377 node1, node2 = None, qp
1392 node1, node2 = None, qp
1378 else:
1393 else:
1379 node1, node2 = qp, None
1394 node1, node2 = qp, None
1380 diffopts = self.diffopts(opts, patch)
1395 diffopts = self.diffopts(opts, patch)
1381 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1396 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1382
1397
1383 def refresh(self, repo, pats=None, **opts):
1398 def refresh(self, repo, pats=None, **opts):
1384 if not self.applied:
1399 if not self.applied:
1385 self.ui.write(_("no patches applied\n"))
1400 self.ui.write(_("no patches applied\n"))
1386 return 1
1401 return 1
1387 msg = opts.get('msg', '').rstrip()
1402 msg = opts.get('msg', '').rstrip()
1388 newuser = opts.get('user')
1403 newuser = opts.get('user')
1389 newdate = opts.get('date')
1404 newdate = opts.get('date')
1390 if newdate:
1405 if newdate:
1391 newdate = '%d %d' % util.parsedate(newdate)
1406 newdate = '%d %d' % util.parsedate(newdate)
1392 wlock = repo.wlock()
1407 wlock = repo.wlock()
1393
1408
1394 try:
1409 try:
1395 self.checktoppatch(repo)
1410 self.checktoppatch(repo)
1396 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1411 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1397 if repo.changelog.heads(top) != [top]:
1412 if repo.changelog.heads(top) != [top]:
1398 raise util.Abort(_("cannot refresh a revision with children"))
1413 raise util.Abort(_("cannot refresh a revision with children"))
1399 if not repo[top].mutable():
1414 if not repo[top].mutable():
1400 raise util.Abort(_("cannot refresh immutable revision"),
1415 raise util.Abort(_("cannot refresh immutable revision"),
1401 hint=_('see "hg help phases" for details'))
1416 hint=_('see "hg help phases" for details'))
1402
1417
1403 inclsubs = self.checksubstate(repo)
1418 inclsubs = self.checksubstate(repo)
1404
1419
1405 cparents = repo.changelog.parents(top)
1420 cparents = repo.changelog.parents(top)
1406 patchparent = self.qparents(repo, top)
1421 patchparent = self.qparents(repo, top)
1407 ph = patchheader(self.join(patchfn), self.plainmode)
1422 ph = patchheader(self.join(patchfn), self.plainmode)
1408 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1423 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1409 if msg:
1424 if msg:
1410 ph.setmessage(msg)
1425 ph.setmessage(msg)
1411 if newuser:
1426 if newuser:
1412 ph.setuser(newuser)
1427 ph.setuser(newuser)
1413 if newdate:
1428 if newdate:
1414 ph.setdate(newdate)
1429 ph.setdate(newdate)
1415 ph.setparent(hex(patchparent))
1430 ph.setparent(hex(patchparent))
1416
1431
1417 # only commit new patch when write is complete
1432 # only commit new patch when write is complete
1418 patchf = self.opener(patchfn, 'w', atomictemp=True)
1433 patchf = self.opener(patchfn, 'w', atomictemp=True)
1419
1434
1420 comments = str(ph)
1435 comments = str(ph)
1421 if comments:
1436 if comments:
1422 patchf.write(comments)
1437 patchf.write(comments)
1423
1438
1424 # update the dirstate in place, strip off the qtip commit
1439 # update the dirstate in place, strip off the qtip commit
1425 # and then commit.
1440 # and then commit.
1426 #
1441 #
1427 # this should really read:
1442 # this should really read:
1428 # mm, dd, aa = repo.status(top, patchparent)[:3]
1443 # mm, dd, aa = repo.status(top, patchparent)[:3]
1429 # but we do it backwards to take advantage of manifest/chlog
1444 # but we do it backwards to take advantage of manifest/chlog
1430 # caching against the next repo.status call
1445 # caching against the next repo.status call
1431 mm, aa, dd = repo.status(patchparent, top)[:3]
1446 mm, aa, dd = repo.status(patchparent, top)[:3]
1432 changes = repo.changelog.read(top)
1447 changes = repo.changelog.read(top)
1433 man = repo.manifest.read(changes[0])
1448 man = repo.manifest.read(changes[0])
1434 aaa = aa[:]
1449 aaa = aa[:]
1435 matchfn = scmutil.match(repo[None], pats, opts)
1450 matchfn = scmutil.match(repo[None], pats, opts)
1436 # in short mode, we only diff the files included in the
1451 # in short mode, we only diff the files included in the
1437 # patch already plus specified files
1452 # patch already plus specified files
1438 if opts.get('short'):
1453 if opts.get('short'):
1439 # if amending a patch, we start with existing
1454 # if amending a patch, we start with existing
1440 # files plus specified files - unfiltered
1455 # files plus specified files - unfiltered
1441 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1456 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1442 # filter with inc/exl options
1457 # filter with inc/exl options
1443 matchfn = scmutil.match(repo[None], opts=opts)
1458 matchfn = scmutil.match(repo[None], opts=opts)
1444 else:
1459 else:
1445 match = scmutil.matchall(repo)
1460 match = scmutil.matchall(repo)
1446 m, a, r, d = repo.status(match=match)[:4]
1461 m, a, r, d = repo.status(match=match)[:4]
1447 mm = set(mm)
1462 mm = set(mm)
1448 aa = set(aa)
1463 aa = set(aa)
1449 dd = set(dd)
1464 dd = set(dd)
1450
1465
1451 # we might end up with files that were added between
1466 # we might end up with files that were added between
1452 # qtip and the dirstate parent, but then changed in the
1467 # qtip and the dirstate parent, but then changed in the
1453 # local dirstate. in this case, we want them to only
1468 # local dirstate. in this case, we want them to only
1454 # show up in the added section
1469 # show up in the added section
1455 for x in m:
1470 for x in m:
1456 if x not in aa:
1471 if x not in aa:
1457 mm.add(x)
1472 mm.add(x)
1458 # we might end up with files added by the local dirstate that
1473 # we might end up with files added by the local dirstate that
1459 # were deleted by the patch. In this case, they should only
1474 # were deleted by the patch. In this case, they should only
1460 # show up in the changed section.
1475 # show up in the changed section.
1461 for x in a:
1476 for x in a:
1462 if x in dd:
1477 if x in dd:
1463 dd.remove(x)
1478 dd.remove(x)
1464 mm.add(x)
1479 mm.add(x)
1465 else:
1480 else:
1466 aa.add(x)
1481 aa.add(x)
1467 # make sure any files deleted in the local dirstate
1482 # make sure any files deleted in the local dirstate
1468 # are not in the add or change column of the patch
1483 # are not in the add or change column of the patch
1469 forget = []
1484 forget = []
1470 for x in d + r:
1485 for x in d + r:
1471 if x in aa:
1486 if x in aa:
1472 aa.remove(x)
1487 aa.remove(x)
1473 forget.append(x)
1488 forget.append(x)
1474 continue
1489 continue
1475 else:
1490 else:
1476 mm.discard(x)
1491 mm.discard(x)
1477 dd.add(x)
1492 dd.add(x)
1478
1493
1479 m = list(mm)
1494 m = list(mm)
1480 r = list(dd)
1495 r = list(dd)
1481 a = list(aa)
1496 a = list(aa)
1482 c = [filter(matchfn, l) for l in (m, a, r)]
1497 c = [filter(matchfn, l) for l in (m, a, r)]
1483 match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
1498 match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
1484 chunks = patchmod.diff(repo, patchparent, match=match,
1499 chunks = patchmod.diff(repo, patchparent, match=match,
1485 changes=c, opts=diffopts)
1500 changes=c, opts=diffopts)
1486 for chunk in chunks:
1501 for chunk in chunks:
1487 patchf.write(chunk)
1502 patchf.write(chunk)
1488
1503
1489 try:
1504 try:
1490 if diffopts.git or diffopts.upgrade:
1505 if diffopts.git or diffopts.upgrade:
1491 copies = {}
1506 copies = {}
1492 for dst in a:
1507 for dst in a:
1493 src = repo.dirstate.copied(dst)
1508 src = repo.dirstate.copied(dst)
1494 # during qfold, the source file for copies may
1509 # during qfold, the source file for copies may
1495 # be removed. Treat this as a simple add.
1510 # be removed. Treat this as a simple add.
1496 if src is not None and src in repo.dirstate:
1511 if src is not None and src in repo.dirstate:
1497 copies.setdefault(src, []).append(dst)
1512 copies.setdefault(src, []).append(dst)
1498 repo.dirstate.add(dst)
1513 repo.dirstate.add(dst)
1499 # remember the copies between patchparent and qtip
1514 # remember the copies between patchparent and qtip
1500 for dst in aaa:
1515 for dst in aaa:
1501 f = repo.file(dst)
1516 f = repo.file(dst)
1502 src = f.renamed(man[dst])
1517 src = f.renamed(man[dst])
1503 if src:
1518 if src:
1504 copies.setdefault(src[0], []).extend(
1519 copies.setdefault(src[0], []).extend(
1505 copies.get(dst, []))
1520 copies.get(dst, []))
1506 if dst in a:
1521 if dst in a:
1507 copies[src[0]].append(dst)
1522 copies[src[0]].append(dst)
1508 # we can't copy a file created by the patch itself
1523 # we can't copy a file created by the patch itself
1509 if dst in copies:
1524 if dst in copies:
1510 del copies[dst]
1525 del copies[dst]
1511 for src, dsts in copies.iteritems():
1526 for src, dsts in copies.iteritems():
1512 for dst in dsts:
1527 for dst in dsts:
1513 repo.dirstate.copy(src, dst)
1528 repo.dirstate.copy(src, dst)
1514 else:
1529 else:
1515 for dst in a:
1530 for dst in a:
1516 repo.dirstate.add(dst)
1531 repo.dirstate.add(dst)
1517 # Drop useless copy information
1532 # Drop useless copy information
1518 for f in list(repo.dirstate.copies()):
1533 for f in list(repo.dirstate.copies()):
1519 repo.dirstate.copy(None, f)
1534 repo.dirstate.copy(None, f)
1520 for f in r:
1535 for f in r:
1521 repo.dirstate.remove(f)
1536 repo.dirstate.remove(f)
1522 # if the patch excludes a modified file, mark that
1537 # if the patch excludes a modified file, mark that
1523 # file with mtime=0 so status can see it.
1538 # file with mtime=0 so status can see it.
1524 mm = []
1539 mm = []
1525 for i in xrange(len(m)-1, -1, -1):
1540 for i in xrange(len(m)-1, -1, -1):
1526 if not matchfn(m[i]):
1541 if not matchfn(m[i]):
1527 mm.append(m[i])
1542 mm.append(m[i])
1528 del m[i]
1543 del m[i]
1529 for f in m:
1544 for f in m:
1530 repo.dirstate.normal(f)
1545 repo.dirstate.normal(f)
1531 for f in mm:
1546 for f in mm:
1532 repo.dirstate.normallookup(f)
1547 repo.dirstate.normallookup(f)
1533 for f in forget:
1548 for f in forget:
1534 repo.dirstate.drop(f)
1549 repo.dirstate.drop(f)
1535
1550
1536 if not msg:
1551 if not msg:
1537 if not ph.message:
1552 if not ph.message:
1538 message = "[mq]: %s\n" % patchfn
1553 message = "[mq]: %s\n" % patchfn
1539 else:
1554 else:
1540 message = "\n".join(ph.message)
1555 message = "\n".join(ph.message)
1541 else:
1556 else:
1542 message = msg
1557 message = msg
1543
1558
1544 user = ph.user or changes[1]
1559 user = ph.user or changes[1]
1545
1560
1546 oldphase = repo[top].phase()
1561 oldphase = repo[top].phase()
1547
1562
1548 # assumes strip can roll itself back if interrupted
1563 # assumes strip can roll itself back if interrupted
1549 repo.setparents(*cparents)
1564 repo.setparents(*cparents)
1550 self.applied.pop()
1565 self.applied.pop()
1551 self.applieddirty = True
1566 self.applieddirty = True
1552 self.strip(repo, [top], update=False,
1567 self.strip(repo, [top], update=False,
1553 backup='strip')
1568 backup='strip')
1554 except:
1569 except:
1555 repo.dirstate.invalidate()
1570 repo.dirstate.invalidate()
1556 raise
1571 raise
1557
1572
1558 try:
1573 try:
1559 # might be nice to attempt to roll back strip after this
1574 # might be nice to attempt to roll back strip after this
1560
1575
1561 # Ensure we create a new changeset in the same phase than
1576 # Ensure we create a new changeset in the same phase than
1562 # the old one.
1577 # the old one.
1563 n = newcommit(repo, oldphase, message, user, ph.date,
1578 n = newcommit(repo, oldphase, message, user, ph.date,
1564 match=match, force=True)
1579 match=match, force=True)
1565 # only write patch after a successful commit
1580 # only write patch after a successful commit
1566 patchf.close()
1581 patchf.close()
1567 self.applied.append(statusentry(n, patchfn))
1582 self.applied.append(statusentry(n, patchfn))
1568 except:
1583 except:
1569 ctx = repo[cparents[0]]
1584 ctx = repo[cparents[0]]
1570 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1585 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1571 self.savedirty()
1586 self.savedirty()
1572 self.ui.warn(_('refresh interrupted while patch was popped! '
1587 self.ui.warn(_('refresh interrupted while patch was popped! '
1573 '(revert --all, qpush to recover)\n'))
1588 '(revert --all, qpush to recover)\n'))
1574 raise
1589 raise
1575 finally:
1590 finally:
1576 wlock.release()
1591 wlock.release()
1577 self.removeundo(repo)
1592 self.removeundo(repo)
1578
1593
1579 def init(self, repo, create=False):
1594 def init(self, repo, create=False):
1580 if not create and os.path.isdir(self.path):
1595 if not create and os.path.isdir(self.path):
1581 raise util.Abort(_("patch queue directory already exists"))
1596 raise util.Abort(_("patch queue directory already exists"))
1582 try:
1597 try:
1583 os.mkdir(self.path)
1598 os.mkdir(self.path)
1584 except OSError, inst:
1599 except OSError, inst:
1585 if inst.errno != errno.EEXIST or not create:
1600 if inst.errno != errno.EEXIST or not create:
1586 raise
1601 raise
1587 if create:
1602 if create:
1588 return self.qrepo(create=True)
1603 return self.qrepo(create=True)
1589
1604
1590 def unapplied(self, repo, patch=None):
1605 def unapplied(self, repo, patch=None):
1591 if patch and patch not in self.series:
1606 if patch and patch not in self.series:
1592 raise util.Abort(_("patch %s is not in series file") % patch)
1607 raise util.Abort(_("patch %s is not in series file") % patch)
1593 if not patch:
1608 if not patch:
1594 start = self.seriesend()
1609 start = self.seriesend()
1595 else:
1610 else:
1596 start = self.series.index(patch) + 1
1611 start = self.series.index(patch) + 1
1597 unapplied = []
1612 unapplied = []
1598 for i in xrange(start, len(self.series)):
1613 for i in xrange(start, len(self.series)):
1599 pushable, reason = self.pushable(i)
1614 pushable, reason = self.pushable(i)
1600 if pushable:
1615 if pushable:
1601 unapplied.append((i, self.series[i]))
1616 unapplied.append((i, self.series[i]))
1602 self.explainpushable(i)
1617 self.explainpushable(i)
1603 return unapplied
1618 return unapplied
1604
1619
1605 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1620 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1606 summary=False):
1621 summary=False):
1607 def displayname(pfx, patchname, state):
1622 def displayname(pfx, patchname, state):
1608 if pfx:
1623 if pfx:
1609 self.ui.write(pfx)
1624 self.ui.write(pfx)
1610 if summary:
1625 if summary:
1611 ph = patchheader(self.join(patchname), self.plainmode)
1626 ph = patchheader(self.join(patchname), self.plainmode)
1612 msg = ph.message and ph.message[0] or ''
1627 msg = ph.message and ph.message[0] or ''
1613 if self.ui.formatted():
1628 if self.ui.formatted():
1614 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1629 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1615 if width > 0:
1630 if width > 0:
1616 msg = util.ellipsis(msg, width)
1631 msg = util.ellipsis(msg, width)
1617 else:
1632 else:
1618 msg = ''
1633 msg = ''
1619 self.ui.write(patchname, label='qseries.' + state)
1634 self.ui.write(patchname, label='qseries.' + state)
1620 self.ui.write(': ')
1635 self.ui.write(': ')
1621 self.ui.write(msg, label='qseries.message.' + state)
1636 self.ui.write(msg, label='qseries.message.' + state)
1622 else:
1637 else:
1623 self.ui.write(patchname, label='qseries.' + state)
1638 self.ui.write(patchname, label='qseries.' + state)
1624 self.ui.write('\n')
1639 self.ui.write('\n')
1625
1640
1626 applied = set([p.name for p in self.applied])
1641 applied = set([p.name for p in self.applied])
1627 if length is None:
1642 if length is None:
1628 length = len(self.series) - start
1643 length = len(self.series) - start
1629 if not missing:
1644 if not missing:
1630 if self.ui.verbose:
1645 if self.ui.verbose:
1631 idxwidth = len(str(start + length - 1))
1646 idxwidth = len(str(start + length - 1))
1632 for i in xrange(start, start + length):
1647 for i in xrange(start, start + length):
1633 patch = self.series[i]
1648 patch = self.series[i]
1634 if patch in applied:
1649 if patch in applied:
1635 char, state = 'A', 'applied'
1650 char, state = 'A', 'applied'
1636 elif self.pushable(i)[0]:
1651 elif self.pushable(i)[0]:
1637 char, state = 'U', 'unapplied'
1652 char, state = 'U', 'unapplied'
1638 else:
1653 else:
1639 char, state = 'G', 'guarded'
1654 char, state = 'G', 'guarded'
1640 pfx = ''
1655 pfx = ''
1641 if self.ui.verbose:
1656 if self.ui.verbose:
1642 pfx = '%*d %s ' % (idxwidth, i, char)
1657 pfx = '%*d %s ' % (idxwidth, i, char)
1643 elif status and status != char:
1658 elif status and status != char:
1644 continue
1659 continue
1645 displayname(pfx, patch, state)
1660 displayname(pfx, patch, state)
1646 else:
1661 else:
1647 msng_list = []
1662 msng_list = []
1648 for root, dirs, files in os.walk(self.path):
1663 for root, dirs, files in os.walk(self.path):
1649 d = root[len(self.path) + 1:]
1664 d = root[len(self.path) + 1:]
1650 for f in files:
1665 for f in files:
1651 fl = os.path.join(d, f)
1666 fl = os.path.join(d, f)
1652 if (fl not in self.series and
1667 if (fl not in self.series and
1653 fl not in (self.statuspath, self.seriespath,
1668 fl not in (self.statuspath, self.seriespath,
1654 self.guardspath)
1669 self.guardspath)
1655 and not fl.startswith('.')):
1670 and not fl.startswith('.')):
1656 msng_list.append(fl)
1671 msng_list.append(fl)
1657 for x in sorted(msng_list):
1672 for x in sorted(msng_list):
1658 pfx = self.ui.verbose and ('D ') or ''
1673 pfx = self.ui.verbose and ('D ') or ''
1659 displayname(pfx, x, 'missing')
1674 displayname(pfx, x, 'missing')
1660
1675
1661 def issaveline(self, l):
1676 def issaveline(self, l):
1662 if l.name == '.hg.patches.save.line':
1677 if l.name == '.hg.patches.save.line':
1663 return True
1678 return True
1664
1679
1665 def qrepo(self, create=False):
1680 def qrepo(self, create=False):
1666 ui = self.ui.copy()
1681 ui = self.ui.copy()
1667 ui.setconfig('paths', 'default', '', overlay=False)
1682 ui.setconfig('paths', 'default', '', overlay=False)
1668 ui.setconfig('paths', 'default-push', '', overlay=False)
1683 ui.setconfig('paths', 'default-push', '', overlay=False)
1669 if create or os.path.isdir(self.join(".hg")):
1684 if create or os.path.isdir(self.join(".hg")):
1670 return hg.repository(ui, path=self.path, create=create)
1685 return hg.repository(ui, path=self.path, create=create)
1671
1686
1672 def restore(self, repo, rev, delete=None, qupdate=None):
1687 def restore(self, repo, rev, delete=None, qupdate=None):
1673 desc = repo[rev].description().strip()
1688 desc = repo[rev].description().strip()
1674 lines = desc.splitlines()
1689 lines = desc.splitlines()
1675 i = 0
1690 i = 0
1676 datastart = None
1691 datastart = None
1677 series = []
1692 series = []
1678 applied = []
1693 applied = []
1679 qpp = None
1694 qpp = None
1680 for i, line in enumerate(lines):
1695 for i, line in enumerate(lines):
1681 if line == 'Patch Data:':
1696 if line == 'Patch Data:':
1682 datastart = i + 1
1697 datastart = i + 1
1683 elif line.startswith('Dirstate:'):
1698 elif line.startswith('Dirstate:'):
1684 l = line.rstrip()
1699 l = line.rstrip()
1685 l = l[10:].split(' ')
1700 l = l[10:].split(' ')
1686 qpp = [bin(x) for x in l]
1701 qpp = [bin(x) for x in l]
1687 elif datastart is not None:
1702 elif datastart is not None:
1688 l = line.rstrip()
1703 l = line.rstrip()
1689 n, name = l.split(':', 1)
1704 n, name = l.split(':', 1)
1690 if n:
1705 if n:
1691 applied.append(statusentry(bin(n), name))
1706 applied.append(statusentry(bin(n), name))
1692 else:
1707 else:
1693 series.append(l)
1708 series.append(l)
1694 if datastart is None:
1709 if datastart is None:
1695 self.ui.warn(_("No saved patch data found\n"))
1710 self.ui.warn(_("No saved patch data found\n"))
1696 return 1
1711 return 1
1697 self.ui.warn(_("restoring status: %s\n") % lines[0])
1712 self.ui.warn(_("restoring status: %s\n") % lines[0])
1698 self.fullseries = series
1713 self.fullseries = series
1699 self.applied = applied
1714 self.applied = applied
1700 self.parseseries()
1715 self.parseseries()
1701 self.seriesdirty = True
1716 self.seriesdirty = True
1702 self.applieddirty = True
1717 self.applieddirty = True
1703 heads = repo.changelog.heads()
1718 heads = repo.changelog.heads()
1704 if delete:
1719 if delete:
1705 if rev not in heads:
1720 if rev not in heads:
1706 self.ui.warn(_("save entry has children, leaving it alone\n"))
1721 self.ui.warn(_("save entry has children, leaving it alone\n"))
1707 else:
1722 else:
1708 self.ui.warn(_("removing save entry %s\n") % short(rev))
1723 self.ui.warn(_("removing save entry %s\n") % short(rev))
1709 pp = repo.dirstate.parents()
1724 pp = repo.dirstate.parents()
1710 if rev in pp:
1725 if rev in pp:
1711 update = True
1726 update = True
1712 else:
1727 else:
1713 update = False
1728 update = False
1714 self.strip(repo, [rev], update=update, backup='strip')
1729 self.strip(repo, [rev], update=update, backup='strip')
1715 if qpp:
1730 if qpp:
1716 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1731 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1717 (short(qpp[0]), short(qpp[1])))
1732 (short(qpp[0]), short(qpp[1])))
1718 if qupdate:
1733 if qupdate:
1719 self.ui.status(_("updating queue directory\n"))
1734 self.ui.status(_("updating queue directory\n"))
1720 r = self.qrepo()
1735 r = self.qrepo()
1721 if not r:
1736 if not r:
1722 self.ui.warn(_("Unable to load queue repository\n"))
1737 self.ui.warn(_("Unable to load queue repository\n"))
1723 return 1
1738 return 1
1724 hg.clean(r, qpp[0])
1739 hg.clean(r, qpp[0])
1725
1740
1726 def save(self, repo, msg=None):
1741 def save(self, repo, msg=None):
1727 if not self.applied:
1742 if not self.applied:
1728 self.ui.warn(_("save: no patches applied, exiting\n"))
1743 self.ui.warn(_("save: no patches applied, exiting\n"))
1729 return 1
1744 return 1
1730 if self.issaveline(self.applied[-1]):
1745 if self.issaveline(self.applied[-1]):
1731 self.ui.warn(_("status is already saved\n"))
1746 self.ui.warn(_("status is already saved\n"))
1732 return 1
1747 return 1
1733
1748
1734 if not msg:
1749 if not msg:
1735 msg = _("hg patches saved state")
1750 msg = _("hg patches saved state")
1736 else:
1751 else:
1737 msg = "hg patches: " + msg.rstrip('\r\n')
1752 msg = "hg patches: " + msg.rstrip('\r\n')
1738 r = self.qrepo()
1753 r = self.qrepo()
1739 if r:
1754 if r:
1740 pp = r.dirstate.parents()
1755 pp = r.dirstate.parents()
1741 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1756 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1742 msg += "\n\nPatch Data:\n"
1757 msg += "\n\nPatch Data:\n"
1743 msg += ''.join('%s\n' % x for x in self.applied)
1758 msg += ''.join('%s\n' % x for x in self.applied)
1744 msg += ''.join(':%s\n' % x for x in self.fullseries)
1759 msg += ''.join(':%s\n' % x for x in self.fullseries)
1745 n = repo.commit(msg, force=True)
1760 n = repo.commit(msg, force=True)
1746 if not n:
1761 if not n:
1747 self.ui.warn(_("repo commit failed\n"))
1762 self.ui.warn(_("repo commit failed\n"))
1748 return 1
1763 return 1
1749 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1764 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1750 self.applieddirty = True
1765 self.applieddirty = True
1751 self.removeundo(repo)
1766 self.removeundo(repo)
1752
1767
1753 def fullseriesend(self):
1768 def fullseriesend(self):
1754 if self.applied:
1769 if self.applied:
1755 p = self.applied[-1].name
1770 p = self.applied[-1].name
1756 end = self.findseries(p)
1771 end = self.findseries(p)
1757 if end is None:
1772 if end is None:
1758 return len(self.fullseries)
1773 return len(self.fullseries)
1759 return end + 1
1774 return end + 1
1760 return 0
1775 return 0
1761
1776
1762 def seriesend(self, all_patches=False):
1777 def seriesend(self, all_patches=False):
1763 """If all_patches is False, return the index of the next pushable patch
1778 """If all_patches is False, return the index of the next pushable patch
1764 in the series, or the series length. If all_patches is True, return the
1779 in the series, or the series length. If all_patches is True, return the
1765 index of the first patch past the last applied one.
1780 index of the first patch past the last applied one.
1766 """
1781 """
1767 end = 0
1782 end = 0
1768 def next(start):
1783 def next(start):
1769 if all_patches or start >= len(self.series):
1784 if all_patches or start >= len(self.series):
1770 return start
1785 return start
1771 for i in xrange(start, len(self.series)):
1786 for i in xrange(start, len(self.series)):
1772 p, reason = self.pushable(i)
1787 p, reason = self.pushable(i)
1773 if p:
1788 if p:
1774 return i
1789 return i
1775 self.explainpushable(i)
1790 self.explainpushable(i)
1776 return len(self.series)
1791 return len(self.series)
1777 if self.applied:
1792 if self.applied:
1778 p = self.applied[-1].name
1793 p = self.applied[-1].name
1779 try:
1794 try:
1780 end = self.series.index(p)
1795 end = self.series.index(p)
1781 except ValueError:
1796 except ValueError:
1782 return 0
1797 return 0
1783 return next(end + 1)
1798 return next(end + 1)
1784 return next(end)
1799 return next(end)
1785
1800
1786 def appliedname(self, index):
1801 def appliedname(self, index):
1787 pname = self.applied[index].name
1802 pname = self.applied[index].name
1788 if not self.ui.verbose:
1803 if not self.ui.verbose:
1789 p = pname
1804 p = pname
1790 else:
1805 else:
1791 p = str(self.series.index(pname)) + " " + pname
1806 p = str(self.series.index(pname)) + " " + pname
1792 return p
1807 return p
1793
1808
1794 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1809 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1795 force=None, git=False):
1810 force=None, git=False):
1796 def checkseries(patchname):
1811 def checkseries(patchname):
1797 if patchname in self.series:
1812 if patchname in self.series:
1798 raise util.Abort(_('patch %s is already in the series file')
1813 raise util.Abort(_('patch %s is already in the series file')
1799 % patchname)
1814 % patchname)
1800
1815
1801 if rev:
1816 if rev:
1802 if files:
1817 if files:
1803 raise util.Abort(_('option "-r" not valid when importing '
1818 raise util.Abort(_('option "-r" not valid when importing '
1804 'files'))
1819 'files'))
1805 rev = scmutil.revrange(repo, rev)
1820 rev = scmutil.revrange(repo, rev)
1806 rev.sort(reverse=True)
1821 rev.sort(reverse=True)
1807 if (len(files) > 1 or len(rev) > 1) and patchname:
1822 if (len(files) > 1 or len(rev) > 1) and patchname:
1808 raise util.Abort(_('option "-n" not valid when importing multiple '
1823 raise util.Abort(_('option "-n" not valid when importing multiple '
1809 'patches'))
1824 'patches'))
1810 imported = []
1825 imported = []
1811 if rev:
1826 if rev:
1812 # If mq patches are applied, we can only import revisions
1827 # If mq patches are applied, we can only import revisions
1813 # that form a linear path to qbase.
1828 # that form a linear path to qbase.
1814 # Otherwise, they should form a linear path to a head.
1829 # Otherwise, they should form a linear path to a head.
1815 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1830 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1816 if len(heads) > 1:
1831 if len(heads) > 1:
1817 raise util.Abort(_('revision %d is the root of more than one '
1832 raise util.Abort(_('revision %d is the root of more than one '
1818 'branch') % rev[-1])
1833 'branch') % rev[-1])
1819 if self.applied:
1834 if self.applied:
1820 base = repo.changelog.node(rev[0])
1835 base = repo.changelog.node(rev[0])
1821 if base in [n.node for n in self.applied]:
1836 if base in [n.node for n in self.applied]:
1822 raise util.Abort(_('revision %d is already managed')
1837 raise util.Abort(_('revision %d is already managed')
1823 % rev[0])
1838 % rev[0])
1824 if heads != [self.applied[-1].node]:
1839 if heads != [self.applied[-1].node]:
1825 raise util.Abort(_('revision %d is not the parent of '
1840 raise util.Abort(_('revision %d is not the parent of '
1826 'the queue') % rev[0])
1841 'the queue') % rev[0])
1827 base = repo.changelog.rev(self.applied[0].node)
1842 base = repo.changelog.rev(self.applied[0].node)
1828 lastparent = repo.changelog.parentrevs(base)[0]
1843 lastparent = repo.changelog.parentrevs(base)[0]
1829 else:
1844 else:
1830 if heads != [repo.changelog.node(rev[0])]:
1845 if heads != [repo.changelog.node(rev[0])]:
1831 raise util.Abort(_('revision %d has unmanaged children')
1846 raise util.Abort(_('revision %d has unmanaged children')
1832 % rev[0])
1847 % rev[0])
1833 lastparent = None
1848 lastparent = None
1834
1849
1835 diffopts = self.diffopts({'git': git})
1850 diffopts = self.diffopts({'git': git})
1836 for r in rev:
1851 for r in rev:
1837 if not repo[r].mutable():
1852 if not repo[r].mutable():
1838 raise util.Abort(_('revision %d is not mutable') % r,
1853 raise util.Abort(_('revision %d is not mutable') % r,
1839 hint=_('see "hg help phases" for details'))
1854 hint=_('see "hg help phases" for details'))
1840 p1, p2 = repo.changelog.parentrevs(r)
1855 p1, p2 = repo.changelog.parentrevs(r)
1841 n = repo.changelog.node(r)
1856 n = repo.changelog.node(r)
1842 if p2 != nullrev:
1857 if p2 != nullrev:
1843 raise util.Abort(_('cannot import merge revision %d') % r)
1858 raise util.Abort(_('cannot import merge revision %d') % r)
1844 if lastparent and lastparent != r:
1859 if lastparent and lastparent != r:
1845 raise util.Abort(_('revision %d is not the parent of %d')
1860 raise util.Abort(_('revision %d is not the parent of %d')
1846 % (r, lastparent))
1861 % (r, lastparent))
1847 lastparent = p1
1862 lastparent = p1
1848
1863
1849 if not patchname:
1864 if not patchname:
1850 patchname = normname('%d.diff' % r)
1865 patchname = normname('%d.diff' % r)
1851 checkseries(patchname)
1866 checkseries(patchname)
1852 self.checkpatchname(patchname, force)
1867 self.checkpatchname(patchname, force)
1853 self.fullseries.insert(0, patchname)
1868 self.fullseries.insert(0, patchname)
1854
1869
1855 patchf = self.opener(patchname, "w")
1870 patchf = self.opener(patchname, "w")
1856 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1871 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1857 patchf.close()
1872 patchf.close()
1858
1873
1859 se = statusentry(n, patchname)
1874 se = statusentry(n, patchname)
1860 self.applied.insert(0, se)
1875 self.applied.insert(0, se)
1861
1876
1862 self.added.append(patchname)
1877 self.added.append(patchname)
1863 imported.append(patchname)
1878 imported.append(patchname)
1864 patchname = None
1879 patchname = None
1865 if rev and repo.ui.configbool('mq', 'secret', False):
1880 if rev and repo.ui.configbool('mq', 'secret', False):
1866 # if we added anything with --rev, we must move the secret root
1881 # if we added anything with --rev, we must move the secret root
1867 phases.retractboundary(repo, phases.secret, [n])
1882 phases.retractboundary(repo, phases.secret, [n])
1868 self.parseseries()
1883 self.parseseries()
1869 self.applieddirty = True
1884 self.applieddirty = True
1870 self.seriesdirty = True
1885 self.seriesdirty = True
1871
1886
1872 for i, filename in enumerate(files):
1887 for i, filename in enumerate(files):
1873 if existing:
1888 if existing:
1874 if filename == '-':
1889 if filename == '-':
1875 raise util.Abort(_('-e is incompatible with import from -'))
1890 raise util.Abort(_('-e is incompatible with import from -'))
1876 filename = normname(filename)
1891 filename = normname(filename)
1877 self.checkreservedname(filename)
1892 self.checkreservedname(filename)
1878 originpath = self.join(filename)
1893 originpath = self.join(filename)
1879 if not os.path.isfile(originpath):
1894 if not os.path.isfile(originpath):
1880 raise util.Abort(_("patch %s does not exist") % filename)
1895 raise util.Abort(_("patch %s does not exist") % filename)
1881
1896
1882 if patchname:
1897 if patchname:
1883 self.checkpatchname(patchname, force)
1898 self.checkpatchname(patchname, force)
1884
1899
1885 self.ui.write(_('renaming %s to %s\n')
1900 self.ui.write(_('renaming %s to %s\n')
1886 % (filename, patchname))
1901 % (filename, patchname))
1887 util.rename(originpath, self.join(patchname))
1902 util.rename(originpath, self.join(patchname))
1888 else:
1903 else:
1889 patchname = filename
1904 patchname = filename
1890
1905
1891 else:
1906 else:
1892 if filename == '-' and not patchname:
1907 if filename == '-' and not patchname:
1893 raise util.Abort(_('need --name to import a patch from -'))
1908 raise util.Abort(_('need --name to import a patch from -'))
1894 elif not patchname:
1909 elif not patchname:
1895 patchname = normname(os.path.basename(filename.rstrip('/')))
1910 patchname = normname(os.path.basename(filename.rstrip('/')))
1896 self.checkpatchname(patchname, force)
1911 self.checkpatchname(patchname, force)
1897 try:
1912 try:
1898 if filename == '-':
1913 if filename == '-':
1899 text = self.ui.fin.read()
1914 text = self.ui.fin.read()
1900 else:
1915 else:
1901 fp = url.open(self.ui, filename)
1916 fp = url.open(self.ui, filename)
1902 text = fp.read()
1917 text = fp.read()
1903 fp.close()
1918 fp.close()
1904 except (OSError, IOError):
1919 except (OSError, IOError):
1905 raise util.Abort(_("unable to read file %s") % filename)
1920 raise util.Abort(_("unable to read file %s") % filename)
1906 patchf = self.opener(patchname, "w")
1921 patchf = self.opener(patchname, "w")
1907 patchf.write(text)
1922 patchf.write(text)
1908 patchf.close()
1923 patchf.close()
1909 if not force:
1924 if not force:
1910 checkseries(patchname)
1925 checkseries(patchname)
1911 if patchname not in self.series:
1926 if patchname not in self.series:
1912 index = self.fullseriesend() + i
1927 index = self.fullseriesend() + i
1913 self.fullseries[index:index] = [patchname]
1928 self.fullseries[index:index] = [patchname]
1914 self.parseseries()
1929 self.parseseries()
1915 self.seriesdirty = True
1930 self.seriesdirty = True
1916 self.ui.warn(_("adding %s to series file\n") % patchname)
1931 self.ui.warn(_("adding %s to series file\n") % patchname)
1917 self.added.append(patchname)
1932 self.added.append(patchname)
1918 imported.append(patchname)
1933 imported.append(patchname)
1919 patchname = None
1934 patchname = None
1920
1935
1921 self.removeundo(repo)
1936 self.removeundo(repo)
1922 return imported
1937 return imported
1923
1938
1924 @command("qdelete|qremove|qrm",
1939 @command("qdelete|qremove|qrm",
1925 [('k', 'keep', None, _('keep patch file')),
1940 [('k', 'keep', None, _('keep patch file')),
1926 ('r', 'rev', [],
1941 ('r', 'rev', [],
1927 _('stop managing a revision (DEPRECATED)'), _('REV'))],
1942 _('stop managing a revision (DEPRECATED)'), _('REV'))],
1928 _('hg qdelete [-k] [PATCH]...'))
1943 _('hg qdelete [-k] [PATCH]...'))
1929 def delete(ui, repo, *patches, **opts):
1944 def delete(ui, repo, *patches, **opts):
1930 """remove patches from queue
1945 """remove patches from queue
1931
1946
1932 The patches must not be applied, and at least one patch is required. Exact
1947 The patches must not be applied, and at least one patch is required. Exact
1933 patch identifiers must be given. With -k/--keep, the patch files are
1948 patch identifiers must be given. With -k/--keep, the patch files are
1934 preserved in the patch directory.
1949 preserved in the patch directory.
1935
1950
1936 To stop managing a patch and move it into permanent history,
1951 To stop managing a patch and move it into permanent history,
1937 use the :hg:`qfinish` command."""
1952 use the :hg:`qfinish` command."""
1938 q = repo.mq
1953 q = repo.mq
1939 q.delete(repo, patches, opts)
1954 q.delete(repo, patches, opts)
1940 q.savedirty()
1955 q.savedirty()
1941 return 0
1956 return 0
1942
1957
1943 @command("qapplied",
1958 @command("qapplied",
1944 [('1', 'last', None, _('show only the preceding applied patch'))
1959 [('1', 'last', None, _('show only the preceding applied patch'))
1945 ] + seriesopts,
1960 ] + seriesopts,
1946 _('hg qapplied [-1] [-s] [PATCH]'))
1961 _('hg qapplied [-1] [-s] [PATCH]'))
1947 def applied(ui, repo, patch=None, **opts):
1962 def applied(ui, repo, patch=None, **opts):
1948 """print the patches already applied
1963 """print the patches already applied
1949
1964
1950 Returns 0 on success."""
1965 Returns 0 on success."""
1951
1966
1952 q = repo.mq
1967 q = repo.mq
1953
1968
1954 if patch:
1969 if patch:
1955 if patch not in q.series:
1970 if patch not in q.series:
1956 raise util.Abort(_("patch %s is not in series file") % patch)
1971 raise util.Abort(_("patch %s is not in series file") % patch)
1957 end = q.series.index(patch) + 1
1972 end = q.series.index(patch) + 1
1958 else:
1973 else:
1959 end = q.seriesend(True)
1974 end = q.seriesend(True)
1960
1975
1961 if opts.get('last') and not end:
1976 if opts.get('last') and not end:
1962 ui.write(_("no patches applied\n"))
1977 ui.write(_("no patches applied\n"))
1963 return 1
1978 return 1
1964 elif opts.get('last') and end == 1:
1979 elif opts.get('last') and end == 1:
1965 ui.write(_("only one patch applied\n"))
1980 ui.write(_("only one patch applied\n"))
1966 return 1
1981 return 1
1967 elif opts.get('last'):
1982 elif opts.get('last'):
1968 start = end - 2
1983 start = end - 2
1969 end = 1
1984 end = 1
1970 else:
1985 else:
1971 start = 0
1986 start = 0
1972
1987
1973 q.qseries(repo, length=end, start=start, status='A',
1988 q.qseries(repo, length=end, start=start, status='A',
1974 summary=opts.get('summary'))
1989 summary=opts.get('summary'))
1975
1990
1976
1991
1977 @command("qunapplied",
1992 @command("qunapplied",
1978 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
1993 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
1979 _('hg qunapplied [-1] [-s] [PATCH]'))
1994 _('hg qunapplied [-1] [-s] [PATCH]'))
1980 def unapplied(ui, repo, patch=None, **opts):
1995 def unapplied(ui, repo, patch=None, **opts):
1981 """print the patches not yet applied
1996 """print the patches not yet applied
1982
1997
1983 Returns 0 on success."""
1998 Returns 0 on success."""
1984
1999
1985 q = repo.mq
2000 q = repo.mq
1986 if patch:
2001 if patch:
1987 if patch not in q.series:
2002 if patch not in q.series:
1988 raise util.Abort(_("patch %s is not in series file") % patch)
2003 raise util.Abort(_("patch %s is not in series file") % patch)
1989 start = q.series.index(patch) + 1
2004 start = q.series.index(patch) + 1
1990 else:
2005 else:
1991 start = q.seriesend(True)
2006 start = q.seriesend(True)
1992
2007
1993 if start == len(q.series) and opts.get('first'):
2008 if start == len(q.series) and opts.get('first'):
1994 ui.write(_("all patches applied\n"))
2009 ui.write(_("all patches applied\n"))
1995 return 1
2010 return 1
1996
2011
1997 length = opts.get('first') and 1 or None
2012 length = opts.get('first') and 1 or None
1998 q.qseries(repo, start=start, length=length, status='U',
2013 q.qseries(repo, start=start, length=length, status='U',
1999 summary=opts.get('summary'))
2014 summary=opts.get('summary'))
2000
2015
2001 @command("qimport",
2016 @command("qimport",
2002 [('e', 'existing', None, _('import file in patch directory')),
2017 [('e', 'existing', None, _('import file in patch directory')),
2003 ('n', 'name', '',
2018 ('n', 'name', '',
2004 _('name of patch file'), _('NAME')),
2019 _('name of patch file'), _('NAME')),
2005 ('f', 'force', None, _('overwrite existing files')),
2020 ('f', 'force', None, _('overwrite existing files')),
2006 ('r', 'rev', [],
2021 ('r', 'rev', [],
2007 _('place existing revisions under mq control'), _('REV')),
2022 _('place existing revisions under mq control'), _('REV')),
2008 ('g', 'git', None, _('use git extended diff format')),
2023 ('g', 'git', None, _('use git extended diff format')),
2009 ('P', 'push', None, _('qpush after importing'))],
2024 ('P', 'push', None, _('qpush after importing'))],
2010 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...'))
2025 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...'))
2011 def qimport(ui, repo, *filename, **opts):
2026 def qimport(ui, repo, *filename, **opts):
2012 """import a patch or existing changeset
2027 """import a patch or existing changeset
2013
2028
2014 The patch is inserted into the series after the last applied
2029 The patch is inserted into the series after the last applied
2015 patch. If no patches have been applied, qimport prepends the patch
2030 patch. If no patches have been applied, qimport prepends the patch
2016 to the series.
2031 to the series.
2017
2032
2018 The patch will have the same name as its source file unless you
2033 The patch will have the same name as its source file unless you
2019 give it a new one with -n/--name.
2034 give it a new one with -n/--name.
2020
2035
2021 You can register an existing patch inside the patch directory with
2036 You can register an existing patch inside the patch directory with
2022 the -e/--existing flag.
2037 the -e/--existing flag.
2023
2038
2024 With -f/--force, an existing patch of the same name will be
2039 With -f/--force, an existing patch of the same name will be
2025 overwritten.
2040 overwritten.
2026
2041
2027 An existing changeset may be placed under mq control with -r/--rev
2042 An existing changeset may be placed under mq control with -r/--rev
2028 (e.g. qimport --rev tip -n patch will place tip under mq control).
2043 (e.g. qimport --rev tip -n patch will place tip under mq control).
2029 With -g/--git, patches imported with --rev will use the git diff
2044 With -g/--git, patches imported with --rev will use the git diff
2030 format. See the diffs help topic for information on why this is
2045 format. See the diffs help topic for information on why this is
2031 important for preserving rename/copy information and permission
2046 important for preserving rename/copy information and permission
2032 changes. Use :hg:`qfinish` to remove changesets from mq control.
2047 changes. Use :hg:`qfinish` to remove changesets from mq control.
2033
2048
2034 To import a patch from standard input, pass - as the patch file.
2049 To import a patch from standard input, pass - as the patch file.
2035 When importing from standard input, a patch name must be specified
2050 When importing from standard input, a patch name must be specified
2036 using the --name flag.
2051 using the --name flag.
2037
2052
2038 To import an existing patch while renaming it::
2053 To import an existing patch while renaming it::
2039
2054
2040 hg qimport -e existing-patch -n new-name
2055 hg qimport -e existing-patch -n new-name
2041
2056
2042 Returns 0 if import succeeded.
2057 Returns 0 if import succeeded.
2043 """
2058 """
2044 lock = repo.lock() # cause this may move phase
2059 lock = repo.lock() # cause this may move phase
2045 try:
2060 try:
2046 q = repo.mq
2061 q = repo.mq
2047 try:
2062 try:
2048 imported = q.qimport(
2063 imported = q.qimport(
2049 repo, filename, patchname=opts.get('name'),
2064 repo, filename, patchname=opts.get('name'),
2050 existing=opts.get('existing'), force=opts.get('force'),
2065 existing=opts.get('existing'), force=opts.get('force'),
2051 rev=opts.get('rev'), git=opts.get('git'))
2066 rev=opts.get('rev'), git=opts.get('git'))
2052 finally:
2067 finally:
2053 q.savedirty()
2068 q.savedirty()
2054
2069
2055
2070
2056 if imported and opts.get('push') and not opts.get('rev'):
2071 if imported and opts.get('push') and not opts.get('rev'):
2057 return q.push(repo, imported[-1])
2072 return q.push(repo, imported[-1])
2058 finally:
2073 finally:
2059 lock.release()
2074 lock.release()
2060 return 0
2075 return 0
2061
2076
2062 def qinit(ui, repo, create):
2077 def qinit(ui, repo, create):
2063 """initialize a new queue repository
2078 """initialize a new queue repository
2064
2079
2065 This command also creates a series file for ordering patches, and
2080 This command also creates a series file for ordering patches, and
2066 an mq-specific .hgignore file in the queue repository, to exclude
2081 an mq-specific .hgignore file in the queue repository, to exclude
2067 the status and guards files (these contain mostly transient state).
2082 the status and guards files (these contain mostly transient state).
2068
2083
2069 Returns 0 if initialization succeeded."""
2084 Returns 0 if initialization succeeded."""
2070 q = repo.mq
2085 q = repo.mq
2071 r = q.init(repo, create)
2086 r = q.init(repo, create)
2072 q.savedirty()
2087 q.savedirty()
2073 if r:
2088 if r:
2074 if not os.path.exists(r.wjoin('.hgignore')):
2089 if not os.path.exists(r.wjoin('.hgignore')):
2075 fp = r.wopener('.hgignore', 'w')
2090 fp = r.wopener('.hgignore', 'w')
2076 fp.write('^\\.hg\n')
2091 fp.write('^\\.hg\n')
2077 fp.write('^\\.mq\n')
2092 fp.write('^\\.mq\n')
2078 fp.write('syntax: glob\n')
2093 fp.write('syntax: glob\n')
2079 fp.write('status\n')
2094 fp.write('status\n')
2080 fp.write('guards\n')
2095 fp.write('guards\n')
2081 fp.close()
2096 fp.close()
2082 if not os.path.exists(r.wjoin('series')):
2097 if not os.path.exists(r.wjoin('series')):
2083 r.wopener('series', 'w').close()
2098 r.wopener('series', 'w').close()
2084 r[None].add(['.hgignore', 'series'])
2099 r[None].add(['.hgignore', 'series'])
2085 commands.add(ui, r)
2100 commands.add(ui, r)
2086 return 0
2101 return 0
2087
2102
2088 @command("^qinit",
2103 @command("^qinit",
2089 [('c', 'create-repo', None, _('create queue repository'))],
2104 [('c', 'create-repo', None, _('create queue repository'))],
2090 _('hg qinit [-c]'))
2105 _('hg qinit [-c]'))
2091 def init(ui, repo, **opts):
2106 def init(ui, repo, **opts):
2092 """init a new queue repository (DEPRECATED)
2107 """init a new queue repository (DEPRECATED)
2093
2108
2094 The queue repository is unversioned by default. If
2109 The queue repository is unversioned by default. If
2095 -c/--create-repo is specified, qinit will create a separate nested
2110 -c/--create-repo is specified, qinit will create a separate nested
2096 repository for patches (qinit -c may also be run later to convert
2111 repository for patches (qinit -c may also be run later to convert
2097 an unversioned patch repository into a versioned one). You can use
2112 an unversioned patch repository into a versioned one). You can use
2098 qcommit to commit changes to this queue repository.
2113 qcommit to commit changes to this queue repository.
2099
2114
2100 This command is deprecated. Without -c, it's implied by other relevant
2115 This command is deprecated. Without -c, it's implied by other relevant
2101 commands. With -c, use :hg:`init --mq` instead."""
2116 commands. With -c, use :hg:`init --mq` instead."""
2102 return qinit(ui, repo, create=opts.get('create_repo'))
2117 return qinit(ui, repo, create=opts.get('create_repo'))
2103
2118
2104 @command("qclone",
2119 @command("qclone",
2105 [('', 'pull', None, _('use pull protocol to copy metadata')),
2120 [('', 'pull', None, _('use pull protocol to copy metadata')),
2106 ('U', 'noupdate', None, _('do not update the new working directories')),
2121 ('U', 'noupdate', None, _('do not update the new working directories')),
2107 ('', 'uncompressed', None,
2122 ('', 'uncompressed', None,
2108 _('use uncompressed transfer (fast over LAN)')),
2123 _('use uncompressed transfer (fast over LAN)')),
2109 ('p', 'patches', '',
2124 ('p', 'patches', '',
2110 _('location of source patch repository'), _('REPO')),
2125 _('location of source patch repository'), _('REPO')),
2111 ] + commands.remoteopts,
2126 ] + commands.remoteopts,
2112 _('hg qclone [OPTION]... SOURCE [DEST]'))
2127 _('hg qclone [OPTION]... SOURCE [DEST]'))
2113 def clone(ui, source, dest=None, **opts):
2128 def clone(ui, source, dest=None, **opts):
2114 '''clone main and patch repository at same time
2129 '''clone main and patch repository at same time
2115
2130
2116 If source is local, destination will have no patches applied. If
2131 If source is local, destination will have no patches applied. If
2117 source is remote, this command can not check if patches are
2132 source is remote, this command can not check if patches are
2118 applied in source, so cannot guarantee that patches are not
2133 applied in source, so cannot guarantee that patches are not
2119 applied in destination. If you clone remote repository, be sure
2134 applied in destination. If you clone remote repository, be sure
2120 before that it has no patches applied.
2135 before that it has no patches applied.
2121
2136
2122 Source patch repository is looked for in <src>/.hg/patches by
2137 Source patch repository is looked for in <src>/.hg/patches by
2123 default. Use -p <url> to change.
2138 default. Use -p <url> to change.
2124
2139
2125 The patch directory must be a nested Mercurial repository, as
2140 The patch directory must be a nested Mercurial repository, as
2126 would be created by :hg:`init --mq`.
2141 would be created by :hg:`init --mq`.
2127
2142
2128 Return 0 on success.
2143 Return 0 on success.
2129 '''
2144 '''
2130 def patchdir(repo):
2145 def patchdir(repo):
2131 """compute a patch repo url from a repo object"""
2146 """compute a patch repo url from a repo object"""
2132 url = repo.url()
2147 url = repo.url()
2133 if url.endswith('/'):
2148 if url.endswith('/'):
2134 url = url[:-1]
2149 url = url[:-1]
2135 return url + '/.hg/patches'
2150 return url + '/.hg/patches'
2136
2151
2137 # main repo (destination and sources)
2152 # main repo (destination and sources)
2138 if dest is None:
2153 if dest is None:
2139 dest = hg.defaultdest(source)
2154 dest = hg.defaultdest(source)
2140 sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source))
2155 sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source))
2141
2156
2142 # patches repo (source only)
2157 # patches repo (source only)
2143 if opts.get('patches'):
2158 if opts.get('patches'):
2144 patchespath = ui.expandpath(opts.get('patches'))
2159 patchespath = ui.expandpath(opts.get('patches'))
2145 else:
2160 else:
2146 patchespath = patchdir(sr)
2161 patchespath = patchdir(sr)
2147 try:
2162 try:
2148 hg.repository(ui, patchespath)
2163 hg.repository(ui, patchespath)
2149 except error.RepoError:
2164 except error.RepoError:
2150 raise util.Abort(_('versioned patch repository not found'
2165 raise util.Abort(_('versioned patch repository not found'
2151 ' (see init --mq)'))
2166 ' (see init --mq)'))
2152 qbase, destrev = None, None
2167 qbase, destrev = None, None
2153 if sr.local():
2168 if sr.local():
2154 if sr.mq.applied and sr[qbase].phase() != phases.secret:
2169 if sr.mq.applied and sr[qbase].phase() != phases.secret:
2155 qbase = sr.mq.applied[0].node
2170 qbase = sr.mq.applied[0].node
2156 if not hg.islocal(dest):
2171 if not hg.islocal(dest):
2157 heads = set(sr.heads())
2172 heads = set(sr.heads())
2158 destrev = list(heads.difference(sr.heads(qbase)))
2173 destrev = list(heads.difference(sr.heads(qbase)))
2159 destrev.append(sr.changelog.parents(qbase)[0])
2174 destrev.append(sr.changelog.parents(qbase)[0])
2160 elif sr.capable('lookup'):
2175 elif sr.capable('lookup'):
2161 try:
2176 try:
2162 qbase = sr.lookup('qbase')
2177 qbase = sr.lookup('qbase')
2163 except error.RepoError:
2178 except error.RepoError:
2164 pass
2179 pass
2165
2180
2166 ui.note(_('cloning main repository\n'))
2181 ui.note(_('cloning main repository\n'))
2167 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2182 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2168 pull=opts.get('pull'),
2183 pull=opts.get('pull'),
2169 rev=destrev,
2184 rev=destrev,
2170 update=False,
2185 update=False,
2171 stream=opts.get('uncompressed'))
2186 stream=opts.get('uncompressed'))
2172
2187
2173 ui.note(_('cloning patch repository\n'))
2188 ui.note(_('cloning patch repository\n'))
2174 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2189 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2175 pull=opts.get('pull'), update=not opts.get('noupdate'),
2190 pull=opts.get('pull'), update=not opts.get('noupdate'),
2176 stream=opts.get('uncompressed'))
2191 stream=opts.get('uncompressed'))
2177
2192
2178 if dr.local():
2193 if dr.local():
2179 if qbase:
2194 if qbase:
2180 ui.note(_('stripping applied patches from destination '
2195 ui.note(_('stripping applied patches from destination '
2181 'repository\n'))
2196 'repository\n'))
2182 dr.mq.strip(dr, [qbase], update=False, backup=None)
2197 dr.mq.strip(dr, [qbase], update=False, backup=None)
2183 if not opts.get('noupdate'):
2198 if not opts.get('noupdate'):
2184 ui.note(_('updating destination repository\n'))
2199 ui.note(_('updating destination repository\n'))
2185 hg.update(dr, dr.changelog.tip())
2200 hg.update(dr, dr.changelog.tip())
2186
2201
2187 @command("qcommit|qci",
2202 @command("qcommit|qci",
2188 commands.table["^commit|ci"][1],
2203 commands.table["^commit|ci"][1],
2189 _('hg qcommit [OPTION]... [FILE]...'))
2204 _('hg qcommit [OPTION]... [FILE]...'))
2190 def commit(ui, repo, *pats, **opts):
2205 def commit(ui, repo, *pats, **opts):
2191 """commit changes in the queue repository (DEPRECATED)
2206 """commit changes in the queue repository (DEPRECATED)
2192
2207
2193 This command is deprecated; use :hg:`commit --mq` instead."""
2208 This command is deprecated; use :hg:`commit --mq` instead."""
2194 q = repo.mq
2209 q = repo.mq
2195 r = q.qrepo()
2210 r = q.qrepo()
2196 if not r:
2211 if not r:
2197 raise util.Abort('no queue repository')
2212 raise util.Abort('no queue repository')
2198 commands.commit(r.ui, r, *pats, **opts)
2213 commands.commit(r.ui, r, *pats, **opts)
2199
2214
2200 @command("qseries",
2215 @command("qseries",
2201 [('m', 'missing', None, _('print patches not in series')),
2216 [('m', 'missing', None, _('print patches not in series')),
2202 ] + seriesopts,
2217 ] + seriesopts,
2203 _('hg qseries [-ms]'))
2218 _('hg qseries [-ms]'))
2204 def series(ui, repo, **opts):
2219 def series(ui, repo, **opts):
2205 """print the entire series file
2220 """print the entire series file
2206
2221
2207 Returns 0 on success."""
2222 Returns 0 on success."""
2208 repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
2223 repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
2209 return 0
2224 return 0
2210
2225
2211 @command("qtop", seriesopts, _('hg qtop [-s]'))
2226 @command("qtop", seriesopts, _('hg qtop [-s]'))
2212 def top(ui, repo, **opts):
2227 def top(ui, repo, **opts):
2213 """print the name of the current patch
2228 """print the name of the current patch
2214
2229
2215 Returns 0 on success."""
2230 Returns 0 on success."""
2216 q = repo.mq
2231 q = repo.mq
2217 t = q.applied and q.seriesend(True) or 0
2232 t = q.applied and q.seriesend(True) or 0
2218 if t:
2233 if t:
2219 q.qseries(repo, start=t - 1, length=1, status='A',
2234 q.qseries(repo, start=t - 1, length=1, status='A',
2220 summary=opts.get('summary'))
2235 summary=opts.get('summary'))
2221 else:
2236 else:
2222 ui.write(_("no patches applied\n"))
2237 ui.write(_("no patches applied\n"))
2223 return 1
2238 return 1
2224
2239
2225 @command("qnext", seriesopts, _('hg qnext [-s]'))
2240 @command("qnext", seriesopts, _('hg qnext [-s]'))
2226 def next(ui, repo, **opts):
2241 def next(ui, repo, **opts):
2227 """print the name of the next pushable patch
2242 """print the name of the next pushable patch
2228
2243
2229 Returns 0 on success."""
2244 Returns 0 on success."""
2230 q = repo.mq
2245 q = repo.mq
2231 end = q.seriesend()
2246 end = q.seriesend()
2232 if end == len(q.series):
2247 if end == len(q.series):
2233 ui.write(_("all patches applied\n"))
2248 ui.write(_("all patches applied\n"))
2234 return 1
2249 return 1
2235 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2250 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2236
2251
2237 @command("qprev", seriesopts, _('hg qprev [-s]'))
2252 @command("qprev", seriesopts, _('hg qprev [-s]'))
2238 def prev(ui, repo, **opts):
2253 def prev(ui, repo, **opts):
2239 """print the name of the preceding applied patch
2254 """print the name of the preceding applied patch
2240
2255
2241 Returns 0 on success."""
2256 Returns 0 on success."""
2242 q = repo.mq
2257 q = repo.mq
2243 l = len(q.applied)
2258 l = len(q.applied)
2244 if l == 1:
2259 if l == 1:
2245 ui.write(_("only one patch applied\n"))
2260 ui.write(_("only one patch applied\n"))
2246 return 1
2261 return 1
2247 if not l:
2262 if not l:
2248 ui.write(_("no patches applied\n"))
2263 ui.write(_("no patches applied\n"))
2249 return 1
2264 return 1
2250 idx = q.series.index(q.applied[-2].name)
2265 idx = q.series.index(q.applied[-2].name)
2251 q.qseries(repo, start=idx, length=1, status='A',
2266 q.qseries(repo, start=idx, length=1, status='A',
2252 summary=opts.get('summary'))
2267 summary=opts.get('summary'))
2253
2268
2254 def setupheaderopts(ui, opts):
2269 def setupheaderopts(ui, opts):
2255 if not opts.get('user') and opts.get('currentuser'):
2270 if not opts.get('user') and opts.get('currentuser'):
2256 opts['user'] = ui.username()
2271 opts['user'] = ui.username()
2257 if not opts.get('date') and opts.get('currentdate'):
2272 if not opts.get('date') and opts.get('currentdate'):
2258 opts['date'] = "%d %d" % util.makedate()
2273 opts['date'] = "%d %d" % util.makedate()
2259
2274
2260 @command("^qnew",
2275 @command("^qnew",
2261 [('e', 'edit', None, _('edit commit message')),
2276 [('e', 'edit', None, _('edit commit message')),
2262 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2277 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2263 ('g', 'git', None, _('use git extended diff format')),
2278 ('g', 'git', None, _('use git extended diff format')),
2264 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2279 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2265 ('u', 'user', '',
2280 ('u', 'user', '',
2266 _('add "From: <USER>" to patch'), _('USER')),
2281 _('add "From: <USER>" to patch'), _('USER')),
2267 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2282 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2268 ('d', 'date', '',
2283 ('d', 'date', '',
2269 _('add "Date: <DATE>" to patch'), _('DATE'))
2284 _('add "Date: <DATE>" to patch'), _('DATE'))
2270 ] + commands.walkopts + commands.commitopts,
2285 ] + commands.walkopts + commands.commitopts,
2271 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'))
2286 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'))
2272 def new(ui, repo, patch, *args, **opts):
2287 def new(ui, repo, patch, *args, **opts):
2273 """create a new patch
2288 """create a new patch
2274
2289
2275 qnew creates a new patch on top of the currently-applied patch (if
2290 qnew creates a new patch on top of the currently-applied patch (if
2276 any). The patch will be initialized with any outstanding changes
2291 any). The patch will be initialized with any outstanding changes
2277 in the working directory. You may also use -I/--include,
2292 in the working directory. You may also use -I/--include,
2278 -X/--exclude, and/or a list of files after the patch name to add
2293 -X/--exclude, and/or a list of files after the patch name to add
2279 only changes to matching files to the new patch, leaving the rest
2294 only changes to matching files to the new patch, leaving the rest
2280 as uncommitted modifications.
2295 as uncommitted modifications.
2281
2296
2282 -u/--user and -d/--date can be used to set the (given) user and
2297 -u/--user and -d/--date can be used to set the (given) user and
2283 date, respectively. -U/--currentuser and -D/--currentdate set user
2298 date, respectively. -U/--currentuser and -D/--currentdate set user
2284 to current user and date to current date.
2299 to current user and date to current date.
2285
2300
2286 -e/--edit, -m/--message or -l/--logfile set the patch header as
2301 -e/--edit, -m/--message or -l/--logfile set the patch header as
2287 well as the commit message. If none is specified, the header is
2302 well as the commit message. If none is specified, the header is
2288 empty and the commit message is '[mq]: PATCH'.
2303 empty and the commit message is '[mq]: PATCH'.
2289
2304
2290 Use the -g/--git option to keep the patch in the git extended diff
2305 Use the -g/--git option to keep the patch in the git extended diff
2291 format. Read the diffs help topic for more information on why this
2306 format. Read the diffs help topic for more information on why this
2292 is important for preserving permission changes and copy/rename
2307 is important for preserving permission changes and copy/rename
2293 information.
2308 information.
2294
2309
2295 Returns 0 on successful creation of a new patch.
2310 Returns 0 on successful creation of a new patch.
2296 """
2311 """
2297 msg = cmdutil.logmessage(ui, opts)
2312 msg = cmdutil.logmessage(ui, opts)
2298 def getmsg():
2313 def getmsg():
2299 return ui.edit(msg, opts.get('user') or ui.username())
2314 return ui.edit(msg, opts.get('user') or ui.username())
2300 q = repo.mq
2315 q = repo.mq
2301 opts['msg'] = msg
2316 opts['msg'] = msg
2302 if opts.get('edit'):
2317 if opts.get('edit'):
2303 opts['msg'] = getmsg
2318 opts['msg'] = getmsg
2304 else:
2319 else:
2305 opts['msg'] = msg
2320 opts['msg'] = msg
2306 setupheaderopts(ui, opts)
2321 setupheaderopts(ui, opts)
2307 q.new(repo, patch, *args, **opts)
2322 q.new(repo, patch, *args, **opts)
2308 q.savedirty()
2323 q.savedirty()
2309 return 0
2324 return 0
2310
2325
2311 @command("^qrefresh",
2326 @command("^qrefresh",
2312 [('e', 'edit', None, _('edit commit message')),
2327 [('e', 'edit', None, _('edit commit message')),
2313 ('g', 'git', None, _('use git extended diff format')),
2328 ('g', 'git', None, _('use git extended diff format')),
2314 ('s', 'short', None,
2329 ('s', 'short', None,
2315 _('refresh only files already in the patch and specified files')),
2330 _('refresh only files already in the patch and specified files')),
2316 ('U', 'currentuser', None,
2331 ('U', 'currentuser', None,
2317 _('add/update author field in patch with current user')),
2332 _('add/update author field in patch with current user')),
2318 ('u', 'user', '',
2333 ('u', 'user', '',
2319 _('add/update author field in patch with given user'), _('USER')),
2334 _('add/update author field in patch with given user'), _('USER')),
2320 ('D', 'currentdate', None,
2335 ('D', 'currentdate', None,
2321 _('add/update date field in patch with current date')),
2336 _('add/update date field in patch with current date')),
2322 ('d', 'date', '',
2337 ('d', 'date', '',
2323 _('add/update date field in patch with given date'), _('DATE'))
2338 _('add/update date field in patch with given date'), _('DATE'))
2324 ] + commands.walkopts + commands.commitopts,
2339 ] + commands.walkopts + commands.commitopts,
2325 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'))
2340 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'))
2326 def refresh(ui, repo, *pats, **opts):
2341 def refresh(ui, repo, *pats, **opts):
2327 """update the current patch
2342 """update the current patch
2328
2343
2329 If any file patterns are provided, the refreshed patch will
2344 If any file patterns are provided, the refreshed patch will
2330 contain only the modifications that match those patterns; the
2345 contain only the modifications that match those patterns; the
2331 remaining modifications will remain in the working directory.
2346 remaining modifications will remain in the working directory.
2332
2347
2333 If -s/--short is specified, files currently included in the patch
2348 If -s/--short is specified, files currently included in the patch
2334 will be refreshed just like matched files and remain in the patch.
2349 will be refreshed just like matched files and remain in the patch.
2335
2350
2336 If -e/--edit is specified, Mercurial will start your configured editor for
2351 If -e/--edit is specified, Mercurial will start your configured editor for
2337 you to enter a message. In case qrefresh fails, you will find a backup of
2352 you to enter a message. In case qrefresh fails, you will find a backup of
2338 your message in ``.hg/last-message.txt``.
2353 your message in ``.hg/last-message.txt``.
2339
2354
2340 hg add/remove/copy/rename work as usual, though you might want to
2355 hg add/remove/copy/rename work as usual, though you might want to
2341 use git-style patches (-g/--git or [diff] git=1) to track copies
2356 use git-style patches (-g/--git or [diff] git=1) to track copies
2342 and renames. See the diffs help topic for more information on the
2357 and renames. See the diffs help topic for more information on the
2343 git diff format.
2358 git diff format.
2344
2359
2345 Returns 0 on success.
2360 Returns 0 on success.
2346 """
2361 """
2347 q = repo.mq
2362 q = repo.mq
2348 message = cmdutil.logmessage(ui, opts)
2363 message = cmdutil.logmessage(ui, opts)
2349 if opts.get('edit'):
2364 if opts.get('edit'):
2350 if not q.applied:
2365 if not q.applied:
2351 ui.write(_("no patches applied\n"))
2366 ui.write(_("no patches applied\n"))
2352 return 1
2367 return 1
2353 if message:
2368 if message:
2354 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2369 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2355 patch = q.applied[-1].name
2370 patch = q.applied[-1].name
2356 ph = patchheader(q.join(patch), q.plainmode)
2371 ph = patchheader(q.join(patch), q.plainmode)
2357 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2372 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2358 # We don't want to lose the patch message if qrefresh fails (issue2062)
2373 # We don't want to lose the patch message if qrefresh fails (issue2062)
2359 repo.savecommitmessage(message)
2374 repo.savecommitmessage(message)
2360 setupheaderopts(ui, opts)
2375 setupheaderopts(ui, opts)
2361 wlock = repo.wlock()
2376 wlock = repo.wlock()
2362 try:
2377 try:
2363 ret = q.refresh(repo, pats, msg=message, **opts)
2378 ret = q.refresh(repo, pats, msg=message, **opts)
2364 q.savedirty()
2379 q.savedirty()
2365 return ret
2380 return ret
2366 finally:
2381 finally:
2367 wlock.release()
2382 wlock.release()
2368
2383
2369 @command("^qdiff",
2384 @command("^qdiff",
2370 commands.diffopts + commands.diffopts2 + commands.walkopts,
2385 commands.diffopts + commands.diffopts2 + commands.walkopts,
2371 _('hg qdiff [OPTION]... [FILE]...'))
2386 _('hg qdiff [OPTION]... [FILE]...'))
2372 def diff(ui, repo, *pats, **opts):
2387 def diff(ui, repo, *pats, **opts):
2373 """diff of the current patch and subsequent modifications
2388 """diff of the current patch and subsequent modifications
2374
2389
2375 Shows a diff which includes the current patch as well as any
2390 Shows a diff which includes the current patch as well as any
2376 changes which have been made in the working directory since the
2391 changes which have been made in the working directory since the
2377 last refresh (thus showing what the current patch would become
2392 last refresh (thus showing what the current patch would become
2378 after a qrefresh).
2393 after a qrefresh).
2379
2394
2380 Use :hg:`diff` if you only want to see the changes made since the
2395 Use :hg:`diff` if you only want to see the changes made since the
2381 last qrefresh, or :hg:`export qtip` if you want to see changes
2396 last qrefresh, or :hg:`export qtip` if you want to see changes
2382 made by the current patch without including changes made since the
2397 made by the current patch without including changes made since the
2383 qrefresh.
2398 qrefresh.
2384
2399
2385 Returns 0 on success.
2400 Returns 0 on success.
2386 """
2401 """
2387 repo.mq.diff(repo, pats, opts)
2402 repo.mq.diff(repo, pats, opts)
2388 return 0
2403 return 0
2389
2404
2390 @command('qfold',
2405 @command('qfold',
2391 [('e', 'edit', None, _('edit patch header')),
2406 [('e', 'edit', None, _('edit patch header')),
2392 ('k', 'keep', None, _('keep folded patch files')),
2407 ('k', 'keep', None, _('keep folded patch files')),
2393 ] + commands.commitopts,
2408 ] + commands.commitopts,
2394 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2409 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2395 def fold(ui, repo, *files, **opts):
2410 def fold(ui, repo, *files, **opts):
2396 """fold the named patches into the current patch
2411 """fold the named patches into the current patch
2397
2412
2398 Patches must not yet be applied. Each patch will be successively
2413 Patches must not yet be applied. Each patch will be successively
2399 applied to the current patch in the order given. If all the
2414 applied to the current patch in the order given. If all the
2400 patches apply successfully, the current patch will be refreshed
2415 patches apply successfully, the current patch will be refreshed
2401 with the new cumulative patch, and the folded patches will be
2416 with the new cumulative patch, and the folded patches will be
2402 deleted. With -k/--keep, the folded patch files will not be
2417 deleted. With -k/--keep, the folded patch files will not be
2403 removed afterwards.
2418 removed afterwards.
2404
2419
2405 The header for each folded patch will be concatenated with the
2420 The header for each folded patch will be concatenated with the
2406 current patch header, separated by a line of ``* * *``.
2421 current patch header, separated by a line of ``* * *``.
2407
2422
2408 Returns 0 on success."""
2423 Returns 0 on success."""
2409 q = repo.mq
2424 q = repo.mq
2410 if not files:
2425 if not files:
2411 raise util.Abort(_('qfold requires at least one patch name'))
2426 raise util.Abort(_('qfold requires at least one patch name'))
2412 if not q.checktoppatch(repo)[0]:
2427 if not q.checktoppatch(repo)[0]:
2413 raise util.Abort(_('no patches applied'))
2428 raise util.Abort(_('no patches applied'))
2414 q.checklocalchanges(repo)
2429 q.checklocalchanges(repo)
2415
2430
2416 message = cmdutil.logmessage(ui, opts)
2431 message = cmdutil.logmessage(ui, opts)
2417 if opts.get('edit'):
2432 if opts.get('edit'):
2418 if message:
2433 if message:
2419 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2434 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2420
2435
2421 parent = q.lookup('qtip')
2436 parent = q.lookup('qtip')
2422 patches = []
2437 patches = []
2423 messages = []
2438 messages = []
2424 for f in files:
2439 for f in files:
2425 p = q.lookup(f)
2440 p = q.lookup(f)
2426 if p in patches or p == parent:
2441 if p in patches or p == parent:
2427 ui.warn(_('Skipping already folded patch %s\n') % p)
2442 ui.warn(_('Skipping already folded patch %s\n') % p)
2428 if q.isapplied(p):
2443 if q.isapplied(p):
2429 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2444 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2430 patches.append(p)
2445 patches.append(p)
2431
2446
2432 for p in patches:
2447 for p in patches:
2433 if not message:
2448 if not message:
2434 ph = patchheader(q.join(p), q.plainmode)
2449 ph = patchheader(q.join(p), q.plainmode)
2435 if ph.message:
2450 if ph.message:
2436 messages.append(ph.message)
2451 messages.append(ph.message)
2437 pf = q.join(p)
2452 pf = q.join(p)
2438 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2453 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2439 if not patchsuccess:
2454 if not patchsuccess:
2440 raise util.Abort(_('error folding patch %s') % p)
2455 raise util.Abort(_('error folding patch %s') % p)
2441
2456
2442 if not message:
2457 if not message:
2443 ph = patchheader(q.join(parent), q.plainmode)
2458 ph = patchheader(q.join(parent), q.plainmode)
2444 message, user = ph.message, ph.user
2459 message, user = ph.message, ph.user
2445 for msg in messages:
2460 for msg in messages:
2446 message.append('* * *')
2461 message.append('* * *')
2447 message.extend(msg)
2462 message.extend(msg)
2448 message = '\n'.join(message)
2463 message = '\n'.join(message)
2449
2464
2450 if opts.get('edit'):
2465 if opts.get('edit'):
2451 message = ui.edit(message, user or ui.username())
2466 message = ui.edit(message, user or ui.username())
2452
2467
2453 diffopts = q.patchopts(q.diffopts(), *patches)
2468 diffopts = q.patchopts(q.diffopts(), *patches)
2454 wlock = repo.wlock()
2469 wlock = repo.wlock()
2455 try:
2470 try:
2456 q.refresh(repo, msg=message, git=diffopts.git)
2471 q.refresh(repo, msg=message, git=diffopts.git)
2457 q.delete(repo, patches, opts)
2472 q.delete(repo, patches, opts)
2458 q.savedirty()
2473 q.savedirty()
2459 finally:
2474 finally:
2460 wlock.release()
2475 wlock.release()
2461
2476
2462 @command("qgoto",
2477 @command("qgoto",
2463 [('f', 'force', None, _('overwrite any local changes'))],
2478 [('f', 'force', None, _('overwrite any local changes'))],
2464 _('hg qgoto [OPTION]... PATCH'))
2479 _('hg qgoto [OPTION]... PATCH'))
2465 def goto(ui, repo, patch, **opts):
2480 def goto(ui, repo, patch, **opts):
2466 '''push or pop patches until named patch is at top of stack
2481 '''push or pop patches until named patch is at top of stack
2467
2482
2468 Returns 0 on success.'''
2483 Returns 0 on success.'''
2469 q = repo.mq
2484 q = repo.mq
2470 patch = q.lookup(patch)
2485 patch = q.lookup(patch)
2471 if q.isapplied(patch):
2486 if q.isapplied(patch):
2472 ret = q.pop(repo, patch, force=opts.get('force'))
2487 ret = q.pop(repo, patch, force=opts.get('force'))
2473 else:
2488 else:
2474 ret = q.push(repo, patch, force=opts.get('force'))
2489 ret = q.push(repo, patch, force=opts.get('force'))
2475 q.savedirty()
2490 q.savedirty()
2476 return ret
2491 return ret
2477
2492
2478 @command("qguard",
2493 @command("qguard",
2479 [('l', 'list', None, _('list all patches and guards')),
2494 [('l', 'list', None, _('list all patches and guards')),
2480 ('n', 'none', None, _('drop all guards'))],
2495 ('n', 'none', None, _('drop all guards'))],
2481 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2496 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2482 def guard(ui, repo, *args, **opts):
2497 def guard(ui, repo, *args, **opts):
2483 '''set or print guards for a patch
2498 '''set or print guards for a patch
2484
2499
2485 Guards control whether a patch can be pushed. A patch with no
2500 Guards control whether a patch can be pushed. A patch with no
2486 guards is always pushed. A patch with a positive guard ("+foo") is
2501 guards is always pushed. A patch with a positive guard ("+foo") is
2487 pushed only if the :hg:`qselect` command has activated it. A patch with
2502 pushed only if the :hg:`qselect` command has activated it. A patch with
2488 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2503 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2489 has activated it.
2504 has activated it.
2490
2505
2491 With no arguments, print the currently active guards.
2506 With no arguments, print the currently active guards.
2492 With arguments, set guards for the named patch.
2507 With arguments, set guards for the named patch.
2493
2508
2494 .. note::
2509 .. note::
2495 Specifying negative guards now requires '--'.
2510 Specifying negative guards now requires '--'.
2496
2511
2497 To set guards on another patch::
2512 To set guards on another patch::
2498
2513
2499 hg qguard other.patch -- +2.6.17 -stable
2514 hg qguard other.patch -- +2.6.17 -stable
2500
2515
2501 Returns 0 on success.
2516 Returns 0 on success.
2502 '''
2517 '''
2503 def status(idx):
2518 def status(idx):
2504 guards = q.seriesguards[idx] or ['unguarded']
2519 guards = q.seriesguards[idx] or ['unguarded']
2505 if q.series[idx] in applied:
2520 if q.series[idx] in applied:
2506 state = 'applied'
2521 state = 'applied'
2507 elif q.pushable(idx)[0]:
2522 elif q.pushable(idx)[0]:
2508 state = 'unapplied'
2523 state = 'unapplied'
2509 else:
2524 else:
2510 state = 'guarded'
2525 state = 'guarded'
2511 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2526 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2512 ui.write('%s: ' % ui.label(q.series[idx], label))
2527 ui.write('%s: ' % ui.label(q.series[idx], label))
2513
2528
2514 for i, guard in enumerate(guards):
2529 for i, guard in enumerate(guards):
2515 if guard.startswith('+'):
2530 if guard.startswith('+'):
2516 ui.write(guard, label='qguard.positive')
2531 ui.write(guard, label='qguard.positive')
2517 elif guard.startswith('-'):
2532 elif guard.startswith('-'):
2518 ui.write(guard, label='qguard.negative')
2533 ui.write(guard, label='qguard.negative')
2519 else:
2534 else:
2520 ui.write(guard, label='qguard.unguarded')
2535 ui.write(guard, label='qguard.unguarded')
2521 if i != len(guards) - 1:
2536 if i != len(guards) - 1:
2522 ui.write(' ')
2537 ui.write(' ')
2523 ui.write('\n')
2538 ui.write('\n')
2524 q = repo.mq
2539 q = repo.mq
2525 applied = set(p.name for p in q.applied)
2540 applied = set(p.name for p in q.applied)
2526 patch = None
2541 patch = None
2527 args = list(args)
2542 args = list(args)
2528 if opts.get('list'):
2543 if opts.get('list'):
2529 if args or opts.get('none'):
2544 if args or opts.get('none'):
2530 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2545 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2531 for i in xrange(len(q.series)):
2546 for i in xrange(len(q.series)):
2532 status(i)
2547 status(i)
2533 return
2548 return
2534 if not args or args[0][0:1] in '-+':
2549 if not args or args[0][0:1] in '-+':
2535 if not q.applied:
2550 if not q.applied:
2536 raise util.Abort(_('no patches applied'))
2551 raise util.Abort(_('no patches applied'))
2537 patch = q.applied[-1].name
2552 patch = q.applied[-1].name
2538 if patch is None and args[0][0:1] not in '-+':
2553 if patch is None and args[0][0:1] not in '-+':
2539 patch = args.pop(0)
2554 patch = args.pop(0)
2540 if patch is None:
2555 if patch is None:
2541 raise util.Abort(_('no patch to work with'))
2556 raise util.Abort(_('no patch to work with'))
2542 if args or opts.get('none'):
2557 if args or opts.get('none'):
2543 idx = q.findseries(patch)
2558 idx = q.findseries(patch)
2544 if idx is None:
2559 if idx is None:
2545 raise util.Abort(_('no patch named %s') % patch)
2560 raise util.Abort(_('no patch named %s') % patch)
2546 q.setguards(idx, args)
2561 q.setguards(idx, args)
2547 q.savedirty()
2562 q.savedirty()
2548 else:
2563 else:
2549 status(q.series.index(q.lookup(patch)))
2564 status(q.series.index(q.lookup(patch)))
2550
2565
2551 @command("qheader", [], _('hg qheader [PATCH]'))
2566 @command("qheader", [], _('hg qheader [PATCH]'))
2552 def header(ui, repo, patch=None):
2567 def header(ui, repo, patch=None):
2553 """print the header of the topmost or specified patch
2568 """print the header of the topmost or specified patch
2554
2569
2555 Returns 0 on success."""
2570 Returns 0 on success."""
2556 q = repo.mq
2571 q = repo.mq
2557
2572
2558 if patch:
2573 if patch:
2559 patch = q.lookup(patch)
2574 patch = q.lookup(patch)
2560 else:
2575 else:
2561 if not q.applied:
2576 if not q.applied:
2562 ui.write(_('no patches applied\n'))
2577 ui.write(_('no patches applied\n'))
2563 return 1
2578 return 1
2564 patch = q.lookup('qtip')
2579 patch = q.lookup('qtip')
2565 ph = patchheader(q.join(patch), q.plainmode)
2580 ph = patchheader(q.join(patch), q.plainmode)
2566
2581
2567 ui.write('\n'.join(ph.message) + '\n')
2582 ui.write('\n'.join(ph.message) + '\n')
2568
2583
2569 def lastsavename(path):
2584 def lastsavename(path):
2570 (directory, base) = os.path.split(path)
2585 (directory, base) = os.path.split(path)
2571 names = os.listdir(directory)
2586 names = os.listdir(directory)
2572 namere = re.compile("%s.([0-9]+)" % base)
2587 namere = re.compile("%s.([0-9]+)" % base)
2573 maxindex = None
2588 maxindex = None
2574 maxname = None
2589 maxname = None
2575 for f in names:
2590 for f in names:
2576 m = namere.match(f)
2591 m = namere.match(f)
2577 if m:
2592 if m:
2578 index = int(m.group(1))
2593 index = int(m.group(1))
2579 if maxindex is None or index > maxindex:
2594 if maxindex is None or index > maxindex:
2580 maxindex = index
2595 maxindex = index
2581 maxname = f
2596 maxname = f
2582 if maxname:
2597 if maxname:
2583 return (os.path.join(directory, maxname), maxindex)
2598 return (os.path.join(directory, maxname), maxindex)
2584 return (None, None)
2599 return (None, None)
2585
2600
2586 def savename(path):
2601 def savename(path):
2587 (last, index) = lastsavename(path)
2602 (last, index) = lastsavename(path)
2588 if last is None:
2603 if last is None:
2589 index = 0
2604 index = 0
2590 newpath = path + ".%d" % (index + 1)
2605 newpath = path + ".%d" % (index + 1)
2591 return newpath
2606 return newpath
2592
2607
2593 @command("^qpush",
2608 @command("^qpush",
2594 [('f', 'force', None, _('apply on top of local changes')),
2609 [('f', 'force', None, _('apply on top of local changes')),
2595 ('e', 'exact', None, _('apply the target patch to its recorded parent')),
2610 ('e', 'exact', None, _('apply the target patch to its recorded parent')),
2596 ('l', 'list', None, _('list patch name in commit text')),
2611 ('l', 'list', None, _('list patch name in commit text')),
2597 ('a', 'all', None, _('apply all patches')),
2612 ('a', 'all', None, _('apply all patches')),
2598 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2613 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2599 ('n', 'name', '',
2614 ('n', 'name', '',
2600 _('merge queue name (DEPRECATED)'), _('NAME')),
2615 _('merge queue name (DEPRECATED)'), _('NAME')),
2601 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2616 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2602 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2617 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2603 def push(ui, repo, patch=None, **opts):
2618 def push(ui, repo, patch=None, **opts):
2604 """push the next patch onto the stack
2619 """push the next patch onto the stack
2605
2620
2606 When -f/--force is applied, all local changes in patched files
2621 When -f/--force is applied, all local changes in patched files
2607 will be lost.
2622 will be lost.
2608
2623
2609 Return 0 on success.
2624 Return 0 on success.
2610 """
2625 """
2611 q = repo.mq
2626 q = repo.mq
2612 mergeq = None
2627 mergeq = None
2613
2628
2614 if opts.get('merge'):
2629 if opts.get('merge'):
2615 if opts.get('name'):
2630 if opts.get('name'):
2616 newpath = repo.join(opts.get('name'))
2631 newpath = repo.join(opts.get('name'))
2617 else:
2632 else:
2618 newpath, i = lastsavename(q.path)
2633 newpath, i = lastsavename(q.path)
2619 if not newpath:
2634 if not newpath:
2620 ui.warn(_("no saved queues found, please use -n\n"))
2635 ui.warn(_("no saved queues found, please use -n\n"))
2621 return 1
2636 return 1
2622 mergeq = queue(ui, repo.path, newpath)
2637 mergeq = queue(ui, repo.path, newpath)
2623 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2638 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2624 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2639 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2625 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2640 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2626 exact=opts.get('exact'))
2641 exact=opts.get('exact'))
2627 return ret
2642 return ret
2628
2643
2629 @command("^qpop",
2644 @command("^qpop",
2630 [('a', 'all', None, _('pop all patches')),
2645 [('a', 'all', None, _('pop all patches')),
2631 ('n', 'name', '',
2646 ('n', 'name', '',
2632 _('queue name to pop (DEPRECATED)'), _('NAME')),
2647 _('queue name to pop (DEPRECATED)'), _('NAME')),
2633 ('f', 'force', None, _('forget any local changes to patched files'))],
2648 ('f', 'force', None, _('forget any local changes to patched files'))],
2634 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2649 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2635 def pop(ui, repo, patch=None, **opts):
2650 def pop(ui, repo, patch=None, **opts):
2636 """pop the current patch off the stack
2651 """pop the current patch off the stack
2637
2652
2638 By default, pops off the top of the patch stack. If given a patch
2653 By default, pops off the top of the patch stack. If given a patch
2639 name, keeps popping off patches until the named patch is at the
2654 name, keeps popping off patches until the named patch is at the
2640 top of the stack.
2655 top of the stack.
2641
2656
2642 Return 0 on success.
2657 Return 0 on success.
2643 """
2658 """
2644 localupdate = True
2659 localupdate = True
2645 if opts.get('name'):
2660 if opts.get('name'):
2646 q = queue(ui, repo.path, repo.join(opts.get('name')))
2661 q = queue(ui, repo.path, repo.join(opts.get('name')))
2647 ui.warn(_('using patch queue: %s\n') % q.path)
2662 ui.warn(_('using patch queue: %s\n') % q.path)
2648 localupdate = False
2663 localupdate = False
2649 else:
2664 else:
2650 q = repo.mq
2665 q = repo.mq
2651 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2666 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2652 all=opts.get('all'))
2667 all=opts.get('all'))
2653 q.savedirty()
2668 q.savedirty()
2654 return ret
2669 return ret
2655
2670
2656 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2671 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2657 def rename(ui, repo, patch, name=None, **opts):
2672 def rename(ui, repo, patch, name=None, **opts):
2658 """rename a patch
2673 """rename a patch
2659
2674
2660 With one argument, renames the current patch to PATCH1.
2675 With one argument, renames the current patch to PATCH1.
2661 With two arguments, renames PATCH1 to PATCH2.
2676 With two arguments, renames PATCH1 to PATCH2.
2662
2677
2663 Returns 0 on success."""
2678 Returns 0 on success."""
2664 q = repo.mq
2679 q = repo.mq
2665 if not name:
2680 if not name:
2666 name = patch
2681 name = patch
2667 patch = None
2682 patch = None
2668
2683
2669 if patch:
2684 if patch:
2670 patch = q.lookup(patch)
2685 patch = q.lookup(patch)
2671 else:
2686 else:
2672 if not q.applied:
2687 if not q.applied:
2673 ui.write(_('no patches applied\n'))
2688 ui.write(_('no patches applied\n'))
2674 return
2689 return
2675 patch = q.lookup('qtip')
2690 patch = q.lookup('qtip')
2676 absdest = q.join(name)
2691 absdest = q.join(name)
2677 if os.path.isdir(absdest):
2692 if os.path.isdir(absdest):
2678 name = normname(os.path.join(name, os.path.basename(patch)))
2693 name = normname(os.path.join(name, os.path.basename(patch)))
2679 absdest = q.join(name)
2694 absdest = q.join(name)
2680 q.checkpatchname(name)
2695 q.checkpatchname(name)
2681
2696
2682 ui.note(_('renaming %s to %s\n') % (patch, name))
2697 ui.note(_('renaming %s to %s\n') % (patch, name))
2683 i = q.findseries(patch)
2698 i = q.findseries(patch)
2684 guards = q.guard_re.findall(q.fullseries[i])
2699 guards = q.guard_re.findall(q.fullseries[i])
2685 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2700 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2686 q.parseseries()
2701 q.parseseries()
2687 q.seriesdirty = True
2702 q.seriesdirty = True
2688
2703
2689 info = q.isapplied(patch)
2704 info = q.isapplied(patch)
2690 if info:
2705 if info:
2691 q.applied[info[0]] = statusentry(info[1], name)
2706 q.applied[info[0]] = statusentry(info[1], name)
2692 q.applieddirty = True
2707 q.applieddirty = True
2693
2708
2694 destdir = os.path.dirname(absdest)
2709 destdir = os.path.dirname(absdest)
2695 if not os.path.isdir(destdir):
2710 if not os.path.isdir(destdir):
2696 os.makedirs(destdir)
2711 os.makedirs(destdir)
2697 util.rename(q.join(patch), absdest)
2712 util.rename(q.join(patch), absdest)
2698 r = q.qrepo()
2713 r = q.qrepo()
2699 if r and patch in r.dirstate:
2714 if r and patch in r.dirstate:
2700 wctx = r[None]
2715 wctx = r[None]
2701 wlock = r.wlock()
2716 wlock = r.wlock()
2702 try:
2717 try:
2703 if r.dirstate[patch] == 'a':
2718 if r.dirstate[patch] == 'a':
2704 r.dirstate.drop(patch)
2719 r.dirstate.drop(patch)
2705 r.dirstate.add(name)
2720 r.dirstate.add(name)
2706 else:
2721 else:
2707 wctx.copy(patch, name)
2722 wctx.copy(patch, name)
2708 wctx.forget([patch])
2723 wctx.forget([patch])
2709 finally:
2724 finally:
2710 wlock.release()
2725 wlock.release()
2711
2726
2712 q.savedirty()
2727 q.savedirty()
2713
2728
2714 @command("qrestore",
2729 @command("qrestore",
2715 [('d', 'delete', None, _('delete save entry')),
2730 [('d', 'delete', None, _('delete save entry')),
2716 ('u', 'update', None, _('update queue working directory'))],
2731 ('u', 'update', None, _('update queue working directory'))],
2717 _('hg qrestore [-d] [-u] REV'))
2732 _('hg qrestore [-d] [-u] REV'))
2718 def restore(ui, repo, rev, **opts):
2733 def restore(ui, repo, rev, **opts):
2719 """restore the queue state saved by a revision (DEPRECATED)
2734 """restore the queue state saved by a revision (DEPRECATED)
2720
2735
2721 This command is deprecated, use :hg:`rebase` instead."""
2736 This command is deprecated, use :hg:`rebase` instead."""
2722 rev = repo.lookup(rev)
2737 rev = repo.lookup(rev)
2723 q = repo.mq
2738 q = repo.mq
2724 q.restore(repo, rev, delete=opts.get('delete'),
2739 q.restore(repo, rev, delete=opts.get('delete'),
2725 qupdate=opts.get('update'))
2740 qupdate=opts.get('update'))
2726 q.savedirty()
2741 q.savedirty()
2727 return 0
2742 return 0
2728
2743
2729 @command("qsave",
2744 @command("qsave",
2730 [('c', 'copy', None, _('copy patch directory')),
2745 [('c', 'copy', None, _('copy patch directory')),
2731 ('n', 'name', '',
2746 ('n', 'name', '',
2732 _('copy directory name'), _('NAME')),
2747 _('copy directory name'), _('NAME')),
2733 ('e', 'empty', None, _('clear queue status file')),
2748 ('e', 'empty', None, _('clear queue status file')),
2734 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2749 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2735 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
2750 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
2736 def save(ui, repo, **opts):
2751 def save(ui, repo, **opts):
2737 """save current queue state (DEPRECATED)
2752 """save current queue state (DEPRECATED)
2738
2753
2739 This command is deprecated, use :hg:`rebase` instead."""
2754 This command is deprecated, use :hg:`rebase` instead."""
2740 q = repo.mq
2755 q = repo.mq
2741 message = cmdutil.logmessage(ui, opts)
2756 message = cmdutil.logmessage(ui, opts)
2742 ret = q.save(repo, msg=message)
2757 ret = q.save(repo, msg=message)
2743 if ret:
2758 if ret:
2744 return ret
2759 return ret
2745 q.savedirty() # save to .hg/patches before copying
2760 q.savedirty() # save to .hg/patches before copying
2746 if opts.get('copy'):
2761 if opts.get('copy'):
2747 path = q.path
2762 path = q.path
2748 if opts.get('name'):
2763 if opts.get('name'):
2749 newpath = os.path.join(q.basepath, opts.get('name'))
2764 newpath = os.path.join(q.basepath, opts.get('name'))
2750 if os.path.exists(newpath):
2765 if os.path.exists(newpath):
2751 if not os.path.isdir(newpath):
2766 if not os.path.isdir(newpath):
2752 raise util.Abort(_('destination %s exists and is not '
2767 raise util.Abort(_('destination %s exists and is not '
2753 'a directory') % newpath)
2768 'a directory') % newpath)
2754 if not opts.get('force'):
2769 if not opts.get('force'):
2755 raise util.Abort(_('destination %s exists, '
2770 raise util.Abort(_('destination %s exists, '
2756 'use -f to force') % newpath)
2771 'use -f to force') % newpath)
2757 else:
2772 else:
2758 newpath = savename(path)
2773 newpath = savename(path)
2759 ui.warn(_("copy %s to %s\n") % (path, newpath))
2774 ui.warn(_("copy %s to %s\n") % (path, newpath))
2760 util.copyfiles(path, newpath)
2775 util.copyfiles(path, newpath)
2761 if opts.get('empty'):
2776 if opts.get('empty'):
2762 del q.applied[:]
2777 del q.applied[:]
2763 q.applieddirty = True
2778 q.applieddirty = True
2764 q.savedirty()
2779 q.savedirty()
2765 return 0
2780 return 0
2766
2781
2767 @command("strip",
2782 @command("strip",
2768 [
2783 [
2769 ('r', 'rev', [], _('strip specified revision (optional, '
2784 ('r', 'rev', [], _('strip specified revision (optional, '
2770 'can specify revisions without this '
2785 'can specify revisions without this '
2771 'option)'), _('REV')),
2786 'option)'), _('REV')),
2772 ('f', 'force', None, _('force removal of changesets, discard '
2787 ('f', 'force', None, _('force removal of changesets, discard '
2773 'uncommitted changes (no backup)')),
2788 'uncommitted changes (no backup)')),
2774 ('b', 'backup', None, _('bundle only changesets with local revision'
2789 ('b', 'backup', None, _('bundle only changesets with local revision'
2775 ' number greater than REV which are not'
2790 ' number greater than REV which are not'
2776 ' descendants of REV (DEPRECATED)')),
2791 ' descendants of REV (DEPRECATED)')),
2777 ('', 'no-backup', None, _('no backups')),
2792 ('', 'no-backup', None, _('no backups')),
2778 ('', 'nobackup', None, _('no backups (DEPRECATED)')),
2793 ('', 'nobackup', None, _('no backups (DEPRECATED)')),
2779 ('n', '', None, _('ignored (DEPRECATED)')),
2794 ('n', '', None, _('ignored (DEPRECATED)')),
2780 ('k', 'keep', None, _("do not modify working copy during strip"))],
2795 ('k', 'keep', None, _("do not modify working copy during strip"))],
2781 _('hg strip [-k] [-f] [-n] REV...'))
2796 _('hg strip [-k] [-f] [-n] REV...'))
2782 def strip(ui, repo, *revs, **opts):
2797 def strip(ui, repo, *revs, **opts):
2783 """strip changesets and all their descendants from the repository
2798 """strip changesets and all their descendants from the repository
2784
2799
2785 The strip command removes the specified changesets and all their
2800 The strip command removes the specified changesets and all their
2786 descendants. If the working directory has uncommitted changes, the
2801 descendants. If the working directory has uncommitted changes, the
2787 operation is aborted unless the --force flag is supplied, in which
2802 operation is aborted unless the --force flag is supplied, in which
2788 case changes will be discarded.
2803 case changes will be discarded.
2789
2804
2790 If a parent of the working directory is stripped, then the working
2805 If a parent of the working directory is stripped, then the working
2791 directory will automatically be updated to the most recent
2806 directory will automatically be updated to the most recent
2792 available ancestor of the stripped parent after the operation
2807 available ancestor of the stripped parent after the operation
2793 completes.
2808 completes.
2794
2809
2795 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2810 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2796 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2811 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2797 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2812 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2798 where BUNDLE is the bundle file created by the strip. Note that
2813 where BUNDLE is the bundle file created by the strip. Note that
2799 the local revision numbers will in general be different after the
2814 the local revision numbers will in general be different after the
2800 restore.
2815 restore.
2801
2816
2802 Use the --no-backup option to discard the backup bundle once the
2817 Use the --no-backup option to discard the backup bundle once the
2803 operation completes.
2818 operation completes.
2804
2819
2805 Return 0 on success.
2820 Return 0 on success.
2806 """
2821 """
2807 backup = 'all'
2822 backup = 'all'
2808 if opts.get('backup'):
2823 if opts.get('backup'):
2809 backup = 'strip'
2824 backup = 'strip'
2810 elif opts.get('no_backup') or opts.get('nobackup'):
2825 elif opts.get('no_backup') or opts.get('nobackup'):
2811 backup = 'none'
2826 backup = 'none'
2812
2827
2813 cl = repo.changelog
2828 cl = repo.changelog
2814 revs = list(revs) + opts.get('rev')
2829 revs = list(revs) + opts.get('rev')
2815 revs = set(scmutil.revrange(repo, revs))
2830 revs = set(scmutil.revrange(repo, revs))
2816 if not revs:
2831 if not revs:
2817 raise util.Abort(_('empty revision set'))
2832 raise util.Abort(_('empty revision set'))
2818
2833
2819 descendants = set(cl.descendants(*revs))
2834 descendants = set(cl.descendants(*revs))
2820 strippedrevs = revs.union(descendants)
2835 strippedrevs = revs.union(descendants)
2821 roots = revs.difference(descendants)
2836 roots = revs.difference(descendants)
2822
2837
2823 update = False
2838 update = False
2824 # if one of the wdir parent is stripped we'll need
2839 # if one of the wdir parent is stripped we'll need
2825 # to update away to an earlier revision
2840 # to update away to an earlier revision
2826 for p in repo.dirstate.parents():
2841 for p in repo.dirstate.parents():
2827 if p != nullid and cl.rev(p) in strippedrevs:
2842 if p != nullid and cl.rev(p) in strippedrevs:
2828 update = True
2843 update = True
2829 break
2844 break
2830
2845
2831 rootnodes = set(cl.node(r) for r in roots)
2846 rootnodes = set(cl.node(r) for r in roots)
2832
2847
2833 q = repo.mq
2848 q = repo.mq
2834 if q.applied:
2849 if q.applied:
2835 # refresh queue state if we're about to strip
2850 # refresh queue state if we're about to strip
2836 # applied patches
2851 # applied patches
2837 if cl.rev(repo.lookup('qtip')) in strippedrevs:
2852 if cl.rev(repo.lookup('qtip')) in strippedrevs:
2838 q.applieddirty = True
2853 q.applieddirty = True
2839 start = 0
2854 start = 0
2840 end = len(q.applied)
2855 end = len(q.applied)
2841 for i, statusentry in enumerate(q.applied):
2856 for i, statusentry in enumerate(q.applied):
2842 if statusentry.node in rootnodes:
2857 if statusentry.node in rootnodes:
2843 # if one of the stripped roots is an applied
2858 # if one of the stripped roots is an applied
2844 # patch, only part of the queue is stripped
2859 # patch, only part of the queue is stripped
2845 start = i
2860 start = i
2846 break
2861 break
2847 del q.applied[start:end]
2862 del q.applied[start:end]
2848 q.savedirty()
2863 q.savedirty()
2849
2864
2850 revs = list(rootnodes)
2865 revs = list(rootnodes)
2851 if update and opts.get('keep'):
2866 if update and opts.get('keep'):
2852 wlock = repo.wlock()
2867 wlock = repo.wlock()
2853 try:
2868 try:
2854 urev = repo.mq.qparents(repo, revs[0])
2869 urev = repo.mq.qparents(repo, revs[0])
2855 repo.dirstate.rebuild(urev, repo[urev].manifest())
2870 repo.dirstate.rebuild(urev, repo[urev].manifest())
2856 repo.dirstate.write()
2871 repo.dirstate.write()
2857 update = False
2872 update = False
2858 finally:
2873 finally:
2859 wlock.release()
2874 wlock.release()
2860
2875
2861 repo.mq.strip(repo, revs, backup=backup, update=update,
2876 repo.mq.strip(repo, revs, backup=backup, update=update,
2862 force=opts.get('force'))
2877 force=opts.get('force'))
2863 return 0
2878 return 0
2864
2879
2865 @command("qselect",
2880 @command("qselect",
2866 [('n', 'none', None, _('disable all guards')),
2881 [('n', 'none', None, _('disable all guards')),
2867 ('s', 'series', None, _('list all guards in series file')),
2882 ('s', 'series', None, _('list all guards in series file')),
2868 ('', 'pop', None, _('pop to before first guarded applied patch')),
2883 ('', 'pop', None, _('pop to before first guarded applied patch')),
2869 ('', 'reapply', None, _('pop, then reapply patches'))],
2884 ('', 'reapply', None, _('pop, then reapply patches'))],
2870 _('hg qselect [OPTION]... [GUARD]...'))
2885 _('hg qselect [OPTION]... [GUARD]...'))
2871 def select(ui, repo, *args, **opts):
2886 def select(ui, repo, *args, **opts):
2872 '''set or print guarded patches to push
2887 '''set or print guarded patches to push
2873
2888
2874 Use the :hg:`qguard` command to set or print guards on patch, then use
2889 Use the :hg:`qguard` command to set or print guards on patch, then use
2875 qselect to tell mq which guards to use. A patch will be pushed if
2890 qselect to tell mq which guards to use. A patch will be pushed if
2876 it has no guards or any positive guards match the currently
2891 it has no guards or any positive guards match the currently
2877 selected guard, but will not be pushed if any negative guards
2892 selected guard, but will not be pushed if any negative guards
2878 match the current guard. For example::
2893 match the current guard. For example::
2879
2894
2880 qguard foo.patch -- -stable (negative guard)
2895 qguard foo.patch -- -stable (negative guard)
2881 qguard bar.patch +stable (positive guard)
2896 qguard bar.patch +stable (positive guard)
2882 qselect stable
2897 qselect stable
2883
2898
2884 This activates the "stable" guard. mq will skip foo.patch (because
2899 This activates the "stable" guard. mq will skip foo.patch (because
2885 it has a negative match) but push bar.patch (because it has a
2900 it has a negative match) but push bar.patch (because it has a
2886 positive match).
2901 positive match).
2887
2902
2888 With no arguments, prints the currently active guards.
2903 With no arguments, prints the currently active guards.
2889 With one argument, sets the active guard.
2904 With one argument, sets the active guard.
2890
2905
2891 Use -n/--none to deactivate guards (no other arguments needed).
2906 Use -n/--none to deactivate guards (no other arguments needed).
2892 When no guards are active, patches with positive guards are
2907 When no guards are active, patches with positive guards are
2893 skipped and patches with negative guards are pushed.
2908 skipped and patches with negative guards are pushed.
2894
2909
2895 qselect can change the guards on applied patches. It does not pop
2910 qselect can change the guards on applied patches. It does not pop
2896 guarded patches by default. Use --pop to pop back to the last
2911 guarded patches by default. Use --pop to pop back to the last
2897 applied patch that is not guarded. Use --reapply (which implies
2912 applied patch that is not guarded. Use --reapply (which implies
2898 --pop) to push back to the current patch afterwards, but skip
2913 --pop) to push back to the current patch afterwards, but skip
2899 guarded patches.
2914 guarded patches.
2900
2915
2901 Use -s/--series to print a list of all guards in the series file
2916 Use -s/--series to print a list of all guards in the series file
2902 (no other arguments needed). Use -v for more information.
2917 (no other arguments needed). Use -v for more information.
2903
2918
2904 Returns 0 on success.'''
2919 Returns 0 on success.'''
2905
2920
2906 q = repo.mq
2921 q = repo.mq
2907 guards = q.active()
2922 guards = q.active()
2908 if args or opts.get('none'):
2923 if args or opts.get('none'):
2909 old_unapplied = q.unapplied(repo)
2924 old_unapplied = q.unapplied(repo)
2910 old_guarded = [i for i in xrange(len(q.applied)) if
2925 old_guarded = [i for i in xrange(len(q.applied)) if
2911 not q.pushable(i)[0]]
2926 not q.pushable(i)[0]]
2912 q.setactive(args)
2927 q.setactive(args)
2913 q.savedirty()
2928 q.savedirty()
2914 if not args:
2929 if not args:
2915 ui.status(_('guards deactivated\n'))
2930 ui.status(_('guards deactivated\n'))
2916 if not opts.get('pop') and not opts.get('reapply'):
2931 if not opts.get('pop') and not opts.get('reapply'):
2917 unapplied = q.unapplied(repo)
2932 unapplied = q.unapplied(repo)
2918 guarded = [i for i in xrange(len(q.applied))
2933 guarded = [i for i in xrange(len(q.applied))
2919 if not q.pushable(i)[0]]
2934 if not q.pushable(i)[0]]
2920 if len(unapplied) != len(old_unapplied):
2935 if len(unapplied) != len(old_unapplied):
2921 ui.status(_('number of unguarded, unapplied patches has '
2936 ui.status(_('number of unguarded, unapplied patches has '
2922 'changed from %d to %d\n') %
2937 'changed from %d to %d\n') %
2923 (len(old_unapplied), len(unapplied)))
2938 (len(old_unapplied), len(unapplied)))
2924 if len(guarded) != len(old_guarded):
2939 if len(guarded) != len(old_guarded):
2925 ui.status(_('number of guarded, applied patches has changed '
2940 ui.status(_('number of guarded, applied patches has changed '
2926 'from %d to %d\n') %
2941 'from %d to %d\n') %
2927 (len(old_guarded), len(guarded)))
2942 (len(old_guarded), len(guarded)))
2928 elif opts.get('series'):
2943 elif opts.get('series'):
2929 guards = {}
2944 guards = {}
2930 noguards = 0
2945 noguards = 0
2931 for gs in q.seriesguards:
2946 for gs in q.seriesguards:
2932 if not gs:
2947 if not gs:
2933 noguards += 1
2948 noguards += 1
2934 for g in gs:
2949 for g in gs:
2935 guards.setdefault(g, 0)
2950 guards.setdefault(g, 0)
2936 guards[g] += 1
2951 guards[g] += 1
2937 if ui.verbose:
2952 if ui.verbose:
2938 guards['NONE'] = noguards
2953 guards['NONE'] = noguards
2939 guards = guards.items()
2954 guards = guards.items()
2940 guards.sort(key=lambda x: x[0][1:])
2955 guards.sort(key=lambda x: x[0][1:])
2941 if guards:
2956 if guards:
2942 ui.note(_('guards in series file:\n'))
2957 ui.note(_('guards in series file:\n'))
2943 for guard, count in guards:
2958 for guard, count in guards:
2944 ui.note('%2d ' % count)
2959 ui.note('%2d ' % count)
2945 ui.write(guard, '\n')
2960 ui.write(guard, '\n')
2946 else:
2961 else:
2947 ui.note(_('no guards in series file\n'))
2962 ui.note(_('no guards in series file\n'))
2948 else:
2963 else:
2949 if guards:
2964 if guards:
2950 ui.note(_('active guards:\n'))
2965 ui.note(_('active guards:\n'))
2951 for g in guards:
2966 for g in guards:
2952 ui.write(g, '\n')
2967 ui.write(g, '\n')
2953 else:
2968 else:
2954 ui.write(_('no active guards\n'))
2969 ui.write(_('no active guards\n'))
2955 reapply = opts.get('reapply') and q.applied and q.appliedname(-1)
2970 reapply = opts.get('reapply') and q.applied and q.appliedname(-1)
2956 popped = False
2971 popped = False
2957 if opts.get('pop') or opts.get('reapply'):
2972 if opts.get('pop') or opts.get('reapply'):
2958 for i in xrange(len(q.applied)):
2973 for i in xrange(len(q.applied)):
2959 pushable, reason = q.pushable(i)
2974 pushable, reason = q.pushable(i)
2960 if not pushable:
2975 if not pushable:
2961 ui.status(_('popping guarded patches\n'))
2976 ui.status(_('popping guarded patches\n'))
2962 popped = True
2977 popped = True
2963 if i == 0:
2978 if i == 0:
2964 q.pop(repo, all=True)
2979 q.pop(repo, all=True)
2965 else:
2980 else:
2966 q.pop(repo, str(i - 1))
2981 q.pop(repo, str(i - 1))
2967 break
2982 break
2968 if popped:
2983 if popped:
2969 try:
2984 try:
2970 if reapply:
2985 if reapply:
2971 ui.status(_('reapplying unguarded patches\n'))
2986 ui.status(_('reapplying unguarded patches\n'))
2972 q.push(repo, reapply)
2987 q.push(repo, reapply)
2973 finally:
2988 finally:
2974 q.savedirty()
2989 q.savedirty()
2975
2990
2976 @command("qfinish",
2991 @command("qfinish",
2977 [('a', 'applied', None, _('finish all applied changesets'))],
2992 [('a', 'applied', None, _('finish all applied changesets'))],
2978 _('hg qfinish [-a] [REV]...'))
2993 _('hg qfinish [-a] [REV]...'))
2979 def finish(ui, repo, *revrange, **opts):
2994 def finish(ui, repo, *revrange, **opts):
2980 """move applied patches into repository history
2995 """move applied patches into repository history
2981
2996
2982 Finishes the specified revisions (corresponding to applied
2997 Finishes the specified revisions (corresponding to applied
2983 patches) by moving them out of mq control into regular repository
2998 patches) by moving them out of mq control into regular repository
2984 history.
2999 history.
2985
3000
2986 Accepts a revision range or the -a/--applied option. If --applied
3001 Accepts a revision range or the -a/--applied option. If --applied
2987 is specified, all applied mq revisions are removed from mq
3002 is specified, all applied mq revisions are removed from mq
2988 control. Otherwise, the given revisions must be at the base of the
3003 control. Otherwise, the given revisions must be at the base of the
2989 stack of applied patches.
3004 stack of applied patches.
2990
3005
2991 This can be especially useful if your changes have been applied to
3006 This can be especially useful if your changes have been applied to
2992 an upstream repository, or if you are about to push your changes
3007 an upstream repository, or if you are about to push your changes
2993 to upstream.
3008 to upstream.
2994
3009
2995 Returns 0 on success.
3010 Returns 0 on success.
2996 """
3011 """
2997 if not opts.get('applied') and not revrange:
3012 if not opts.get('applied') and not revrange:
2998 raise util.Abort(_('no revisions specified'))
3013 raise util.Abort(_('no revisions specified'))
2999 elif opts.get('applied'):
3014 elif opts.get('applied'):
3000 revrange = ('qbase::qtip',) + revrange
3015 revrange = ('qbase::qtip',) + revrange
3001
3016
3002 q = repo.mq
3017 q = repo.mq
3003 if not q.applied:
3018 if not q.applied:
3004 ui.status(_('no patches applied\n'))
3019 ui.status(_('no patches applied\n'))
3005 return 0
3020 return 0
3006
3021
3007 revs = scmutil.revrange(repo, revrange)
3022 revs = scmutil.revrange(repo, revrange)
3008 if repo['.'].rev() in revs and repo[None].files():
3023 if repo['.'].rev() in revs and repo[None].files():
3009 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3024 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3010 # queue.finish may changes phases but leave the responsability to lock the
3025 # queue.finish may changes phases but leave the responsability to lock the
3011 # repo to the caller to avoid deadlock with wlock. This command code is
3026 # repo to the caller to avoid deadlock with wlock. This command code is
3012 # responsability for this locking.
3027 # responsability for this locking.
3013 lock = repo.lock()
3028 lock = repo.lock()
3014 try:
3029 try:
3015 q.finish(repo, revs)
3030 q.finish(repo, revs)
3016 q.savedirty()
3031 q.savedirty()
3017 finally:
3032 finally:
3018 lock.release()
3033 lock.release()
3019 return 0
3034 return 0
3020
3035
3021 @command("qqueue",
3036 @command("qqueue",
3022 [('l', 'list', False, _('list all available queues')),
3037 [('l', 'list', False, _('list all available queues')),
3023 ('', 'active', False, _('print name of active queue')),
3038 ('', 'active', False, _('print name of active queue')),
3024 ('c', 'create', False, _('create new queue')),
3039 ('c', 'create', False, _('create new queue')),
3025 ('', 'rename', False, _('rename active queue')),
3040 ('', 'rename', False, _('rename active queue')),
3026 ('', 'delete', False, _('delete reference to queue')),
3041 ('', 'delete', False, _('delete reference to queue')),
3027 ('', 'purge', False, _('delete queue, and remove patch dir')),
3042 ('', 'purge', False, _('delete queue, and remove patch dir')),
3028 ],
3043 ],
3029 _('[OPTION] [QUEUE]'))
3044 _('[OPTION] [QUEUE]'))
3030 def qqueue(ui, repo, name=None, **opts):
3045 def qqueue(ui, repo, name=None, **opts):
3031 '''manage multiple patch queues
3046 '''manage multiple patch queues
3032
3047
3033 Supports switching between different patch queues, as well as creating
3048 Supports switching between different patch queues, as well as creating
3034 new patch queues and deleting existing ones.
3049 new patch queues and deleting existing ones.
3035
3050
3036 Omitting a queue name or specifying -l/--list will show you the registered
3051 Omitting a queue name or specifying -l/--list will show you the registered
3037 queues - by default the "normal" patches queue is registered. The currently
3052 queues - by default the "normal" patches queue is registered. The currently
3038 active queue will be marked with "(active)". Specifying --active will print
3053 active queue will be marked with "(active)". Specifying --active will print
3039 only the name of the active queue.
3054 only the name of the active queue.
3040
3055
3041 To create a new queue, use -c/--create. The queue is automatically made
3056 To create a new queue, use -c/--create. The queue is automatically made
3042 active, except in the case where there are applied patches from the
3057 active, except in the case where there are applied patches from the
3043 currently active queue in the repository. Then the queue will only be
3058 currently active queue in the repository. Then the queue will only be
3044 created and switching will fail.
3059 created and switching will fail.
3045
3060
3046 To delete an existing queue, use --delete. You cannot delete the currently
3061 To delete an existing queue, use --delete. You cannot delete the currently
3047 active queue.
3062 active queue.
3048
3063
3049 Returns 0 on success.
3064 Returns 0 on success.
3050 '''
3065 '''
3051 q = repo.mq
3066 q = repo.mq
3052 _defaultqueue = 'patches'
3067 _defaultqueue = 'patches'
3053 _allqueues = 'patches.queues'
3068 _allqueues = 'patches.queues'
3054 _activequeue = 'patches.queue'
3069 _activequeue = 'patches.queue'
3055
3070
3056 def _getcurrent():
3071 def _getcurrent():
3057 cur = os.path.basename(q.path)
3072 cur = os.path.basename(q.path)
3058 if cur.startswith('patches-'):
3073 if cur.startswith('patches-'):
3059 cur = cur[8:]
3074 cur = cur[8:]
3060 return cur
3075 return cur
3061
3076
3062 def _noqueues():
3077 def _noqueues():
3063 try:
3078 try:
3064 fh = repo.opener(_allqueues, 'r')
3079 fh = repo.opener(_allqueues, 'r')
3065 fh.close()
3080 fh.close()
3066 except IOError:
3081 except IOError:
3067 return True
3082 return True
3068
3083
3069 return False
3084 return False
3070
3085
3071 def _getqueues():
3086 def _getqueues():
3072 current = _getcurrent()
3087 current = _getcurrent()
3073
3088
3074 try:
3089 try:
3075 fh = repo.opener(_allqueues, 'r')
3090 fh = repo.opener(_allqueues, 'r')
3076 queues = [queue.strip() for queue in fh if queue.strip()]
3091 queues = [queue.strip() for queue in fh if queue.strip()]
3077 fh.close()
3092 fh.close()
3078 if current not in queues:
3093 if current not in queues:
3079 queues.append(current)
3094 queues.append(current)
3080 except IOError:
3095 except IOError:
3081 queues = [_defaultqueue]
3096 queues = [_defaultqueue]
3082
3097
3083 return sorted(queues)
3098 return sorted(queues)
3084
3099
3085 def _setactive(name):
3100 def _setactive(name):
3086 if q.applied:
3101 if q.applied:
3087 raise util.Abort(_('patches applied - cannot set new queue active'))
3102 raise util.Abort(_('patches applied - cannot set new queue active'))
3088 _setactivenocheck(name)
3103 _setactivenocheck(name)
3089
3104
3090 def _setactivenocheck(name):
3105 def _setactivenocheck(name):
3091 fh = repo.opener(_activequeue, 'w')
3106 fh = repo.opener(_activequeue, 'w')
3092 if name != 'patches':
3107 if name != 'patches':
3093 fh.write(name)
3108 fh.write(name)
3094 fh.close()
3109 fh.close()
3095
3110
3096 def _addqueue(name):
3111 def _addqueue(name):
3097 fh = repo.opener(_allqueues, 'a')
3112 fh = repo.opener(_allqueues, 'a')
3098 fh.write('%s\n' % (name,))
3113 fh.write('%s\n' % (name,))
3099 fh.close()
3114 fh.close()
3100
3115
3101 def _queuedir(name):
3116 def _queuedir(name):
3102 if name == 'patches':
3117 if name == 'patches':
3103 return repo.join('patches')
3118 return repo.join('patches')
3104 else:
3119 else:
3105 return repo.join('patches-' + name)
3120 return repo.join('patches-' + name)
3106
3121
3107 def _validname(name):
3122 def _validname(name):
3108 for n in name:
3123 for n in name:
3109 if n in ':\\/.':
3124 if n in ':\\/.':
3110 return False
3125 return False
3111 return True
3126 return True
3112
3127
3113 def _delete(name):
3128 def _delete(name):
3114 if name not in existing:
3129 if name not in existing:
3115 raise util.Abort(_('cannot delete queue that does not exist'))
3130 raise util.Abort(_('cannot delete queue that does not exist'))
3116
3131
3117 current = _getcurrent()
3132 current = _getcurrent()
3118
3133
3119 if name == current:
3134 if name == current:
3120 raise util.Abort(_('cannot delete currently active queue'))
3135 raise util.Abort(_('cannot delete currently active queue'))
3121
3136
3122 fh = repo.opener('patches.queues.new', 'w')
3137 fh = repo.opener('patches.queues.new', 'w')
3123 for queue in existing:
3138 for queue in existing:
3124 if queue == name:
3139 if queue == name:
3125 continue
3140 continue
3126 fh.write('%s\n' % (queue,))
3141 fh.write('%s\n' % (queue,))
3127 fh.close()
3142 fh.close()
3128 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3143 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3129
3144
3130 if not name or opts.get('list') or opts.get('active'):
3145 if not name or opts.get('list') or opts.get('active'):
3131 current = _getcurrent()
3146 current = _getcurrent()
3132 if opts.get('active'):
3147 if opts.get('active'):
3133 ui.write('%s\n' % (current,))
3148 ui.write('%s\n' % (current,))
3134 return
3149 return
3135 for queue in _getqueues():
3150 for queue in _getqueues():
3136 ui.write('%s' % (queue,))
3151 ui.write('%s' % (queue,))
3137 if queue == current and not ui.quiet:
3152 if queue == current and not ui.quiet:
3138 ui.write(_(' (active)\n'))
3153 ui.write(_(' (active)\n'))
3139 else:
3154 else:
3140 ui.write('\n')
3155 ui.write('\n')
3141 return
3156 return
3142
3157
3143 if not _validname(name):
3158 if not _validname(name):
3144 raise util.Abort(
3159 raise util.Abort(
3145 _('invalid queue name, may not contain the characters ":\\/."'))
3160 _('invalid queue name, may not contain the characters ":\\/."'))
3146
3161
3147 existing = _getqueues()
3162 existing = _getqueues()
3148
3163
3149 if opts.get('create'):
3164 if opts.get('create'):
3150 if name in existing:
3165 if name in existing:
3151 raise util.Abort(_('queue "%s" already exists') % name)
3166 raise util.Abort(_('queue "%s" already exists') % name)
3152 if _noqueues():
3167 if _noqueues():
3153 _addqueue(_defaultqueue)
3168 _addqueue(_defaultqueue)
3154 _addqueue(name)
3169 _addqueue(name)
3155 _setactive(name)
3170 _setactive(name)
3156 elif opts.get('rename'):
3171 elif opts.get('rename'):
3157 current = _getcurrent()
3172 current = _getcurrent()
3158 if name == current:
3173 if name == current:
3159 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3174 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3160 if name in existing:
3175 if name in existing:
3161 raise util.Abort(_('queue "%s" already exists') % name)
3176 raise util.Abort(_('queue "%s" already exists') % name)
3162
3177
3163 olddir = _queuedir(current)
3178 olddir = _queuedir(current)
3164 newdir = _queuedir(name)
3179 newdir = _queuedir(name)
3165
3180
3166 if os.path.exists(newdir):
3181 if os.path.exists(newdir):
3167 raise util.Abort(_('non-queue directory "%s" already exists') %
3182 raise util.Abort(_('non-queue directory "%s" already exists') %
3168 newdir)
3183 newdir)
3169
3184
3170 fh = repo.opener('patches.queues.new', 'w')
3185 fh = repo.opener('patches.queues.new', 'w')
3171 for queue in existing:
3186 for queue in existing:
3172 if queue == current:
3187 if queue == current:
3173 fh.write('%s\n' % (name,))
3188 fh.write('%s\n' % (name,))
3174 if os.path.exists(olddir):
3189 if os.path.exists(olddir):
3175 util.rename(olddir, newdir)
3190 util.rename(olddir, newdir)
3176 else:
3191 else:
3177 fh.write('%s\n' % (queue,))
3192 fh.write('%s\n' % (queue,))
3178 fh.close()
3193 fh.close()
3179 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3194 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3180 _setactivenocheck(name)
3195 _setactivenocheck(name)
3181 elif opts.get('delete'):
3196 elif opts.get('delete'):
3182 _delete(name)
3197 _delete(name)
3183 elif opts.get('purge'):
3198 elif opts.get('purge'):
3184 if name in existing:
3199 if name in existing:
3185 _delete(name)
3200 _delete(name)
3186 qdir = _queuedir(name)
3201 qdir = _queuedir(name)
3187 if os.path.exists(qdir):
3202 if os.path.exists(qdir):
3188 shutil.rmtree(qdir)
3203 shutil.rmtree(qdir)
3189 else:
3204 else:
3190 if name not in existing:
3205 if name not in existing:
3191 raise util.Abort(_('use --create to create a new queue'))
3206 raise util.Abort(_('use --create to create a new queue'))
3192 _setactive(name)
3207 _setactive(name)
3193
3208
3194 def mqphasedefaults(repo, roots):
3209 def mqphasedefaults(repo, roots):
3195 """callback used to set mq changeset as secret when no phase data exists"""
3210 """callback used to set mq changeset as secret when no phase data exists"""
3196 if repo.mq.applied:
3211 if repo.mq.applied:
3197 if repo.ui.configbool('mq', 'secret', False):
3212 if repo.ui.configbool('mq', 'secret', False):
3198 mqphase = phases.secret
3213 mqphase = phases.secret
3199 else:
3214 else:
3200 mqphase = phases.draft
3215 mqphase = phases.draft
3201 qbase = repo[repo.mq.applied[0].node]
3216 qbase = repo[repo.mq.applied[0].node]
3202 roots[mqphase].add(qbase.node())
3217 roots[mqphase].add(qbase.node())
3203 return roots
3218 return roots
3204
3219
3205 def reposetup(ui, repo):
3220 def reposetup(ui, repo):
3206 class mqrepo(repo.__class__):
3221 class mqrepo(repo.__class__):
3207 @util.propertycache
3222 @util.propertycache
3208 def mq(self):
3223 def mq(self):
3209 return queue(self.ui, self.path)
3224 return queue(self.ui, self.path)
3210
3225
3211 def abortifwdirpatched(self, errmsg, force=False):
3226 def abortifwdirpatched(self, errmsg, force=False):
3212 if self.mq.applied and not force:
3227 if self.mq.applied and not force:
3213 parents = self.dirstate.parents()
3228 parents = self.dirstate.parents()
3214 patches = [s.node for s in self.mq.applied]
3229 patches = [s.node for s in self.mq.applied]
3215 if parents[0] in patches or parents[1] in patches:
3230 if parents[0] in patches or parents[1] in patches:
3216 raise util.Abort(errmsg)
3231 raise util.Abort(errmsg)
3217
3232
3218 def commit(self, text="", user=None, date=None, match=None,
3233 def commit(self, text="", user=None, date=None, match=None,
3219 force=False, editor=False, extra={}):
3234 force=False, editor=False, extra={}):
3220 self.abortifwdirpatched(
3235 self.abortifwdirpatched(
3221 _('cannot commit over an applied mq patch'),
3236 _('cannot commit over an applied mq patch'),
3222 force)
3237 force)
3223
3238
3224 return super(mqrepo, self).commit(text, user, date, match, force,
3239 return super(mqrepo, self).commit(text, user, date, match, force,
3225 editor, extra)
3240 editor, extra)
3226
3241
3227 def checkpush(self, force, revs):
3242 def checkpush(self, force, revs):
3228 if self.mq.applied and not force:
3243 if self.mq.applied and not force:
3229 outapplied = [e.node for e in self.mq.applied]
3244 outapplied = [e.node for e in self.mq.applied]
3230 if revs:
3245 if revs:
3231 # Assume applied patches have no non-patch descendants and
3246 # Assume applied patches have no non-patch descendants and
3232 # are not on remote already. Filtering any changeset not
3247 # are not on remote already. Filtering any changeset not
3233 # pushed.
3248 # pushed.
3234 heads = set(revs)
3249 heads = set(revs)
3235 for node in reversed(outapplied):
3250 for node in reversed(outapplied):
3236 if node in heads:
3251 if node in heads:
3237 break
3252 break
3238 else:
3253 else:
3239 outapplied.pop()
3254 outapplied.pop()
3240 # looking for pushed and shared changeset
3255 # looking for pushed and shared changeset
3241 for node in outapplied:
3256 for node in outapplied:
3242 if repo[node].phase() < phases.secret:
3257 if repo[node].phase() < phases.secret:
3243 raise util.Abort(_('source has mq patches applied'))
3258 raise util.Abort(_('source has mq patches applied'))
3244 # no non-secret patches pushed
3259 # no non-secret patches pushed
3245 super(mqrepo, self).checkpush(force, revs)
3260 super(mqrepo, self).checkpush(force, revs)
3246
3261
3247 def _findtags(self):
3262 def _findtags(self):
3248 '''augment tags from base class with patch tags'''
3263 '''augment tags from base class with patch tags'''
3249 result = super(mqrepo, self)._findtags()
3264 result = super(mqrepo, self)._findtags()
3250
3265
3251 q = self.mq
3266 q = self.mq
3252 if not q.applied:
3267 if not q.applied:
3253 return result
3268 return result
3254
3269
3255 mqtags = [(patch.node, patch.name) for patch in q.applied]
3270 mqtags = [(patch.node, patch.name) for patch in q.applied]
3256
3271
3257 try:
3272 try:
3258 self.changelog.rev(mqtags[-1][0])
3273 self.changelog.rev(mqtags[-1][0])
3259 except error.LookupError:
3274 except error.LookupError:
3260 self.ui.warn(_('mq status file refers to unknown node %s\n')
3275 self.ui.warn(_('mq status file refers to unknown node %s\n')
3261 % short(mqtags[-1][0]))
3276 % short(mqtags[-1][0]))
3262 return result
3277 return result
3263
3278
3264 mqtags.append((mqtags[-1][0], 'qtip'))
3279 mqtags.append((mqtags[-1][0], 'qtip'))
3265 mqtags.append((mqtags[0][0], 'qbase'))
3280 mqtags.append((mqtags[0][0], 'qbase'))
3266 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3281 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3267 tags = result[0]
3282 tags = result[0]
3268 for patch in mqtags:
3283 for patch in mqtags:
3269 if patch[1] in tags:
3284 if patch[1] in tags:
3270 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
3285 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
3271 % patch[1])
3286 % patch[1])
3272 else:
3287 else:
3273 tags[patch[1]] = patch[0]
3288 tags[patch[1]] = patch[0]
3274
3289
3275 return result
3290 return result
3276
3291
3277 def _branchtags(self, partial, lrev):
3292 def _branchtags(self, partial, lrev):
3278 q = self.mq
3293 q = self.mq
3279 cl = self.changelog
3294 cl = self.changelog
3280 qbase = None
3295 qbase = None
3281 if not q.applied:
3296 if not q.applied:
3282 if getattr(self, '_committingpatch', False):
3297 if getattr(self, '_committingpatch', False):
3283 # Committing a new patch, must be tip
3298 # Committing a new patch, must be tip
3284 qbase = len(cl) - 1
3299 qbase = len(cl) - 1
3285 else:
3300 else:
3286 qbasenode = q.applied[0].node
3301 qbasenode = q.applied[0].node
3287 try:
3302 try:
3288 qbase = cl.rev(qbasenode)
3303 qbase = cl.rev(qbasenode)
3289 except error.LookupError:
3304 except error.LookupError:
3290 self.ui.warn(_('mq status file refers to unknown node %s\n')
3305 self.ui.warn(_('mq status file refers to unknown node %s\n')
3291 % short(qbasenode))
3306 % short(qbasenode))
3292 if qbase is None:
3307 if qbase is None:
3293 return super(mqrepo, self)._branchtags(partial, lrev)
3308 return super(mqrepo, self)._branchtags(partial, lrev)
3294
3309
3295 start = lrev + 1
3310 start = lrev + 1
3296 if start < qbase:
3311 if start < qbase:
3297 # update the cache (excluding the patches) and save it
3312 # update the cache (excluding the patches) and save it
3298 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
3313 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
3299 self._updatebranchcache(partial, ctxgen)
3314 self._updatebranchcache(partial, ctxgen)
3300 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
3315 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
3301 start = qbase
3316 start = qbase
3302 # if start = qbase, the cache is as updated as it should be.
3317 # if start = qbase, the cache is as updated as it should be.
3303 # if start > qbase, the cache includes (part of) the patches.
3318 # if start > qbase, the cache includes (part of) the patches.
3304 # we might as well use it, but we won't save it.
3319 # we might as well use it, but we won't save it.
3305
3320
3306 # update the cache up to the tip
3321 # update the cache up to the tip
3307 ctxgen = (self[r] for r in xrange(start, len(cl)))
3322 ctxgen = (self[r] for r in xrange(start, len(cl)))
3308 self._updatebranchcache(partial, ctxgen)
3323 self._updatebranchcache(partial, ctxgen)
3309
3324
3310 return partial
3325 return partial
3311
3326
3312 if repo.local():
3327 if repo.local():
3313 repo.__class__ = mqrepo
3328 repo.__class__ = mqrepo
3314
3329
3315 repo._phasedefaults.append(mqphasedefaults)
3330 repo._phasedefaults.append(mqphasedefaults)
3316
3331
3317 def mqimport(orig, ui, repo, *args, **kwargs):
3332 def mqimport(orig, ui, repo, *args, **kwargs):
3318 if (util.safehasattr(repo, 'abortifwdirpatched')
3333 if (util.safehasattr(repo, 'abortifwdirpatched')
3319 and not kwargs.get('no_commit', False)):
3334 and not kwargs.get('no_commit', False)):
3320 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3335 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3321 kwargs.get('force'))
3336 kwargs.get('force'))
3322 return orig(ui, repo, *args, **kwargs)
3337 return orig(ui, repo, *args, **kwargs)
3323
3338
3324 def mqinit(orig, ui, *args, **kwargs):
3339 def mqinit(orig, ui, *args, **kwargs):
3325 mq = kwargs.pop('mq', None)
3340 mq = kwargs.pop('mq', None)
3326
3341
3327 if not mq:
3342 if not mq:
3328 return orig(ui, *args, **kwargs)
3343 return orig(ui, *args, **kwargs)
3329
3344
3330 if args:
3345 if args:
3331 repopath = args[0]
3346 repopath = args[0]
3332 if not hg.islocal(repopath):
3347 if not hg.islocal(repopath):
3333 raise util.Abort(_('only a local queue repository '
3348 raise util.Abort(_('only a local queue repository '
3334 'may be initialized'))
3349 'may be initialized'))
3335 else:
3350 else:
3336 repopath = cmdutil.findrepo(os.getcwd())
3351 repopath = cmdutil.findrepo(os.getcwd())
3337 if not repopath:
3352 if not repopath:
3338 raise util.Abort(_('there is no Mercurial repository here '
3353 raise util.Abort(_('there is no Mercurial repository here '
3339 '(.hg not found)'))
3354 '(.hg not found)'))
3340 repo = hg.repository(ui, repopath)
3355 repo = hg.repository(ui, repopath)
3341 return qinit(ui, repo, True)
3356 return qinit(ui, repo, True)
3342
3357
3343 def mqcommand(orig, ui, repo, *args, **kwargs):
3358 def mqcommand(orig, ui, repo, *args, **kwargs):
3344 """Add --mq option to operate on patch repository instead of main"""
3359 """Add --mq option to operate on patch repository instead of main"""
3345
3360
3346 # some commands do not like getting unknown options
3361 # some commands do not like getting unknown options
3347 mq = kwargs.pop('mq', None)
3362 mq = kwargs.pop('mq', None)
3348
3363
3349 if not mq:
3364 if not mq:
3350 return orig(ui, repo, *args, **kwargs)
3365 return orig(ui, repo, *args, **kwargs)
3351
3366
3352 q = repo.mq
3367 q = repo.mq
3353 r = q.qrepo()
3368 r = q.qrepo()
3354 if not r:
3369 if not r:
3355 raise util.Abort(_('no queue repository'))
3370 raise util.Abort(_('no queue repository'))
3356 return orig(r.ui, r, *args, **kwargs)
3371 return orig(r.ui, r, *args, **kwargs)
3357
3372
3358 def summary(orig, ui, repo, *args, **kwargs):
3373 def summary(orig, ui, repo, *args, **kwargs):
3359 r = orig(ui, repo, *args, **kwargs)
3374 r = orig(ui, repo, *args, **kwargs)
3360 q = repo.mq
3375 q = repo.mq
3361 m = []
3376 m = []
3362 a, u = len(q.applied), len(q.unapplied(repo))
3377 a, u = len(q.applied), len(q.unapplied(repo))
3363 if a:
3378 if a:
3364 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3379 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3365 if u:
3380 if u:
3366 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3381 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3367 if m:
3382 if m:
3368 ui.write("mq: %s\n" % ', '.join(m))
3383 ui.write("mq: %s\n" % ', '.join(m))
3369 else:
3384 else:
3370 ui.note(_("mq: (empty queue)\n"))
3385 ui.note(_("mq: (empty queue)\n"))
3371 return r
3386 return r
3372
3387
3373 def revsetmq(repo, subset, x):
3388 def revsetmq(repo, subset, x):
3374 """``mq()``
3389 """``mq()``
3375 Changesets managed by MQ.
3390 Changesets managed by MQ.
3376 """
3391 """
3377 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3392 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3378 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3393 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3379 return [r for r in subset if r in applied]
3394 return [r for r in subset if r in applied]
3380
3395
3381 def extsetup(ui):
3396 def extsetup(ui):
3382 revset.symbols['mq'] = revsetmq
3397 revset.symbols['mq'] = revsetmq
3383
3398
3384 # tell hggettext to extract docstrings from these functions:
3399 # tell hggettext to extract docstrings from these functions:
3385 i18nfunctions = [revsetmq]
3400 i18nfunctions = [revsetmq]
3386
3401
3387 def uisetup(ui):
3402 def uisetup(ui):
3388 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3403 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3389
3404
3390 extensions.wrapcommand(commands.table, 'import', mqimport)
3405 extensions.wrapcommand(commands.table, 'import', mqimport)
3391 extensions.wrapcommand(commands.table, 'summary', summary)
3406 extensions.wrapcommand(commands.table, 'summary', summary)
3392
3407
3393 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3408 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3394 entry[1].extend(mqopt)
3409 entry[1].extend(mqopt)
3395
3410
3396 nowrap = set(commands.norepo.split(" "))
3411 nowrap = set(commands.norepo.split(" "))
3397
3412
3398 def dotable(cmdtable):
3413 def dotable(cmdtable):
3399 for cmd in cmdtable.keys():
3414 for cmd in cmdtable.keys():
3400 cmd = cmdutil.parsealiases(cmd)[0]
3415 cmd = cmdutil.parsealiases(cmd)[0]
3401 if cmd in nowrap:
3416 if cmd in nowrap:
3402 continue
3417 continue
3403 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3418 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3404 entry[1].extend(mqopt)
3419 entry[1].extend(mqopt)
3405
3420
3406 dotable(commands.table)
3421 dotable(commands.table)
3407
3422
3408 for extname, extmodule in extensions.extensions():
3423 for extname, extmodule in extensions.extensions():
3409 if extmodule.__file__ != __file__:
3424 if extmodule.__file__ != __file__:
3410 dotable(getattr(extmodule, 'cmdtable', {}))
3425 dotable(getattr(extmodule, 'cmdtable', {}))
3411
3426
3412
3427
3413 colortable = {'qguard.negative': 'red',
3428 colortable = {'qguard.negative': 'red',
3414 'qguard.positive': 'yellow',
3429 'qguard.positive': 'yellow',
3415 'qguard.unguarded': 'green',
3430 'qguard.unguarded': 'green',
3416 'qseries.applied': 'blue bold underline',
3431 'qseries.applied': 'blue bold underline',
3417 'qseries.guarded': 'black bold',
3432 'qseries.guarded': 'black bold',
3418 'qseries.missing': 'red bold',
3433 'qseries.missing': 'red bold',
3419 'qseries.unapplied': 'black bold'}
3434 'qseries.unapplied': 'black bold'}
@@ -1,152 +1,190 b''
1 Test that qpush cleans things up if it doesn't complete
1 Test that qpush cleans things up if it doesn't complete
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ echo foo > foo
7 $ echo foo > foo
8 $ hg ci -Am 'add foo'
8 $ hg ci -Am 'add foo'
9 adding foo
9 adding foo
10 $ touch untracked-file
10 $ touch untracked-file
11 $ echo 'syntax: glob' > .hgignore
11 $ echo 'syntax: glob' > .hgignore
12 $ echo '.hgignore' >> .hgignore
12 $ echo '.hgignore' >> .hgignore
13 $ hg qinit
13 $ hg qinit
14
14
15 test qpush on empty series
15 test qpush on empty series
16
16
17 $ hg qpush
17 $ hg qpush
18 no patches in series
18 no patches in series
19 $ hg qnew patch1
19 $ hg qnew patch1
20 $ echo >> foo
20 $ echo >> foo
21 $ hg qrefresh -m 'patch 1'
21 $ hg qrefresh -m 'patch 1'
22 $ hg qnew patch2
22 $ hg qnew patch2
23 $ echo bar > bar
23 $ echo bar > bar
24 $ hg add bar
24 $ hg add bar
25 $ hg qrefresh -m 'patch 2'
25 $ hg qrefresh -m 'patch 2'
26 $ hg qnew --config 'mq.plain=true' bad-patch
26 $ hg qnew --config 'mq.plain=true' bad-patch
27 $ echo >> foo
27 $ echo >> foo
28 $ hg qrefresh
28 $ hg qrefresh
29 $ hg qpop -a
29 $ hg qpop -a
30 popping bad-patch
30 popping bad-patch
31 popping patch2
31 popping patch2
32 popping patch1
32 popping patch1
33 patch queue now empty
33 patch queue now empty
34 $ python -c 'print "\xe9"' > message
34 $ python -c 'print "\xe9"' > message
35 $ cat .hg/patches/bad-patch >> message
35 $ cat .hg/patches/bad-patch >> message
36 $ mv message .hg/patches/bad-patch
36 $ mv message .hg/patches/bad-patch
37 $ hg qpush -a && echo 'qpush succeded?!'
37 $ hg qpush -a && echo 'qpush succeded?!'
38 applying patch1
38 applying patch1
39 applying patch2
39 applying patch2
40 applying bad-patch
40 applying bad-patch
41 transaction abort!
41 transaction abort!
42 rollback completed
42 rollback completed
43 cleaning up working directory...done
43 cleaning up working directory...done
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
45 [255]
45 [255]
46 $ hg parents
46 $ hg parents
47 changeset: 0:bbd179dfa0a7
47 changeset: 0:bbd179dfa0a7
48 tag: tip
48 tag: tip
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:00 1970 +0000
50 date: Thu Jan 01 00:00:00 1970 +0000
51 summary: add foo
51 summary: add foo
52
52
53
53
54 test corrupt status file
54 test corrupt status file
55 $ hg qpush
55 $ hg qpush
56 applying patch1
56 applying patch1
57 now at: patch1
57 now at: patch1
58 $ cp .hg/patches/status .hg/patches/status.orig
58 $ cp .hg/patches/status .hg/patches/status.orig
59 $ hg qpop
59 $ hg qpop
60 popping patch1
60 popping patch1
61 patch queue now empty
61 patch queue now empty
62 $ cp .hg/patches/status.orig .hg/patches/status
62 $ cp .hg/patches/status.orig .hg/patches/status
63 $ hg qpush
63 $ hg qpush
64 mq status file refers to unknown node * (glob)
64 mq status file refers to unknown node * (glob)
65 abort: working directory revision is not qtip
65 abort: working directory revision is not qtip
66 [255]
66 [255]
67 $ rm .hg/patches/status .hg/patches/status.orig
67 $ rm .hg/patches/status .hg/patches/status.orig
68
68
69
69
70 bar should be gone; other unknown/ignored files should still be around
70 bar should be gone; other unknown/ignored files should still be around
71
71
72 $ hg status -A
72 $ hg status -A
73 ? untracked-file
73 ? untracked-file
74 I .hgignore
74 I .hgignore
75 C foo
75 C foo
76
76
77 preparing qpush of a missing patch
77 preparing qpush of a missing patch
78
78
79 $ hg qpop -a
79 $ hg qpop -a
80 no patches applied
80 no patches applied
81 $ hg qpush
81 $ hg qpush
82 applying patch1
82 applying patch1
83 now at: patch1
83 now at: patch1
84 $ rm .hg/patches/patch2
84 $ rm .hg/patches/patch2
85
85
86 now we expect the push to fail, but it should NOT complain about patch1
86 now we expect the push to fail, but it should NOT complain about patch1
87
87
88 $ hg qpush
88 $ hg qpush
89 applying patch2
89 applying patch2
90 unable to read patch2
90 unable to read patch2
91 now at: patch1
91 now at: patch1
92 [1]
92 [1]
93
93
94 preparing qpush of missing patch with no patch applied
94 preparing qpush of missing patch with no patch applied
95
95
96 $ hg qpop -a
96 $ hg qpop -a
97 popping patch1
97 popping patch1
98 patch queue now empty
98 patch queue now empty
99 $ rm .hg/patches/patch1
99 $ rm .hg/patches/patch1
100
100
101 qpush should fail the same way as below
101 qpush should fail the same way as below
102
102
103 $ hg qpush
103 $ hg qpush
104 applying patch1
104 applying patch1
105 unable to read patch1
105 unable to read patch1
106 [1]
106 [1]
107
107
108 Test qpush to a patch below the currently applied patch.
108 Test qpush to a patch below the currently applied patch.
109
109
110 $ hg qq -c guardedseriesorder
110 $ hg qq -c guardedseriesorder
111 $ hg qnew a
111 $ hg qnew a
112 $ hg qguard +block
112 $ hg qguard +block
113 $ hg qnew b
113 $ hg qnew b
114 $ hg qnew c
114 $ hg qnew c
115
115
116 $ hg qpop -a
116 $ hg qpop -a
117 popping c
117 popping c
118 popping b
118 popping b
119 popping a
119 popping a
120 patch queue now empty
120 patch queue now empty
121
121
122 try to push and pop while a is guarded
122 try to push and pop while a is guarded
123
123
124 $ hg qpush a
124 $ hg qpush a
125 cannot push 'a' - guarded by '+block'
125 cannot push 'a' - guarded by '+block'
126 [1]
126 [1]
127 $ hg qpush -a
127 $ hg qpush -a
128 applying b
128 applying b
129 patch b is empty
129 patch b is empty
130 applying c
130 applying c
131 patch c is empty
131 patch c is empty
132 now at: c
132 now at: c
133
133
134 now try it when a is unguarded, and we're at the top of the queue
134 now try it when a is unguarded, and we're at the top of the queue
135 $ hg qsel block
135 $ hg qsel block
136 number of guarded, applied patches has changed from 1 to 0
136 number of guarded, applied patches has changed from 1 to 0
137 $ hg qpush b
137 $ hg qpush b
138 abort: cannot push to a previous patch: b
138 abort: cannot push to a previous patch: b
139 [255]
139 [255]
140 $ hg qpush a
140 $ hg qpush a
141 abort: cannot push to a previous patch: a
141 abort: cannot push to a previous patch: a
142 [255]
142 [255]
143
143
144 and now we try it one more time with a unguarded, while we're not at the top of the queue
144 and now we try it one more time with a unguarded, while we're not at the top of the queue
145
145
146 $ hg qpop b
146 $ hg qpop b
147 popping c
147 popping c
148 now at: b
148 now at: b
149 $ hg qpush a
149 $ hg qpush a
150 abort: cannot push to a previous patch: a
150 abort: cannot push to a previous patch: a
151 [255]
151 [255]
152
152
153 test qpop --force and backup files
154
155 $ hg qpop -a
156 popping b
157 patch queue now empty
158 $ hg qq --create force
159 $ echo a > a
160 $ echo b > b
161 $ echo c > c
162 $ hg ci -Am add a b c
163 $ echo a >> a
164 $ hg rm b
165 $ hg rm c
166 $ hg qnew p1
167 $ echo a >> a
168 $ echo bb > b
169 $ hg add b
170 $ echo cc > c
171 $ hg add c
172 $ hg qpop --force --verbose
173 saving current version of a as a.orig
174 saving current version of b as b.orig
175 saving current version of c as c.orig
176 popping p1
177 patch queue now empty
178 $ hg st
179 ? a.orig
180 ? b.orig
181 ? c.orig
182 ? untracked-file
183 $ cat a.orig
184 a
185 a
186 a
187 $ cat b.orig
188 bb
189 $ cat c.orig
190 cc
General Comments 0
You need to be logged in to leave comments. Login now