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