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