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