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