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