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