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