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