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