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