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