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