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