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