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