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