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