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