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