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