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