##// END OF EJS Templates
qseries: don't truncate the patch name (issue1912)...
Dan Villiom Podlaski Christiansen -
r9874:c51494c5 stable
parent child Browse files
Show More
@@ -1,2698 +1,2701
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 and ph.message[0] or ''
1388 msg = msg and ': ' + msg[0] or ': '
1388 if self.ui.interactive():
1389 width = util.termwidth() - len(pfx) - len(patchname) - 2
1390 if width > 0:
1391 msg = util.ellipsis(msg, width)
1389 else:
1392 else:
1390 msg = ''
1393 msg = ''
1391 msg = "%s%s%s" % (pfx, patchname, msg)
1394 msg = "%s%s: %s" % (pfx, patchname, msg)
1392 if self.ui.interactive():
1395 else:
1393 msg = util.ellipsis(msg, util.termwidth())
1396 msg = pfx + patchname
1394 self.ui.write(msg + '\n')
1397 self.ui.write(msg + '\n')
1395
1398
1396 applied = set([p.name for p in self.applied])
1399 applied = set([p.name for p in self.applied])
1397 if length is None:
1400 if length is None:
1398 length = len(self.series) - start
1401 length = len(self.series) - start
1399 if not missing:
1402 if not missing:
1400 if self.ui.verbose:
1403 if self.ui.verbose:
1401 idxwidth = len(str(start+length - 1))
1404 idxwidth = len(str(start+length - 1))
1402 for i in xrange(start, start+length):
1405 for i in xrange(start, start+length):
1403 patch = self.series[i]
1406 patch = self.series[i]
1404 if patch in applied:
1407 if patch in applied:
1405 stat = 'A'
1408 stat = 'A'
1406 elif self.pushable(i)[0]:
1409 elif self.pushable(i)[0]:
1407 stat = 'U'
1410 stat = 'U'
1408 else:
1411 else:
1409 stat = 'G'
1412 stat = 'G'
1410 pfx = ''
1413 pfx = ''
1411 if self.ui.verbose:
1414 if self.ui.verbose:
1412 pfx = '%*d %s ' % (idxwidth, i, stat)
1415 pfx = '%*d %s ' % (idxwidth, i, stat)
1413 elif status and status != stat:
1416 elif status and status != stat:
1414 continue
1417 continue
1415 displayname(pfx, patch)
1418 displayname(pfx, patch)
1416 else:
1419 else:
1417 msng_list = []
1420 msng_list = []
1418 for root, dirs, files in os.walk(self.path):
1421 for root, dirs, files in os.walk(self.path):
1419 d = root[len(self.path) + 1:]
1422 d = root[len(self.path) + 1:]
1420 for f in files:
1423 for f in files:
1421 fl = os.path.join(d, f)
1424 fl = os.path.join(d, f)
1422 if (fl not in self.series and
1425 if (fl not in self.series and
1423 fl not in (self.status_path, self.series_path,
1426 fl not in (self.status_path, self.series_path,
1424 self.guards_path)
1427 self.guards_path)
1425 and not fl.startswith('.')):
1428 and not fl.startswith('.')):
1426 msng_list.append(fl)
1429 msng_list.append(fl)
1427 for x in sorted(msng_list):
1430 for x in sorted(msng_list):
1428 pfx = self.ui.verbose and ('D ') or ''
1431 pfx = self.ui.verbose and ('D ') or ''
1429 displayname(pfx, x)
1432 displayname(pfx, x)
1430
1433
1431 def issaveline(self, l):
1434 def issaveline(self, l):
1432 if l.name == '.hg.patches.save.line':
1435 if l.name == '.hg.patches.save.line':
1433 return True
1436 return True
1434
1437
1435 def qrepo(self, create=False):
1438 def qrepo(self, create=False):
1436 if create or os.path.isdir(self.join(".hg")):
1439 if create or os.path.isdir(self.join(".hg")):
1437 return hg.repository(self.ui, path=self.path, create=create)
1440 return hg.repository(self.ui, path=self.path, create=create)
1438
1441
1439 def restore(self, repo, rev, delete=None, qupdate=None):
1442 def restore(self, repo, rev, delete=None, qupdate=None):
1440 c = repo.changelog.read(rev)
1443 c = repo.changelog.read(rev)
1441 desc = c[4].strip()
1444 desc = c[4].strip()
1442 lines = desc.splitlines()
1445 lines = desc.splitlines()
1443 i = 0
1446 i = 0
1444 datastart = None
1447 datastart = None
1445 series = []
1448 series = []
1446 applied = []
1449 applied = []
1447 qpp = None
1450 qpp = None
1448 for i, line in enumerate(lines):
1451 for i, line in enumerate(lines):
1449 if line == 'Patch Data:':
1452 if line == 'Patch Data:':
1450 datastart = i + 1
1453 datastart = i + 1
1451 elif line.startswith('Dirstate:'):
1454 elif line.startswith('Dirstate:'):
1452 l = line.rstrip()
1455 l = line.rstrip()
1453 l = l[10:].split(' ')
1456 l = l[10:].split(' ')
1454 qpp = [ bin(x) for x in l ]
1457 qpp = [ bin(x) for x in l ]
1455 elif datastart != None:
1458 elif datastart != None:
1456 l = line.rstrip()
1459 l = line.rstrip()
1457 se = statusentry(l)
1460 se = statusentry(l)
1458 file_ = se.name
1461 file_ = se.name
1459 if se.rev:
1462 if se.rev:
1460 applied.append(se)
1463 applied.append(se)
1461 else:
1464 else:
1462 series.append(file_)
1465 series.append(file_)
1463 if datastart is None:
1466 if datastart is None:
1464 self.ui.warn(_("No saved patch data found\n"))
1467 self.ui.warn(_("No saved patch data found\n"))
1465 return 1
1468 return 1
1466 self.ui.warn(_("restoring status: %s\n") % lines[0])
1469 self.ui.warn(_("restoring status: %s\n") % lines[0])
1467 self.full_series = series
1470 self.full_series = series
1468 self.applied = applied
1471 self.applied = applied
1469 self.parse_series()
1472 self.parse_series()
1470 self.series_dirty = 1
1473 self.series_dirty = 1
1471 self.applied_dirty = 1
1474 self.applied_dirty = 1
1472 heads = repo.changelog.heads()
1475 heads = repo.changelog.heads()
1473 if delete:
1476 if delete:
1474 if rev not in heads:
1477 if rev not in heads:
1475 self.ui.warn(_("save entry has children, leaving it alone\n"))
1478 self.ui.warn(_("save entry has children, leaving it alone\n"))
1476 else:
1479 else:
1477 self.ui.warn(_("removing save entry %s\n") % short(rev))
1480 self.ui.warn(_("removing save entry %s\n") % short(rev))
1478 pp = repo.dirstate.parents()
1481 pp = repo.dirstate.parents()
1479 if rev in pp:
1482 if rev in pp:
1480 update = True
1483 update = True
1481 else:
1484 else:
1482 update = False
1485 update = False
1483 self.strip(repo, rev, update=update, backup='strip')
1486 self.strip(repo, rev, update=update, backup='strip')
1484 if qpp:
1487 if qpp:
1485 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1488 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1486 (short(qpp[0]), short(qpp[1])))
1489 (short(qpp[0]), short(qpp[1])))
1487 if qupdate:
1490 if qupdate:
1488 self.ui.status(_("queue directory updating\n"))
1491 self.ui.status(_("queue directory updating\n"))
1489 r = self.qrepo()
1492 r = self.qrepo()
1490 if not r:
1493 if not r:
1491 self.ui.warn(_("Unable to load queue repository\n"))
1494 self.ui.warn(_("Unable to load queue repository\n"))
1492 return 1
1495 return 1
1493 hg.clean(r, qpp[0])
1496 hg.clean(r, qpp[0])
1494
1497
1495 def save(self, repo, msg=None):
1498 def save(self, repo, msg=None):
1496 if len(self.applied) == 0:
1499 if len(self.applied) == 0:
1497 self.ui.warn(_("save: no patches applied, exiting\n"))
1500 self.ui.warn(_("save: no patches applied, exiting\n"))
1498 return 1
1501 return 1
1499 if self.issaveline(self.applied[-1]):
1502 if self.issaveline(self.applied[-1]):
1500 self.ui.warn(_("status is already saved\n"))
1503 self.ui.warn(_("status is already saved\n"))
1501 return 1
1504 return 1
1502
1505
1503 ar = [ ':' + x for x in self.full_series ]
1506 ar = [ ':' + x for x in self.full_series ]
1504 if not msg:
1507 if not msg:
1505 msg = _("hg patches saved state")
1508 msg = _("hg patches saved state")
1506 else:
1509 else:
1507 msg = "hg patches: " + msg.rstrip('\r\n')
1510 msg = "hg patches: " + msg.rstrip('\r\n')
1508 r = self.qrepo()
1511 r = self.qrepo()
1509 if r:
1512 if r:
1510 pp = r.dirstate.parents()
1513 pp = r.dirstate.parents()
1511 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1514 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1512 msg += "\n\nPatch Data:\n"
1515 msg += "\n\nPatch Data:\n"
1513 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1516 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1514 "\n".join(ar) + '\n' or "")
1517 "\n".join(ar) + '\n' or "")
1515 n = repo.commit(text, force=True)
1518 n = repo.commit(text, force=True)
1516 if not n:
1519 if not n:
1517 self.ui.warn(_("repo commit failed\n"))
1520 self.ui.warn(_("repo commit failed\n"))
1518 return 1
1521 return 1
1519 self.applied.append(statusentry(hex(n),'.hg.patches.save.line'))
1522 self.applied.append(statusentry(hex(n),'.hg.patches.save.line'))
1520 self.applied_dirty = 1
1523 self.applied_dirty = 1
1521 self.removeundo(repo)
1524 self.removeundo(repo)
1522
1525
1523 def full_series_end(self):
1526 def full_series_end(self):
1524 if len(self.applied) > 0:
1527 if len(self.applied) > 0:
1525 p = self.applied[-1].name
1528 p = self.applied[-1].name
1526 end = self.find_series(p)
1529 end = self.find_series(p)
1527 if end is None:
1530 if end is None:
1528 return len(self.full_series)
1531 return len(self.full_series)
1529 return end + 1
1532 return end + 1
1530 return 0
1533 return 0
1531
1534
1532 def series_end(self, all_patches=False):
1535 def series_end(self, all_patches=False):
1533 """If all_patches is False, return the index of the next pushable patch
1536 """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
1537 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.
1538 index of the first patch past the last applied one.
1536 """
1539 """
1537 end = 0
1540 end = 0
1538 def next(start):
1541 def next(start):
1539 if all_patches:
1542 if all_patches:
1540 return start
1543 return start
1541 i = start
1544 i = start
1542 while i < len(self.series):
1545 while i < len(self.series):
1543 p, reason = self.pushable(i)
1546 p, reason = self.pushable(i)
1544 if p:
1547 if p:
1545 break
1548 break
1546 self.explain_pushable(i)
1549 self.explain_pushable(i)
1547 i += 1
1550 i += 1
1548 return i
1551 return i
1549 if len(self.applied) > 0:
1552 if len(self.applied) > 0:
1550 p = self.applied[-1].name
1553 p = self.applied[-1].name
1551 try:
1554 try:
1552 end = self.series.index(p)
1555 end = self.series.index(p)
1553 except ValueError:
1556 except ValueError:
1554 return 0
1557 return 0
1555 return next(end + 1)
1558 return next(end + 1)
1556 return next(end)
1559 return next(end)
1557
1560
1558 def appliedname(self, index):
1561 def appliedname(self, index):
1559 pname = self.applied[index].name
1562 pname = self.applied[index].name
1560 if not self.ui.verbose:
1563 if not self.ui.verbose:
1561 p = pname
1564 p = pname
1562 else:
1565 else:
1563 p = str(self.series.index(pname)) + " " + pname
1566 p = str(self.series.index(pname)) + " " + pname
1564 return p
1567 return p
1565
1568
1566 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1569 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1567 force=None, git=False):
1570 force=None, git=False):
1568 def checkseries(patchname):
1571 def checkseries(patchname):
1569 if patchname in self.series:
1572 if patchname in self.series:
1570 raise util.Abort(_('patch %s is already in the series file')
1573 raise util.Abort(_('patch %s is already in the series file')
1571 % patchname)
1574 % patchname)
1572 def checkfile(patchname):
1575 def checkfile(patchname):
1573 if not force and os.path.exists(self.join(patchname)):
1576 if not force and os.path.exists(self.join(patchname)):
1574 raise util.Abort(_('patch "%s" already exists')
1577 raise util.Abort(_('patch "%s" already exists')
1575 % patchname)
1578 % patchname)
1576
1579
1577 if rev:
1580 if rev:
1578 if files:
1581 if files:
1579 raise util.Abort(_('option "-r" not valid when importing '
1582 raise util.Abort(_('option "-r" not valid when importing '
1580 'files'))
1583 'files'))
1581 rev = cmdutil.revrange(repo, rev)
1584 rev = cmdutil.revrange(repo, rev)
1582 rev.sort(reverse=True)
1585 rev.sort(reverse=True)
1583 if (len(files) > 1 or len(rev) > 1) and patchname:
1586 if (len(files) > 1 or len(rev) > 1) and patchname:
1584 raise util.Abort(_('option "-n" not valid when importing multiple '
1587 raise util.Abort(_('option "-n" not valid when importing multiple '
1585 'patches'))
1588 'patches'))
1586 i = 0
1589 i = 0
1587 added = []
1590 added = []
1588 if rev:
1591 if rev:
1589 # If mq patches are applied, we can only import revisions
1592 # If mq patches are applied, we can only import revisions
1590 # that form a linear path to qbase.
1593 # that form a linear path to qbase.
1591 # Otherwise, they should form a linear path to a head.
1594 # Otherwise, they should form a linear path to a head.
1592 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1595 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1593 if len(heads) > 1:
1596 if len(heads) > 1:
1594 raise util.Abort(_('revision %d is the root of more than one '
1597 raise util.Abort(_('revision %d is the root of more than one '
1595 'branch') % rev[-1])
1598 'branch') % rev[-1])
1596 if self.applied:
1599 if self.applied:
1597 base = hex(repo.changelog.node(rev[0]))
1600 base = hex(repo.changelog.node(rev[0]))
1598 if base in [n.rev for n in self.applied]:
1601 if base in [n.rev for n in self.applied]:
1599 raise util.Abort(_('revision %d is already managed')
1602 raise util.Abort(_('revision %d is already managed')
1600 % rev[0])
1603 % rev[0])
1601 if heads != [bin(self.applied[-1].rev)]:
1604 if heads != [bin(self.applied[-1].rev)]:
1602 raise util.Abort(_('revision %d is not the parent of '
1605 raise util.Abort(_('revision %d is not the parent of '
1603 'the queue') % rev[0])
1606 'the queue') % rev[0])
1604 base = repo.changelog.rev(bin(self.applied[0].rev))
1607 base = repo.changelog.rev(bin(self.applied[0].rev))
1605 lastparent = repo.changelog.parentrevs(base)[0]
1608 lastparent = repo.changelog.parentrevs(base)[0]
1606 else:
1609 else:
1607 if heads != [repo.changelog.node(rev[0])]:
1610 if heads != [repo.changelog.node(rev[0])]:
1608 raise util.Abort(_('revision %d has unmanaged children')
1611 raise util.Abort(_('revision %d has unmanaged children')
1609 % rev[0])
1612 % rev[0])
1610 lastparent = None
1613 lastparent = None
1611
1614
1612 if git:
1615 if git:
1613 self.diffopts().git = True
1616 self.diffopts().git = True
1614
1617
1615 for r in rev:
1618 for r in rev:
1616 p1, p2 = repo.changelog.parentrevs(r)
1619 p1, p2 = repo.changelog.parentrevs(r)
1617 n = repo.changelog.node(r)
1620 n = repo.changelog.node(r)
1618 if p2 != nullrev:
1621 if p2 != nullrev:
1619 raise util.Abort(_('cannot import merge revision %d') % r)
1622 raise util.Abort(_('cannot import merge revision %d') % r)
1620 if lastparent and lastparent != r:
1623 if lastparent and lastparent != r:
1621 raise util.Abort(_('revision %d is not the parent of %d')
1624 raise util.Abort(_('revision %d is not the parent of %d')
1622 % (r, lastparent))
1625 % (r, lastparent))
1623 lastparent = p1
1626 lastparent = p1
1624
1627
1625 if not patchname:
1628 if not patchname:
1626 patchname = normname('%d.diff' % r)
1629 patchname = normname('%d.diff' % r)
1627 self.check_reserved_name(patchname)
1630 self.check_reserved_name(patchname)
1628 checkseries(patchname)
1631 checkseries(patchname)
1629 checkfile(patchname)
1632 checkfile(patchname)
1630 self.full_series.insert(0, patchname)
1633 self.full_series.insert(0, patchname)
1631
1634
1632 patchf = self.opener(patchname, "w")
1635 patchf = self.opener(patchname, "w")
1633 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1636 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1634 patchf.close()
1637 patchf.close()
1635
1638
1636 se = statusentry(hex(n), patchname)
1639 se = statusentry(hex(n), patchname)
1637 self.applied.insert(0, se)
1640 self.applied.insert(0, se)
1638
1641
1639 added.append(patchname)
1642 added.append(patchname)
1640 patchname = None
1643 patchname = None
1641 self.parse_series()
1644 self.parse_series()
1642 self.applied_dirty = 1
1645 self.applied_dirty = 1
1643
1646
1644 for filename in files:
1647 for filename in files:
1645 if existing:
1648 if existing:
1646 if filename == '-':
1649 if filename == '-':
1647 raise util.Abort(_('-e is incompatible with import from -'))
1650 raise util.Abort(_('-e is incompatible with import from -'))
1648 if not patchname:
1651 if not patchname:
1649 patchname = normname(filename)
1652 patchname = normname(filename)
1650 self.check_reserved_name(patchname)
1653 self.check_reserved_name(patchname)
1651 if not os.path.isfile(self.join(patchname)):
1654 if not os.path.isfile(self.join(patchname)):
1652 raise util.Abort(_("patch %s does not exist") % patchname)
1655 raise util.Abort(_("patch %s does not exist") % patchname)
1653 else:
1656 else:
1654 try:
1657 try:
1655 if filename == '-':
1658 if filename == '-':
1656 if not patchname:
1659 if not patchname:
1657 raise util.Abort(_('need --name to import a patch from -'))
1660 raise util.Abort(_('need --name to import a patch from -'))
1658 text = sys.stdin.read()
1661 text = sys.stdin.read()
1659 else:
1662 else:
1660 text = url.open(self.ui, filename).read()
1663 text = url.open(self.ui, filename).read()
1661 except (OSError, IOError):
1664 except (OSError, IOError):
1662 raise util.Abort(_("unable to read %s") % filename)
1665 raise util.Abort(_("unable to read %s") % filename)
1663 if not patchname:
1666 if not patchname:
1664 patchname = normname(os.path.basename(filename))
1667 patchname = normname(os.path.basename(filename))
1665 self.check_reserved_name(patchname)
1668 self.check_reserved_name(patchname)
1666 checkfile(patchname)
1669 checkfile(patchname)
1667 patchf = self.opener(patchname, "w")
1670 patchf = self.opener(patchname, "w")
1668 patchf.write(text)
1671 patchf.write(text)
1669 if not force:
1672 if not force:
1670 checkseries(patchname)
1673 checkseries(patchname)
1671 if patchname not in self.series:
1674 if patchname not in self.series:
1672 index = self.full_series_end() + i
1675 index = self.full_series_end() + i
1673 self.full_series[index:index] = [patchname]
1676 self.full_series[index:index] = [patchname]
1674 self.parse_series()
1677 self.parse_series()
1675 self.ui.warn(_("adding %s to series file\n") % patchname)
1678 self.ui.warn(_("adding %s to series file\n") % patchname)
1676 i += 1
1679 i += 1
1677 added.append(patchname)
1680 added.append(patchname)
1678 patchname = None
1681 patchname = None
1679 self.series_dirty = 1
1682 self.series_dirty = 1
1680 qrepo = self.qrepo()
1683 qrepo = self.qrepo()
1681 if qrepo:
1684 if qrepo:
1682 qrepo.add(added)
1685 qrepo.add(added)
1683
1686
1684 def delete(ui, repo, *patches, **opts):
1687 def delete(ui, repo, *patches, **opts):
1685 """remove patches from queue
1688 """remove patches from queue
1686
1689
1687 The patches must not be applied, and at least one patch is required. With
1690 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.
1691 -k/--keep, the patch files are preserved in the patch directory.
1689
1692
1690 To stop managing a patch and move it into permanent history,
1693 To stop managing a patch and move it into permanent history,
1691 use the qfinish command."""
1694 use the qfinish command."""
1692 q = repo.mq
1695 q = repo.mq
1693 q.delete(repo, patches, opts)
1696 q.delete(repo, patches, opts)
1694 q.save_dirty()
1697 q.save_dirty()
1695 return 0
1698 return 0
1696
1699
1697 def applied(ui, repo, patch=None, **opts):
1700 def applied(ui, repo, patch=None, **opts):
1698 """print the patches already applied"""
1701 """print the patches already applied"""
1699
1702
1700 q = repo.mq
1703 q = repo.mq
1701 l = len(q.applied)
1704 l = len(q.applied)
1702
1705
1703 if patch:
1706 if patch:
1704 if patch not in q.series:
1707 if patch not in q.series:
1705 raise util.Abort(_("patch %s is not in series file") % patch)
1708 raise util.Abort(_("patch %s is not in series file") % patch)
1706 end = q.series.index(patch) + 1
1709 end = q.series.index(patch) + 1
1707 else:
1710 else:
1708 end = q.series_end(True)
1711 end = q.series_end(True)
1709
1712
1710 if opts.get('last') and not end:
1713 if opts.get('last') and not end:
1711 ui.write(_("no patches applied\n"))
1714 ui.write(_("no patches applied\n"))
1712 return 1
1715 return 1
1713 elif opts.get('last') and end == 1:
1716 elif opts.get('last') and end == 1:
1714 ui.write(_("only one patch applied\n"))
1717 ui.write(_("only one patch applied\n"))
1715 return 1
1718 return 1
1716 elif opts.get('last'):
1719 elif opts.get('last'):
1717 start = end - 2
1720 start = end - 2
1718 end = 1
1721 end = 1
1719 else:
1722 else:
1720 start = 0
1723 start = 0
1721
1724
1722 return q.qseries(repo, length=end, start=start, status='A',
1725 return q.qseries(repo, length=end, start=start, status='A',
1723 summary=opts.get('summary'))
1726 summary=opts.get('summary'))
1724
1727
1725 def unapplied(ui, repo, patch=None, **opts):
1728 def unapplied(ui, repo, patch=None, **opts):
1726 """print the patches not yet applied"""
1729 """print the patches not yet applied"""
1727
1730
1728 q = repo.mq
1731 q = repo.mq
1729 if patch:
1732 if patch:
1730 if patch not in q.series:
1733 if patch not in q.series:
1731 raise util.Abort(_("patch %s is not in series file") % patch)
1734 raise util.Abort(_("patch %s is not in series file") % patch)
1732 start = q.series.index(patch) + 1
1735 start = q.series.index(patch) + 1
1733 else:
1736 else:
1734 start = q.series_end(True)
1737 start = q.series_end(True)
1735
1738
1736 if start == len(q.series) and opts.get('first'):
1739 if start == len(q.series) and opts.get('first'):
1737 ui.write(_("all patches applied\n"))
1740 ui.write(_("all patches applied\n"))
1738 return 1
1741 return 1
1739
1742
1740 length = opts.get('first') and 1 or None
1743 length = opts.get('first') and 1 or None
1741 return q.qseries(repo, start=start, length=length, status='U',
1744 return q.qseries(repo, start=start, length=length, status='U',
1742 summary=opts.get('summary'))
1745 summary=opts.get('summary'))
1743
1746
1744 def qimport(ui, repo, *filename, **opts):
1747 def qimport(ui, repo, *filename, **opts):
1745 """import a patch
1748 """import a patch
1746
1749
1747 The patch is inserted into the series after the last applied
1750 The patch is inserted into the series after the last applied
1748 patch. If no patches have been applied, qimport prepends the patch
1751 patch. If no patches have been applied, qimport prepends the patch
1749 to the series.
1752 to the series.
1750
1753
1751 The patch will have the same name as its source file unless you
1754 The patch will have the same name as its source file unless you
1752 give it a new one with -n/--name.
1755 give it a new one with -n/--name.
1753
1756
1754 You can register an existing patch inside the patch directory with
1757 You can register an existing patch inside the patch directory with
1755 the -e/--existing flag.
1758 the -e/--existing flag.
1756
1759
1757 With -f/--force, an existing patch of the same name will be
1760 With -f/--force, an existing patch of the same name will be
1758 overwritten.
1761 overwritten.
1759
1762
1760 An existing changeset may be placed under mq control with -r/--rev
1763 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).
1764 (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
1765 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
1766 format. See the diffs help topic for information on why this is
1764 important for preserving rename/copy information and permission
1767 important for preserving rename/copy information and permission
1765 changes.
1768 changes.
1766
1769
1767 To import a patch from standard input, pass - as the patch file.
1770 To import a patch from standard input, pass - as the patch file.
1768 When importing from standard input, a patch name must be specified
1771 When importing from standard input, a patch name must be specified
1769 using the --name flag.
1772 using the --name flag.
1770 """
1773 """
1771 q = repo.mq
1774 q = repo.mq
1772 q.qimport(repo, filename, patchname=opts['name'],
1775 q.qimport(repo, filename, patchname=opts['name'],
1773 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1776 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1774 git=opts['git'])
1777 git=opts['git'])
1775 q.save_dirty()
1778 q.save_dirty()
1776
1779
1777 if opts.get('push') and not opts.get('rev'):
1780 if opts.get('push') and not opts.get('rev'):
1778 return q.push(repo, None)
1781 return q.push(repo, None)
1779 return 0
1782 return 0
1780
1783
1781 def init(ui, repo, **opts):
1784 def init(ui, repo, **opts):
1782 """init a new queue repository
1785 """init a new queue repository
1783
1786
1784 The queue repository is unversioned by default. If
1787 The queue repository is unversioned by default. If
1785 -c/--create-repo is specified, qinit will create a separate nested
1788 -c/--create-repo is specified, qinit will create a separate nested
1786 repository for patches (qinit -c may also be run later to convert
1789 repository for patches (qinit -c may also be run later to convert
1787 an unversioned patch repository into a versioned one). You can use
1790 an unversioned patch repository into a versioned one). You can use
1788 qcommit to commit changes to this queue repository."""
1791 qcommit to commit changes to this queue repository."""
1789 q = repo.mq
1792 q = repo.mq
1790 r = q.init(repo, create=opts['create_repo'])
1793 r = q.init(repo, create=opts['create_repo'])
1791 q.save_dirty()
1794 q.save_dirty()
1792 if r:
1795 if r:
1793 if not os.path.exists(r.wjoin('.hgignore')):
1796 if not os.path.exists(r.wjoin('.hgignore')):
1794 fp = r.wopener('.hgignore', 'w')
1797 fp = r.wopener('.hgignore', 'w')
1795 fp.write('^\\.hg\n')
1798 fp.write('^\\.hg\n')
1796 fp.write('^\\.mq\n')
1799 fp.write('^\\.mq\n')
1797 fp.write('syntax: glob\n')
1800 fp.write('syntax: glob\n')
1798 fp.write('status\n')
1801 fp.write('status\n')
1799 fp.write('guards\n')
1802 fp.write('guards\n')
1800 fp.close()
1803 fp.close()
1801 if not os.path.exists(r.wjoin('series')):
1804 if not os.path.exists(r.wjoin('series')):
1802 r.wopener('series', 'w').close()
1805 r.wopener('series', 'w').close()
1803 r.add(['.hgignore', 'series'])
1806 r.add(['.hgignore', 'series'])
1804 commands.add(ui, r)
1807 commands.add(ui, r)
1805 return 0
1808 return 0
1806
1809
1807 def clone(ui, source, dest=None, **opts):
1810 def clone(ui, source, dest=None, **opts):
1808 '''clone main and patch repository at same time
1811 '''clone main and patch repository at same time
1809
1812
1810 If source is local, destination will have no patches applied. If
1813 If source is local, destination will have no patches applied. If
1811 source is remote, this command can not check if patches are
1814 source is remote, this command can not check if patches are
1812 applied in source, so cannot guarantee that patches are not
1815 applied in source, so cannot guarantee that patches are not
1813 applied in destination. If you clone remote repository, be sure
1816 applied in destination. If you clone remote repository, be sure
1814 before that it has no patches applied.
1817 before that it has no patches applied.
1815
1818
1816 Source patch repository is looked for in <src>/.hg/patches by
1819 Source patch repository is looked for in <src>/.hg/patches by
1817 default. Use -p <url> to change.
1820 default. Use -p <url> to change.
1818
1821
1819 The patch directory must be a nested Mercurial repository, as
1822 The patch directory must be a nested Mercurial repository, as
1820 would be created by qinit -c.
1823 would be created by qinit -c.
1821 '''
1824 '''
1822 def patchdir(repo):
1825 def patchdir(repo):
1823 url = repo.url()
1826 url = repo.url()
1824 if url.endswith('/'):
1827 if url.endswith('/'):
1825 url = url[:-1]
1828 url = url[:-1]
1826 return url + '/.hg/patches'
1829 return url + '/.hg/patches'
1827 if dest is None:
1830 if dest is None:
1828 dest = hg.defaultdest(source)
1831 dest = hg.defaultdest(source)
1829 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1832 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1830 if opts['patches']:
1833 if opts['patches']:
1831 patchespath = ui.expandpath(opts['patches'])
1834 patchespath = ui.expandpath(opts['patches'])
1832 else:
1835 else:
1833 patchespath = patchdir(sr)
1836 patchespath = patchdir(sr)
1834 try:
1837 try:
1835 hg.repository(ui, patchespath)
1838 hg.repository(ui, patchespath)
1836 except error.RepoError:
1839 except error.RepoError:
1837 raise util.Abort(_('versioned patch repository not found'
1840 raise util.Abort(_('versioned patch repository not found'
1838 ' (see qinit -c)'))
1841 ' (see qinit -c)'))
1839 qbase, destrev = None, None
1842 qbase, destrev = None, None
1840 if sr.local():
1843 if sr.local():
1841 if sr.mq.applied:
1844 if sr.mq.applied:
1842 qbase = bin(sr.mq.applied[0].rev)
1845 qbase = bin(sr.mq.applied[0].rev)
1843 if not hg.islocal(dest):
1846 if not hg.islocal(dest):
1844 heads = set(sr.heads())
1847 heads = set(sr.heads())
1845 destrev = list(heads.difference(sr.heads(qbase)))
1848 destrev = list(heads.difference(sr.heads(qbase)))
1846 destrev.append(sr.changelog.parents(qbase)[0])
1849 destrev.append(sr.changelog.parents(qbase)[0])
1847 elif sr.capable('lookup'):
1850 elif sr.capable('lookup'):
1848 try:
1851 try:
1849 qbase = sr.lookup('qbase')
1852 qbase = sr.lookup('qbase')
1850 except error.RepoError:
1853 except error.RepoError:
1851 pass
1854 pass
1852 ui.note(_('cloning main repository\n'))
1855 ui.note(_('cloning main repository\n'))
1853 sr, dr = hg.clone(ui, sr.url(), dest,
1856 sr, dr = hg.clone(ui, sr.url(), dest,
1854 pull=opts['pull'],
1857 pull=opts['pull'],
1855 rev=destrev,
1858 rev=destrev,
1856 update=False,
1859 update=False,
1857 stream=opts['uncompressed'])
1860 stream=opts['uncompressed'])
1858 ui.note(_('cloning patch repository\n'))
1861 ui.note(_('cloning patch repository\n'))
1859 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1862 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1860 pull=opts['pull'], update=not opts['noupdate'],
1863 pull=opts['pull'], update=not opts['noupdate'],
1861 stream=opts['uncompressed'])
1864 stream=opts['uncompressed'])
1862 if dr.local():
1865 if dr.local():
1863 if qbase:
1866 if qbase:
1864 ui.note(_('stripping applied patches from destination '
1867 ui.note(_('stripping applied patches from destination '
1865 'repository\n'))
1868 'repository\n'))
1866 dr.mq.strip(dr, qbase, update=False, backup=None)
1869 dr.mq.strip(dr, qbase, update=False, backup=None)
1867 if not opts['noupdate']:
1870 if not opts['noupdate']:
1868 ui.note(_('updating destination repository\n'))
1871 ui.note(_('updating destination repository\n'))
1869 hg.update(dr, dr.changelog.tip())
1872 hg.update(dr, dr.changelog.tip())
1870
1873
1871 def commit(ui, repo, *pats, **opts):
1874 def commit(ui, repo, *pats, **opts):
1872 """commit changes in the queue repository"""
1875 """commit changes in the queue repository"""
1873 q = repo.mq
1876 q = repo.mq
1874 r = q.qrepo()
1877 r = q.qrepo()
1875 if not r: raise util.Abort('no queue repository')
1878 if not r: raise util.Abort('no queue repository')
1876 commands.commit(r.ui, r, *pats, **opts)
1879 commands.commit(r.ui, r, *pats, **opts)
1877
1880
1878 def series(ui, repo, **opts):
1881 def series(ui, repo, **opts):
1879 """print the entire series file"""
1882 """print the entire series file"""
1880 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1883 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1881 return 0
1884 return 0
1882
1885
1883 def top(ui, repo, **opts):
1886 def top(ui, repo, **opts):
1884 """print the name of the current patch"""
1887 """print the name of the current patch"""
1885 q = repo.mq
1888 q = repo.mq
1886 t = q.applied and q.series_end(True) or 0
1889 t = q.applied and q.series_end(True) or 0
1887 if t:
1890 if t:
1888 return q.qseries(repo, start=t-1, length=1, status='A',
1891 return q.qseries(repo, start=t-1, length=1, status='A',
1889 summary=opts.get('summary'))
1892 summary=opts.get('summary'))
1890 else:
1893 else:
1891 ui.write(_("no patches applied\n"))
1894 ui.write(_("no patches applied\n"))
1892 return 1
1895 return 1
1893
1896
1894 def next(ui, repo, **opts):
1897 def next(ui, repo, **opts):
1895 """print the name of the next patch"""
1898 """print the name of the next patch"""
1896 q = repo.mq
1899 q = repo.mq
1897 end = q.series_end()
1900 end = q.series_end()
1898 if end == len(q.series):
1901 if end == len(q.series):
1899 ui.write(_("all patches applied\n"))
1902 ui.write(_("all patches applied\n"))
1900 return 1
1903 return 1
1901 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1904 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1902
1905
1903 def prev(ui, repo, **opts):
1906 def prev(ui, repo, **opts):
1904 """print the name of the previous patch"""
1907 """print the name of the previous patch"""
1905 q = repo.mq
1908 q = repo.mq
1906 l = len(q.applied)
1909 l = len(q.applied)
1907 if l == 1:
1910 if l == 1:
1908 ui.write(_("only one patch applied\n"))
1911 ui.write(_("only one patch applied\n"))
1909 return 1
1912 return 1
1910 if not l:
1913 if not l:
1911 ui.write(_("no patches applied\n"))
1914 ui.write(_("no patches applied\n"))
1912 return 1
1915 return 1
1913 return q.qseries(repo, start=l-2, length=1, status='A',
1916 return q.qseries(repo, start=l-2, length=1, status='A',
1914 summary=opts.get('summary'))
1917 summary=opts.get('summary'))
1915
1918
1916 def setupheaderopts(ui, opts):
1919 def setupheaderopts(ui, opts):
1917 if not opts.get('user') and opts.get('currentuser'):
1920 if not opts.get('user') and opts.get('currentuser'):
1918 opts['user'] = ui.username()
1921 opts['user'] = ui.username()
1919 if not opts.get('date') and opts.get('currentdate'):
1922 if not opts.get('date') and opts.get('currentdate'):
1920 opts['date'] = "%d %d" % util.makedate()
1923 opts['date'] = "%d %d" % util.makedate()
1921
1924
1922 def new(ui, repo, patch, *args, **opts):
1925 def new(ui, repo, patch, *args, **opts):
1923 """create a new patch
1926 """create a new patch
1924
1927
1925 qnew creates a new patch on top of the currently-applied patch (if
1928 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
1929 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
1930 unless -f/--force is specified, in which case the patch will be
1928 initialized with them. You may also use -I/--include,
1931 initialized with them. You may also use -I/--include,
1929 -X/--exclude, and/or a list of files after the patch name to add
1932 -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
1933 only changes to matching files to the new patch, leaving the rest
1931 as uncommitted modifications.
1934 as uncommitted modifications.
1932
1935
1933 -u/--user and -d/--date can be used to set the (given) user and
1936 -u/--user and -d/--date can be used to set the (given) user and
1934 date, respectively. -U/--currentuser and -D/--currentdate set user
1937 date, respectively. -U/--currentuser and -D/--currentdate set user
1935 to current user and date to current date.
1938 to current user and date to current date.
1936
1939
1937 -e/--edit, -m/--message or -l/--logfile set the patch header as
1940 -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
1941 well as the commit message. If none is specified, the header is
1939 empty and the commit message is '[mq]: PATCH'.
1942 empty and the commit message is '[mq]: PATCH'.
1940
1943
1941 Use the -g/--git option to keep the patch in the git extended diff
1944 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
1945 format. Read the diffs help topic for more information on why this
1943 is important for preserving permission changes and copy/rename
1946 is important for preserving permission changes and copy/rename
1944 information.
1947 information.
1945 """
1948 """
1946 msg = cmdutil.logmessage(opts)
1949 msg = cmdutil.logmessage(opts)
1947 def getmsg(): return ui.edit(msg, ui.username())
1950 def getmsg(): return ui.edit(msg, ui.username())
1948 q = repo.mq
1951 q = repo.mq
1949 opts['msg'] = msg
1952 opts['msg'] = msg
1950 if opts.get('edit'):
1953 if opts.get('edit'):
1951 opts['msg'] = getmsg
1954 opts['msg'] = getmsg
1952 else:
1955 else:
1953 opts['msg'] = msg
1956 opts['msg'] = msg
1954 setupheaderopts(ui, opts)
1957 setupheaderopts(ui, opts)
1955 q.new(repo, patch, *args, **opts)
1958 q.new(repo, patch, *args, **opts)
1956 q.save_dirty()
1959 q.save_dirty()
1957 return 0
1960 return 0
1958
1961
1959 def refresh(ui, repo, *pats, **opts):
1962 def refresh(ui, repo, *pats, **opts):
1960 """update the current patch
1963 """update the current patch
1961
1964
1962 If any file patterns are provided, the refreshed patch will
1965 If any file patterns are provided, the refreshed patch will
1963 contain only the modifications that match those patterns; the
1966 contain only the modifications that match those patterns; the
1964 remaining modifications will remain in the working directory.
1967 remaining modifications will remain in the working directory.
1965
1968
1966 If -s/--short is specified, files currently included in the patch
1969 If -s/--short is specified, files currently included in the patch
1967 will be refreshed just like matched files and remain in the patch.
1970 will be refreshed just like matched files and remain in the patch.
1968
1971
1969 hg add/remove/copy/rename work as usual, though you might want to
1972 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
1973 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
1974 and renames. See the diffs help topic for more information on the
1972 git diff format.
1975 git diff format.
1973 """
1976 """
1974 q = repo.mq
1977 q = repo.mq
1975 message = cmdutil.logmessage(opts)
1978 message = cmdutil.logmessage(opts)
1976 if opts['edit']:
1979 if opts['edit']:
1977 if not q.applied:
1980 if not q.applied:
1978 ui.write(_("no patches applied\n"))
1981 ui.write(_("no patches applied\n"))
1979 return 1
1982 return 1
1980 if message:
1983 if message:
1981 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1984 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1982 patch = q.applied[-1].name
1985 patch = q.applied[-1].name
1983 ph = patchheader(q.join(patch))
1986 ph = patchheader(q.join(patch))
1984 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
1987 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
1985 setupheaderopts(ui, opts)
1988 setupheaderopts(ui, opts)
1986 ret = q.refresh(repo, pats, msg=message, **opts)
1989 ret = q.refresh(repo, pats, msg=message, **opts)
1987 q.save_dirty()
1990 q.save_dirty()
1988 return ret
1991 return ret
1989
1992
1990 def diff(ui, repo, *pats, **opts):
1993 def diff(ui, repo, *pats, **opts):
1991 """diff of the current patch and subsequent modifications
1994 """diff of the current patch and subsequent modifications
1992
1995
1993 Shows a diff which includes the current patch as well as any
1996 Shows a diff which includes the current patch as well as any
1994 changes which have been made in the working directory since the
1997 changes which have been made in the working directory since the
1995 last refresh (thus showing what the current patch would become
1998 last refresh (thus showing what the current patch would become
1996 after a qrefresh).
1999 after a qrefresh).
1997
2000
1998 Use 'hg diff' if you only want to see the changes made since the
2001 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
2002 last qrefresh, or 'hg export qtip' if you want to see changes made
2000 by the current patch without including changes made since the
2003 by the current patch without including changes made since the
2001 qrefresh.
2004 qrefresh.
2002 """
2005 """
2003 repo.mq.diff(repo, pats, opts)
2006 repo.mq.diff(repo, pats, opts)
2004 return 0
2007 return 0
2005
2008
2006 def fold(ui, repo, *files, **opts):
2009 def fold(ui, repo, *files, **opts):
2007 """fold the named patches into the current patch
2010 """fold the named patches into the current patch
2008
2011
2009 Patches must not yet be applied. Each patch will be successively
2012 Patches must not yet be applied. Each patch will be successively
2010 applied to the current patch in the order given. If all the
2013 applied to the current patch in the order given. If all the
2011 patches apply successfully, the current patch will be refreshed
2014 patches apply successfully, the current patch will be refreshed
2012 with the new cumulative patch, and the folded patches will be
2015 with the new cumulative patch, and the folded patches will be
2013 deleted. With -k/--keep, the folded patch files will not be
2016 deleted. With -k/--keep, the folded patch files will not be
2014 removed afterwards.
2017 removed afterwards.
2015
2018
2016 The header for each folded patch will be concatenated with the
2019 The header for each folded patch will be concatenated with the
2017 current patch header, separated by a line of '* * *'."""
2020 current patch header, separated by a line of '* * *'."""
2018
2021
2019 q = repo.mq
2022 q = repo.mq
2020
2023
2021 if not files:
2024 if not files:
2022 raise util.Abort(_('qfold requires at least one patch name'))
2025 raise util.Abort(_('qfold requires at least one patch name'))
2023 if not q.check_toppatch(repo):
2026 if not q.check_toppatch(repo):
2024 raise util.Abort(_('No patches applied'))
2027 raise util.Abort(_('No patches applied'))
2025 q.check_localchanges(repo)
2028 q.check_localchanges(repo)
2026
2029
2027 message = cmdutil.logmessage(opts)
2030 message = cmdutil.logmessage(opts)
2028 if opts['edit']:
2031 if opts['edit']:
2029 if message:
2032 if message:
2030 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2033 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2031
2034
2032 parent = q.lookup('qtip')
2035 parent = q.lookup('qtip')
2033 patches = []
2036 patches = []
2034 messages = []
2037 messages = []
2035 for f in files:
2038 for f in files:
2036 p = q.lookup(f)
2039 p = q.lookup(f)
2037 if p in patches or p == parent:
2040 if p in patches or p == parent:
2038 ui.warn(_('Skipping already folded patch %s') % p)
2041 ui.warn(_('Skipping already folded patch %s') % p)
2039 if q.isapplied(p):
2042 if q.isapplied(p):
2040 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2043 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2041 patches.append(p)
2044 patches.append(p)
2042
2045
2043 for p in patches:
2046 for p in patches:
2044 if not message:
2047 if not message:
2045 ph = patchheader(q.join(p))
2048 ph = patchheader(q.join(p))
2046 if ph.message:
2049 if ph.message:
2047 messages.append(ph.message)
2050 messages.append(ph.message)
2048 pf = q.join(p)
2051 pf = q.join(p)
2049 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2052 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2050 if not patchsuccess:
2053 if not patchsuccess:
2051 raise util.Abort(_('Error folding patch %s') % p)
2054 raise util.Abort(_('Error folding patch %s') % p)
2052 patch.updatedir(ui, repo, files)
2055 patch.updatedir(ui, repo, files)
2053
2056
2054 if not message:
2057 if not message:
2055 ph = patchheader(q.join(parent))
2058 ph = patchheader(q.join(parent))
2056 message, user = ph.message, ph.user
2059 message, user = ph.message, ph.user
2057 for msg in messages:
2060 for msg in messages:
2058 message.append('* * *')
2061 message.append('* * *')
2059 message.extend(msg)
2062 message.extend(msg)
2060 message = '\n'.join(message)
2063 message = '\n'.join(message)
2061
2064
2062 if opts['edit']:
2065 if opts['edit']:
2063 message = ui.edit(message, user or ui.username())
2066 message = ui.edit(message, user or ui.username())
2064
2067
2065 q.refresh(repo, msg=message)
2068 q.refresh(repo, msg=message)
2066 q.delete(repo, patches, opts)
2069 q.delete(repo, patches, opts)
2067 q.save_dirty()
2070 q.save_dirty()
2068
2071
2069 def goto(ui, repo, patch, **opts):
2072 def goto(ui, repo, patch, **opts):
2070 '''push or pop patches until named patch is at top of stack'''
2073 '''push or pop patches until named patch is at top of stack'''
2071 q = repo.mq
2074 q = repo.mq
2072 patch = q.lookup(patch)
2075 patch = q.lookup(patch)
2073 if q.isapplied(patch):
2076 if q.isapplied(patch):
2074 ret = q.pop(repo, patch, force=opts['force'])
2077 ret = q.pop(repo, patch, force=opts['force'])
2075 else:
2078 else:
2076 ret = q.push(repo, patch, force=opts['force'])
2079 ret = q.push(repo, patch, force=opts['force'])
2077 q.save_dirty()
2080 q.save_dirty()
2078 return ret
2081 return ret
2079
2082
2080 def guard(ui, repo, *args, **opts):
2083 def guard(ui, repo, *args, **opts):
2081 '''set or print guards for a patch
2084 '''set or print guards for a patch
2082
2085
2083 Guards control whether a patch can be pushed. A patch with no
2086 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
2087 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
2088 pushed only if the qselect command has activated it. A patch with
2086 a negative guard ("-foo") is never pushed if the qselect command
2089 a negative guard ("-foo") is never pushed if the qselect command
2087 has activated it.
2090 has activated it.
2088
2091
2089 With no arguments, print the currently active guards.
2092 With no arguments, print the currently active guards.
2090 With arguments, set guards for the named patch.
2093 With arguments, set guards for the named patch.
2091 NOTE: Specifying negative guards now requires '--'.
2094 NOTE: Specifying negative guards now requires '--'.
2092
2095
2093 To set guards on another patch::
2096 To set guards on another patch::
2094
2097
2095 hg qguard -- other.patch +2.6.17 -stable
2098 hg qguard -- other.patch +2.6.17 -stable
2096 '''
2099 '''
2097 def status(idx):
2100 def status(idx):
2098 guards = q.series_guards[idx] or ['unguarded']
2101 guards = q.series_guards[idx] or ['unguarded']
2099 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
2102 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
2100 q = repo.mq
2103 q = repo.mq
2101 patch = None
2104 patch = None
2102 args = list(args)
2105 args = list(args)
2103 if opts['list']:
2106 if opts['list']:
2104 if args or opts['none']:
2107 if args or opts['none']:
2105 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2108 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2106 for i in xrange(len(q.series)):
2109 for i in xrange(len(q.series)):
2107 status(i)
2110 status(i)
2108 return
2111 return
2109 if not args or args[0][0:1] in '-+':
2112 if not args or args[0][0:1] in '-+':
2110 if not q.applied:
2113 if not q.applied:
2111 raise util.Abort(_('no patches applied'))
2114 raise util.Abort(_('no patches applied'))
2112 patch = q.applied[-1].name
2115 patch = q.applied[-1].name
2113 if patch is None and args[0][0:1] not in '-+':
2116 if patch is None and args[0][0:1] not in '-+':
2114 patch = args.pop(0)
2117 patch = args.pop(0)
2115 if patch is None:
2118 if patch is None:
2116 raise util.Abort(_('no patch to work with'))
2119 raise util.Abort(_('no patch to work with'))
2117 if args or opts['none']:
2120 if args or opts['none']:
2118 idx = q.find_series(patch)
2121 idx = q.find_series(patch)
2119 if idx is None:
2122 if idx is None:
2120 raise util.Abort(_('no patch named %s') % patch)
2123 raise util.Abort(_('no patch named %s') % patch)
2121 q.set_guards(idx, args)
2124 q.set_guards(idx, args)
2122 q.save_dirty()
2125 q.save_dirty()
2123 else:
2126 else:
2124 status(q.series.index(q.lookup(patch)))
2127 status(q.series.index(q.lookup(patch)))
2125
2128
2126 def header(ui, repo, patch=None):
2129 def header(ui, repo, patch=None):
2127 """print the header of the topmost or specified patch"""
2130 """print the header of the topmost or specified patch"""
2128 q = repo.mq
2131 q = repo.mq
2129
2132
2130 if patch:
2133 if patch:
2131 patch = q.lookup(patch)
2134 patch = q.lookup(patch)
2132 else:
2135 else:
2133 if not q.applied:
2136 if not q.applied:
2134 ui.write('no patches applied\n')
2137 ui.write('no patches applied\n')
2135 return 1
2138 return 1
2136 patch = q.lookup('qtip')
2139 patch = q.lookup('qtip')
2137 ph = patchheader(repo.mq.join(patch))
2140 ph = patchheader(repo.mq.join(patch))
2138
2141
2139 ui.write('\n'.join(ph.message) + '\n')
2142 ui.write('\n'.join(ph.message) + '\n')
2140
2143
2141 def lastsavename(path):
2144 def lastsavename(path):
2142 (directory, base) = os.path.split(path)
2145 (directory, base) = os.path.split(path)
2143 names = os.listdir(directory)
2146 names = os.listdir(directory)
2144 namere = re.compile("%s.([0-9]+)" % base)
2147 namere = re.compile("%s.([0-9]+)" % base)
2145 maxindex = None
2148 maxindex = None
2146 maxname = None
2149 maxname = None
2147 for f in names:
2150 for f in names:
2148 m = namere.match(f)
2151 m = namere.match(f)
2149 if m:
2152 if m:
2150 index = int(m.group(1))
2153 index = int(m.group(1))
2151 if maxindex is None or index > maxindex:
2154 if maxindex is None or index > maxindex:
2152 maxindex = index
2155 maxindex = index
2153 maxname = f
2156 maxname = f
2154 if maxname:
2157 if maxname:
2155 return (os.path.join(directory, maxname), maxindex)
2158 return (os.path.join(directory, maxname), maxindex)
2156 return (None, None)
2159 return (None, None)
2157
2160
2158 def savename(path):
2161 def savename(path):
2159 (last, index) = lastsavename(path)
2162 (last, index) = lastsavename(path)
2160 if last is None:
2163 if last is None:
2161 index = 0
2164 index = 0
2162 newpath = path + ".%d" % (index + 1)
2165 newpath = path + ".%d" % (index + 1)
2163 return newpath
2166 return newpath
2164
2167
2165 def push(ui, repo, patch=None, **opts):
2168 def push(ui, repo, patch=None, **opts):
2166 """push the next patch onto the stack
2169 """push the next patch onto the stack
2167
2170
2168 When -f/--force is applied, all local changes in patched files
2171 When -f/--force is applied, all local changes in patched files
2169 will be lost.
2172 will be lost.
2170 """
2173 """
2171 q = repo.mq
2174 q = repo.mq
2172 mergeq = None
2175 mergeq = None
2173
2176
2174 if opts['merge']:
2177 if opts['merge']:
2175 if opts['name']:
2178 if opts['name']:
2176 newpath = repo.join(opts['name'])
2179 newpath = repo.join(opts['name'])
2177 else:
2180 else:
2178 newpath, i = lastsavename(q.path)
2181 newpath, i = lastsavename(q.path)
2179 if not newpath:
2182 if not newpath:
2180 ui.warn(_("no saved queues found, please use -n\n"))
2183 ui.warn(_("no saved queues found, please use -n\n"))
2181 return 1
2184 return 1
2182 mergeq = queue(ui, repo.join(""), newpath)
2185 mergeq = queue(ui, repo.join(""), newpath)
2183 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2186 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2184 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2187 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2185 mergeq=mergeq, all=opts.get('all'))
2188 mergeq=mergeq, all=opts.get('all'))
2186 return ret
2189 return ret
2187
2190
2188 def pop(ui, repo, patch=None, **opts):
2191 def pop(ui, repo, patch=None, **opts):
2189 """pop the current patch off the stack
2192 """pop the current patch off the stack
2190
2193
2191 By default, pops off the top of the patch stack. If given a patch
2194 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
2195 name, keeps popping off patches until the named patch is at the
2193 top of the stack.
2196 top of the stack.
2194 """
2197 """
2195 localupdate = True
2198 localupdate = True
2196 if opts['name']:
2199 if opts['name']:
2197 q = queue(ui, repo.join(""), repo.join(opts['name']))
2200 q = queue(ui, repo.join(""), repo.join(opts['name']))
2198 ui.warn(_('using patch queue: %s\n') % q.path)
2201 ui.warn(_('using patch queue: %s\n') % q.path)
2199 localupdate = False
2202 localupdate = False
2200 else:
2203 else:
2201 q = repo.mq
2204 q = repo.mq
2202 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2205 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2203 all=opts['all'])
2206 all=opts['all'])
2204 q.save_dirty()
2207 q.save_dirty()
2205 return ret
2208 return ret
2206
2209
2207 def rename(ui, repo, patch, name=None, **opts):
2210 def rename(ui, repo, patch, name=None, **opts):
2208 """rename a patch
2211 """rename a patch
2209
2212
2210 With one argument, renames the current patch to PATCH1.
2213 With one argument, renames the current patch to PATCH1.
2211 With two arguments, renames PATCH1 to PATCH2."""
2214 With two arguments, renames PATCH1 to PATCH2."""
2212
2215
2213 q = repo.mq
2216 q = repo.mq
2214
2217
2215 if not name:
2218 if not name:
2216 name = patch
2219 name = patch
2217 patch = None
2220 patch = None
2218
2221
2219 if patch:
2222 if patch:
2220 patch = q.lookup(patch)
2223 patch = q.lookup(patch)
2221 else:
2224 else:
2222 if not q.applied:
2225 if not q.applied:
2223 ui.write(_('no patches applied\n'))
2226 ui.write(_('no patches applied\n'))
2224 return
2227 return
2225 patch = q.lookup('qtip')
2228 patch = q.lookup('qtip')
2226 absdest = q.join(name)
2229 absdest = q.join(name)
2227 if os.path.isdir(absdest):
2230 if os.path.isdir(absdest):
2228 name = normname(os.path.join(name, os.path.basename(patch)))
2231 name = normname(os.path.join(name, os.path.basename(patch)))
2229 absdest = q.join(name)
2232 absdest = q.join(name)
2230 if os.path.exists(absdest):
2233 if os.path.exists(absdest):
2231 raise util.Abort(_('%s already exists') % absdest)
2234 raise util.Abort(_('%s already exists') % absdest)
2232
2235
2233 if name in q.series:
2236 if name in q.series:
2234 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2237 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2235
2238
2236 if ui.verbose:
2239 if ui.verbose:
2237 ui.write('renaming %s to %s\n' % (patch, name))
2240 ui.write('renaming %s to %s\n' % (patch, name))
2238 i = q.find_series(patch)
2241 i = q.find_series(patch)
2239 guards = q.guard_re.findall(q.full_series[i])
2242 guards = q.guard_re.findall(q.full_series[i])
2240 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2243 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2241 q.parse_series()
2244 q.parse_series()
2242 q.series_dirty = 1
2245 q.series_dirty = 1
2243
2246
2244 info = q.isapplied(patch)
2247 info = q.isapplied(patch)
2245 if info:
2248 if info:
2246 q.applied[info[0]] = statusentry(info[1], name)
2249 q.applied[info[0]] = statusentry(info[1], name)
2247 q.applied_dirty = 1
2250 q.applied_dirty = 1
2248
2251
2249 util.rename(q.join(patch), absdest)
2252 util.rename(q.join(patch), absdest)
2250 r = q.qrepo()
2253 r = q.qrepo()
2251 if r:
2254 if r:
2252 wlock = r.wlock()
2255 wlock = r.wlock()
2253 try:
2256 try:
2254 if r.dirstate[patch] == 'a':
2257 if r.dirstate[patch] == 'a':
2255 r.dirstate.forget(patch)
2258 r.dirstate.forget(patch)
2256 r.dirstate.add(name)
2259 r.dirstate.add(name)
2257 else:
2260 else:
2258 if r.dirstate[name] == 'r':
2261 if r.dirstate[name] == 'r':
2259 r.undelete([name])
2262 r.undelete([name])
2260 r.copy(patch, name)
2263 r.copy(patch, name)
2261 r.remove([patch], False)
2264 r.remove([patch], False)
2262 finally:
2265 finally:
2263 wlock.release()
2266 wlock.release()
2264
2267
2265 q.save_dirty()
2268 q.save_dirty()
2266
2269
2267 def restore(ui, repo, rev, **opts):
2270 def restore(ui, repo, rev, **opts):
2268 """restore the queue state saved by a revision"""
2271 """restore the queue state saved by a revision"""
2269 rev = repo.lookup(rev)
2272 rev = repo.lookup(rev)
2270 q = repo.mq
2273 q = repo.mq
2271 q.restore(repo, rev, delete=opts['delete'],
2274 q.restore(repo, rev, delete=opts['delete'],
2272 qupdate=opts['update'])
2275 qupdate=opts['update'])
2273 q.save_dirty()
2276 q.save_dirty()
2274 return 0
2277 return 0
2275
2278
2276 def save(ui, repo, **opts):
2279 def save(ui, repo, **opts):
2277 """save current queue state"""
2280 """save current queue state"""
2278 q = repo.mq
2281 q = repo.mq
2279 message = cmdutil.logmessage(opts)
2282 message = cmdutil.logmessage(opts)
2280 ret = q.save(repo, msg=message)
2283 ret = q.save(repo, msg=message)
2281 if ret:
2284 if ret:
2282 return ret
2285 return ret
2283 q.save_dirty()
2286 q.save_dirty()
2284 if opts['copy']:
2287 if opts['copy']:
2285 path = q.path
2288 path = q.path
2286 if opts['name']:
2289 if opts['name']:
2287 newpath = os.path.join(q.basepath, opts['name'])
2290 newpath = os.path.join(q.basepath, opts['name'])
2288 if os.path.exists(newpath):
2291 if os.path.exists(newpath):
2289 if not os.path.isdir(newpath):
2292 if not os.path.isdir(newpath):
2290 raise util.Abort(_('destination %s exists and is not '
2293 raise util.Abort(_('destination %s exists and is not '
2291 'a directory') % newpath)
2294 'a directory') % newpath)
2292 if not opts['force']:
2295 if not opts['force']:
2293 raise util.Abort(_('destination %s exists, '
2296 raise util.Abort(_('destination %s exists, '
2294 'use -f to force') % newpath)
2297 'use -f to force') % newpath)
2295 else:
2298 else:
2296 newpath = savename(path)
2299 newpath = savename(path)
2297 ui.warn(_("copy %s to %s\n") % (path, newpath))
2300 ui.warn(_("copy %s to %s\n") % (path, newpath))
2298 util.copyfiles(path, newpath)
2301 util.copyfiles(path, newpath)
2299 if opts['empty']:
2302 if opts['empty']:
2300 try:
2303 try:
2301 os.unlink(q.join(q.status_path))
2304 os.unlink(q.join(q.status_path))
2302 except:
2305 except:
2303 pass
2306 pass
2304 return 0
2307 return 0
2305
2308
2306 def strip(ui, repo, rev, **opts):
2309 def strip(ui, repo, rev, **opts):
2307 """strip a revision and all its descendants from the repository
2310 """strip a revision and all its descendants from the repository
2308
2311
2309 If one of the working directory's parent revisions is stripped, the
2312 If one of the working directory's parent revisions is stripped, the
2310 working directory will be updated to the parent of the stripped
2313 working directory will be updated to the parent of the stripped
2311 revision.
2314 revision.
2312 """
2315 """
2313 backup = 'all'
2316 backup = 'all'
2314 if opts['backup']:
2317 if opts['backup']:
2315 backup = 'strip'
2318 backup = 'strip'
2316 elif opts['nobackup']:
2319 elif opts['nobackup']:
2317 backup = 'none'
2320 backup = 'none'
2318
2321
2319 rev = repo.lookup(rev)
2322 rev = repo.lookup(rev)
2320 p = repo.dirstate.parents()
2323 p = repo.dirstate.parents()
2321 cl = repo.changelog
2324 cl = repo.changelog
2322 update = True
2325 update = True
2323 if p[0] == nullid:
2326 if p[0] == nullid:
2324 update = False
2327 update = False
2325 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2328 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2326 update = False
2329 update = False
2327 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2330 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2328 update = False
2331 update = False
2329
2332
2330 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2333 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2331 return 0
2334 return 0
2332
2335
2333 def select(ui, repo, *args, **opts):
2336 def select(ui, repo, *args, **opts):
2334 '''set or print guarded patches to push
2337 '''set or print guarded patches to push
2335
2338
2336 Use the qguard command to set or print guards on patch, then use
2339 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
2340 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
2341 it has no guards or any positive guards match the currently
2339 selected guard, but will not be pushed if any negative guards
2342 selected guard, but will not be pushed if any negative guards
2340 match the current guard. For example::
2343 match the current guard. For example::
2341
2344
2342 qguard foo.patch -stable (negative guard)
2345 qguard foo.patch -stable (negative guard)
2343 qguard bar.patch +stable (positive guard)
2346 qguard bar.patch +stable (positive guard)
2344 qselect stable
2347 qselect stable
2345
2348
2346 This activates the "stable" guard. mq will skip foo.patch (because
2349 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
2350 it has a negative match) but push bar.patch (because it has a
2348 positive match).
2351 positive match).
2349
2352
2350 With no arguments, prints the currently active guards.
2353 With no arguments, prints the currently active guards.
2351 With one argument, sets the active guard.
2354 With one argument, sets the active guard.
2352
2355
2353 Use -n/--none to deactivate guards (no other arguments needed).
2356 Use -n/--none to deactivate guards (no other arguments needed).
2354 When no guards are active, patches with positive guards are
2357 When no guards are active, patches with positive guards are
2355 skipped and patches with negative guards are pushed.
2358 skipped and patches with negative guards are pushed.
2356
2359
2357 qselect can change the guards on applied patches. It does not pop
2360 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
2361 guarded patches by default. Use --pop to pop back to the last
2359 applied patch that is not guarded. Use --reapply (which implies
2362 applied patch that is not guarded. Use --reapply (which implies
2360 --pop) to push back to the current patch afterwards, but skip
2363 --pop) to push back to the current patch afterwards, but skip
2361 guarded patches.
2364 guarded patches.
2362
2365
2363 Use -s/--series to print a list of all guards in the series file
2366 Use -s/--series to print a list of all guards in the series file
2364 (no other arguments needed). Use -v for more information.'''
2367 (no other arguments needed). Use -v for more information.'''
2365
2368
2366 q = repo.mq
2369 q = repo.mq
2367 guards = q.active()
2370 guards = q.active()
2368 if args or opts['none']:
2371 if args or opts['none']:
2369 old_unapplied = q.unapplied(repo)
2372 old_unapplied = q.unapplied(repo)
2370 old_guarded = [i for i in xrange(len(q.applied)) if
2373 old_guarded = [i for i in xrange(len(q.applied)) if
2371 not q.pushable(i)[0]]
2374 not q.pushable(i)[0]]
2372 q.set_active(args)
2375 q.set_active(args)
2373 q.save_dirty()
2376 q.save_dirty()
2374 if not args:
2377 if not args:
2375 ui.status(_('guards deactivated\n'))
2378 ui.status(_('guards deactivated\n'))
2376 if not opts['pop'] and not opts['reapply']:
2379 if not opts['pop'] and not opts['reapply']:
2377 unapplied = q.unapplied(repo)
2380 unapplied = q.unapplied(repo)
2378 guarded = [i for i in xrange(len(q.applied))
2381 guarded = [i for i in xrange(len(q.applied))
2379 if not q.pushable(i)[0]]
2382 if not q.pushable(i)[0]]
2380 if len(unapplied) != len(old_unapplied):
2383 if len(unapplied) != len(old_unapplied):
2381 ui.status(_('number of unguarded, unapplied patches has '
2384 ui.status(_('number of unguarded, unapplied patches has '
2382 'changed from %d to %d\n') %
2385 'changed from %d to %d\n') %
2383 (len(old_unapplied), len(unapplied)))
2386 (len(old_unapplied), len(unapplied)))
2384 if len(guarded) != len(old_guarded):
2387 if len(guarded) != len(old_guarded):
2385 ui.status(_('number of guarded, applied patches has changed '
2388 ui.status(_('number of guarded, applied patches has changed '
2386 'from %d to %d\n') %
2389 'from %d to %d\n') %
2387 (len(old_guarded), len(guarded)))
2390 (len(old_guarded), len(guarded)))
2388 elif opts['series']:
2391 elif opts['series']:
2389 guards = {}
2392 guards = {}
2390 noguards = 0
2393 noguards = 0
2391 for gs in q.series_guards:
2394 for gs in q.series_guards:
2392 if not gs:
2395 if not gs:
2393 noguards += 1
2396 noguards += 1
2394 for g in gs:
2397 for g in gs:
2395 guards.setdefault(g, 0)
2398 guards.setdefault(g, 0)
2396 guards[g] += 1
2399 guards[g] += 1
2397 if ui.verbose:
2400 if ui.verbose:
2398 guards['NONE'] = noguards
2401 guards['NONE'] = noguards
2399 guards = guards.items()
2402 guards = guards.items()
2400 guards.sort(key=lambda x: x[0][1:])
2403 guards.sort(key=lambda x: x[0][1:])
2401 if guards:
2404 if guards:
2402 ui.note(_('guards in series file:\n'))
2405 ui.note(_('guards in series file:\n'))
2403 for guard, count in guards:
2406 for guard, count in guards:
2404 ui.note('%2d ' % count)
2407 ui.note('%2d ' % count)
2405 ui.write(guard, '\n')
2408 ui.write(guard, '\n')
2406 else:
2409 else:
2407 ui.note(_('no guards in series file\n'))
2410 ui.note(_('no guards in series file\n'))
2408 else:
2411 else:
2409 if guards:
2412 if guards:
2410 ui.note(_('active guards:\n'))
2413 ui.note(_('active guards:\n'))
2411 for g in guards:
2414 for g in guards:
2412 ui.write(g, '\n')
2415 ui.write(g, '\n')
2413 else:
2416 else:
2414 ui.write(_('no active guards\n'))
2417 ui.write(_('no active guards\n'))
2415 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2418 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2416 popped = False
2419 popped = False
2417 if opts['pop'] or opts['reapply']:
2420 if opts['pop'] or opts['reapply']:
2418 for i in xrange(len(q.applied)):
2421 for i in xrange(len(q.applied)):
2419 pushable, reason = q.pushable(i)
2422 pushable, reason = q.pushable(i)
2420 if not pushable:
2423 if not pushable:
2421 ui.status(_('popping guarded patches\n'))
2424 ui.status(_('popping guarded patches\n'))
2422 popped = True
2425 popped = True
2423 if i == 0:
2426 if i == 0:
2424 q.pop(repo, all=True)
2427 q.pop(repo, all=True)
2425 else:
2428 else:
2426 q.pop(repo, i-1)
2429 q.pop(repo, i-1)
2427 break
2430 break
2428 if popped:
2431 if popped:
2429 try:
2432 try:
2430 if reapply:
2433 if reapply:
2431 ui.status(_('reapplying unguarded patches\n'))
2434 ui.status(_('reapplying unguarded patches\n'))
2432 q.push(repo, reapply)
2435 q.push(repo, reapply)
2433 finally:
2436 finally:
2434 q.save_dirty()
2437 q.save_dirty()
2435
2438
2436 def finish(ui, repo, *revrange, **opts):
2439 def finish(ui, repo, *revrange, **opts):
2437 """move applied patches into repository history
2440 """move applied patches into repository history
2438
2441
2439 Finishes the specified revisions (corresponding to applied
2442 Finishes the specified revisions (corresponding to applied
2440 patches) by moving them out of mq control into regular repository
2443 patches) by moving them out of mq control into regular repository
2441 history.
2444 history.
2442
2445
2443 Accepts a revision range or the -a/--applied option. If --applied
2446 Accepts a revision range or the -a/--applied option. If --applied
2444 is specified, all applied mq revisions are removed from mq
2447 is specified, all applied mq revisions are removed from mq
2445 control. Otherwise, the given revisions must be at the base of the
2448 control. Otherwise, the given revisions must be at the base of the
2446 stack of applied patches.
2449 stack of applied patches.
2447
2450
2448 This can be especially useful if your changes have been applied to
2451 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
2452 an upstream repository, or if you are about to push your changes
2450 to upstream.
2453 to upstream.
2451 """
2454 """
2452 if not opts['applied'] and not revrange:
2455 if not opts['applied'] and not revrange:
2453 raise util.Abort(_('no revisions specified'))
2456 raise util.Abort(_('no revisions specified'))
2454 elif opts['applied']:
2457 elif opts['applied']:
2455 revrange = ('qbase:qtip',) + revrange
2458 revrange = ('qbase:qtip',) + revrange
2456
2459
2457 q = repo.mq
2460 q = repo.mq
2458 if not q.applied:
2461 if not q.applied:
2459 ui.status(_('no patches applied\n'))
2462 ui.status(_('no patches applied\n'))
2460 return 0
2463 return 0
2461
2464
2462 revs = cmdutil.revrange(repo, revrange)
2465 revs = cmdutil.revrange(repo, revrange)
2463 q.finish(repo, revs)
2466 q.finish(repo, revs)
2464 q.save_dirty()
2467 q.save_dirty()
2465 return 0
2468 return 0
2466
2469
2467 def reposetup(ui, repo):
2470 def reposetup(ui, repo):
2468 class mqrepo(repo.__class__):
2471 class mqrepo(repo.__class__):
2469 @util.propertycache
2472 @util.propertycache
2470 def mq(self):
2473 def mq(self):
2471 return queue(self.ui, self.join(""))
2474 return queue(self.ui, self.join(""))
2472
2475
2473 def abort_if_wdir_patched(self, errmsg, force=False):
2476 def abort_if_wdir_patched(self, errmsg, force=False):
2474 if self.mq.applied and not force:
2477 if self.mq.applied and not force:
2475 parent = hex(self.dirstate.parents()[0])
2478 parent = hex(self.dirstate.parents()[0])
2476 if parent in [s.rev for s in self.mq.applied]:
2479 if parent in [s.rev for s in self.mq.applied]:
2477 raise util.Abort(errmsg)
2480 raise util.Abort(errmsg)
2478
2481
2479 def commit(self, text="", user=None, date=None, match=None,
2482 def commit(self, text="", user=None, date=None, match=None,
2480 force=False, editor=False, extra={}):
2483 force=False, editor=False, extra={}):
2481 self.abort_if_wdir_patched(
2484 self.abort_if_wdir_patched(
2482 _('cannot commit over an applied mq patch'),
2485 _('cannot commit over an applied mq patch'),
2483 force)
2486 force)
2484
2487
2485 return super(mqrepo, self).commit(text, user, date, match, force,
2488 return super(mqrepo, self).commit(text, user, date, match, force,
2486 editor, extra)
2489 editor, extra)
2487
2490
2488 def push(self, remote, force=False, revs=None):
2491 def push(self, remote, force=False, revs=None):
2489 if self.mq.applied and not force and not revs:
2492 if self.mq.applied and not force and not revs:
2490 raise util.Abort(_('source has mq patches applied'))
2493 raise util.Abort(_('source has mq patches applied'))
2491 return super(mqrepo, self).push(remote, force, revs)
2494 return super(mqrepo, self).push(remote, force, revs)
2492
2495
2493 def _findtags(self):
2496 def _findtags(self):
2494 '''augment tags from base class with patch tags'''
2497 '''augment tags from base class with patch tags'''
2495 result = super(mqrepo, self)._findtags()
2498 result = super(mqrepo, self)._findtags()
2496
2499
2497 q = self.mq
2500 q = self.mq
2498 if not q.applied:
2501 if not q.applied:
2499 return result
2502 return result
2500
2503
2501 mqtags = [(bin(patch.rev), patch.name) for patch in q.applied]
2504 mqtags = [(bin(patch.rev), patch.name) for patch in q.applied]
2502
2505
2503 if mqtags[-1][0] not in self.changelog.nodemap:
2506 if mqtags[-1][0] not in self.changelog.nodemap:
2504 self.ui.warn(_('mq status file refers to unknown node %s\n')
2507 self.ui.warn(_('mq status file refers to unknown node %s\n')
2505 % short(mqtags[-1][0]))
2508 % short(mqtags[-1][0]))
2506 return result
2509 return result
2507
2510
2508 mqtags.append((mqtags[-1][0], 'qtip'))
2511 mqtags.append((mqtags[-1][0], 'qtip'))
2509 mqtags.append((mqtags[0][0], 'qbase'))
2512 mqtags.append((mqtags[0][0], 'qbase'))
2510 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2513 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2511 tags = result[0]
2514 tags = result[0]
2512 for patch in mqtags:
2515 for patch in mqtags:
2513 if patch[1] in tags:
2516 if patch[1] in tags:
2514 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2517 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2515 % patch[1])
2518 % patch[1])
2516 else:
2519 else:
2517 tags[patch[1]] = patch[0]
2520 tags[patch[1]] = patch[0]
2518
2521
2519 return result
2522 return result
2520
2523
2521 def _branchtags(self, partial, lrev):
2524 def _branchtags(self, partial, lrev):
2522 q = self.mq
2525 q = self.mq
2523 if not q.applied:
2526 if not q.applied:
2524 return super(mqrepo, self)._branchtags(partial, lrev)
2527 return super(mqrepo, self)._branchtags(partial, lrev)
2525
2528
2526 cl = self.changelog
2529 cl = self.changelog
2527 qbasenode = bin(q.applied[0].rev)
2530 qbasenode = bin(q.applied[0].rev)
2528 if qbasenode not in cl.nodemap:
2531 if qbasenode not in cl.nodemap:
2529 self.ui.warn(_('mq status file refers to unknown node %s\n')
2532 self.ui.warn(_('mq status file refers to unknown node %s\n')
2530 % short(qbasenode))
2533 % short(qbasenode))
2531 return super(mqrepo, self)._branchtags(partial, lrev)
2534 return super(mqrepo, self)._branchtags(partial, lrev)
2532
2535
2533 qbase = cl.rev(qbasenode)
2536 qbase = cl.rev(qbasenode)
2534 start = lrev + 1
2537 start = lrev + 1
2535 if start < qbase:
2538 if start < qbase:
2536 # update the cache (excluding the patches) and save it
2539 # update the cache (excluding the patches) and save it
2537 self._updatebranchcache(partial, lrev+1, qbase)
2540 self._updatebranchcache(partial, lrev+1, qbase)
2538 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2541 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2539 start = qbase
2542 start = qbase
2540 # if start = qbase, the cache is as updated as it should be.
2543 # if start = qbase, the cache is as updated as it should be.
2541 # if start > qbase, the cache includes (part of) the patches.
2544 # if start > qbase, the cache includes (part of) the patches.
2542 # we might as well use it, but we won't save it.
2545 # we might as well use it, but we won't save it.
2543
2546
2544 # update the cache up to the tip
2547 # update the cache up to the tip
2545 self._updatebranchcache(partial, start, len(cl))
2548 self._updatebranchcache(partial, start, len(cl))
2546
2549
2547 return partial
2550 return partial
2548
2551
2549 if repo.local():
2552 if repo.local():
2550 repo.__class__ = mqrepo
2553 repo.__class__ = mqrepo
2551
2554
2552 def mqimport(orig, ui, repo, *args, **kwargs):
2555 def mqimport(orig, ui, repo, *args, **kwargs):
2553 if hasattr(repo, 'abort_if_wdir_patched') and not kwargs.get('no_commit', False):
2556 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'),
2557 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2555 kwargs.get('force'))
2558 kwargs.get('force'))
2556 return orig(ui, repo, *args, **kwargs)
2559 return orig(ui, repo, *args, **kwargs)
2557
2560
2558 def uisetup(ui):
2561 def uisetup(ui):
2559 extensions.wrapcommand(commands.table, 'import', mqimport)
2562 extensions.wrapcommand(commands.table, 'import', mqimport)
2560
2563
2561 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2564 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2562
2565
2563 cmdtable = {
2566 cmdtable = {
2564 "qapplied":
2567 "qapplied":
2565 (applied,
2568 (applied,
2566 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2569 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2567 _('hg qapplied [-1] [-s] [PATCH]')),
2570 _('hg qapplied [-1] [-s] [PATCH]')),
2568 "qclone":
2571 "qclone":
2569 (clone,
2572 (clone,
2570 [('', 'pull', None, _('use pull protocol to copy metadata')),
2573 [('', 'pull', None, _('use pull protocol to copy metadata')),
2571 ('U', 'noupdate', None, _('do not update the new working directories')),
2574 ('U', 'noupdate', None, _('do not update the new working directories')),
2572 ('', 'uncompressed', None,
2575 ('', 'uncompressed', None,
2573 _('use uncompressed transfer (fast over LAN)')),
2576 _('use uncompressed transfer (fast over LAN)')),
2574 ('p', 'patches', '', _('location of source patch repository')),
2577 ('p', 'patches', '', _('location of source patch repository')),
2575 ] + commands.remoteopts,
2578 ] + commands.remoteopts,
2576 _('hg qclone [OPTION]... SOURCE [DEST]')),
2579 _('hg qclone [OPTION]... SOURCE [DEST]')),
2577 "qcommit|qci":
2580 "qcommit|qci":
2578 (commit,
2581 (commit,
2579 commands.table["^commit|ci"][1],
2582 commands.table["^commit|ci"][1],
2580 _('hg qcommit [OPTION]... [FILE]...')),
2583 _('hg qcommit [OPTION]... [FILE]...')),
2581 "^qdiff":
2584 "^qdiff":
2582 (diff,
2585 (diff,
2583 commands.diffopts + commands.diffopts2 + commands.walkopts,
2586 commands.diffopts + commands.diffopts2 + commands.walkopts,
2584 _('hg qdiff [OPTION]... [FILE]...')),
2587 _('hg qdiff [OPTION]... [FILE]...')),
2585 "qdelete|qremove|qrm":
2588 "qdelete|qremove|qrm":
2586 (delete,
2589 (delete,
2587 [('k', 'keep', None, _('keep patch file')),
2590 [('k', 'keep', None, _('keep patch file')),
2588 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2591 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2589 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2592 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2590 'qfold':
2593 'qfold':
2591 (fold,
2594 (fold,
2592 [('e', 'edit', None, _('edit patch header')),
2595 [('e', 'edit', None, _('edit patch header')),
2593 ('k', 'keep', None, _('keep folded patch files')),
2596 ('k', 'keep', None, _('keep folded patch files')),
2594 ] + commands.commitopts,
2597 ] + commands.commitopts,
2595 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2598 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2596 'qgoto':
2599 'qgoto':
2597 (goto,
2600 (goto,
2598 [('f', 'force', None, _('overwrite any local changes'))],
2601 [('f', 'force', None, _('overwrite any local changes'))],
2599 _('hg qgoto [OPTION]... PATCH')),
2602 _('hg qgoto [OPTION]... PATCH')),
2600 'qguard':
2603 'qguard':
2601 (guard,
2604 (guard,
2602 [('l', 'list', None, _('list all patches and guards')),
2605 [('l', 'list', None, _('list all patches and guards')),
2603 ('n', 'none', None, _('drop all guards'))],
2606 ('n', 'none', None, _('drop all guards'))],
2604 _('hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...')),
2607 _('hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...')),
2605 'qheader': (header, [], _('hg qheader [PATCH]')),
2608 'qheader': (header, [], _('hg qheader [PATCH]')),
2606 "^qimport":
2609 "^qimport":
2607 (qimport,
2610 (qimport,
2608 [('e', 'existing', None, _('import file in patch directory')),
2611 [('e', 'existing', None, _('import file in patch directory')),
2609 ('n', 'name', '', _('name of patch file')),
2612 ('n', 'name', '', _('name of patch file')),
2610 ('f', 'force', None, _('overwrite existing files')),
2613 ('f', 'force', None, _('overwrite existing files')),
2611 ('r', 'rev', [], _('place existing revisions under mq control')),
2614 ('r', 'rev', [], _('place existing revisions under mq control')),
2612 ('g', 'git', None, _('use git extended diff format')),
2615 ('g', 'git', None, _('use git extended diff format')),
2613 ('P', 'push', None, _('qpush after importing'))],
2616 ('P', 'push', None, _('qpush after importing'))],
2614 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2617 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2615 "^qinit":
2618 "^qinit":
2616 (init,
2619 (init,
2617 [('c', 'create-repo', None, _('create queue repository'))],
2620 [('c', 'create-repo', None, _('create queue repository'))],
2618 _('hg qinit [-c]')),
2621 _('hg qinit [-c]')),
2619 "qnew":
2622 "qnew":
2620 (new,
2623 (new,
2621 [('e', 'edit', None, _('edit commit message')),
2624 [('e', 'edit', None, _('edit commit message')),
2622 ('f', 'force', None, _('import uncommitted changes into patch')),
2625 ('f', 'force', None, _('import uncommitted changes into patch')),
2623 ('g', 'git', None, _('use git extended diff format')),
2626 ('g', 'git', None, _('use git extended diff format')),
2624 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2627 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2625 ('u', 'user', '', _('add "From: <given user>" to patch')),
2628 ('u', 'user', '', _('add "From: <given user>" to patch')),
2626 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2629 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2627 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2630 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2628 ] + commands.walkopts + commands.commitopts,
2631 ] + commands.walkopts + commands.commitopts,
2629 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2632 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2630 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2633 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2631 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2634 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2632 "^qpop":
2635 "^qpop":
2633 (pop,
2636 (pop,
2634 [('a', 'all', None, _('pop all patches')),
2637 [('a', 'all', None, _('pop all patches')),
2635 ('n', 'name', '', _('queue name to pop')),
2638 ('n', 'name', '', _('queue name to pop')),
2636 ('f', 'force', None, _('forget any local changes to patched files'))],
2639 ('f', 'force', None, _('forget any local changes to patched files'))],
2637 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2640 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2638 "^qpush":
2641 "^qpush":
2639 (push,
2642 (push,
2640 [('f', 'force', None, _('apply if the patch has rejects')),
2643 [('f', 'force', None, _('apply if the patch has rejects')),
2641 ('l', 'list', None, _('list patch name in commit text')),
2644 ('l', 'list', None, _('list patch name in commit text')),
2642 ('a', 'all', None, _('apply all patches')),
2645 ('a', 'all', None, _('apply all patches')),
2643 ('m', 'merge', None, _('merge from another queue')),
2646 ('m', 'merge', None, _('merge from another queue')),
2644 ('n', 'name', '', _('merge queue name'))],
2647 ('n', 'name', '', _('merge queue name'))],
2645 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2648 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2646 "^qrefresh":
2649 "^qrefresh":
2647 (refresh,
2650 (refresh,
2648 [('e', 'edit', None, _('edit commit message')),
2651 [('e', 'edit', None, _('edit commit message')),
2649 ('g', 'git', None, _('use git extended diff format')),
2652 ('g', 'git', None, _('use git extended diff format')),
2650 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2653 ('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')),
2654 ('U', 'currentuser', None, _('add/update author field in patch with current user')),
2652 ('u', 'user', '', _('add/update author field in patch with given user')),
2655 ('u', 'user', '', _('add/update author field in patch with given user')),
2653 ('D', 'currentdate', None, _('add/update date field in patch with current date')),
2656 ('D', 'currentdate', None, _('add/update date field in patch with current date')),
2654 ('d', 'date', '', _('add/update date field in patch with given date'))
2657 ('d', 'date', '', _('add/update date field in patch with given date'))
2655 ] + commands.walkopts + commands.commitopts,
2658 ] + commands.walkopts + commands.commitopts,
2656 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2659 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2657 'qrename|qmv':
2660 'qrename|qmv':
2658 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2661 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2659 "qrestore":
2662 "qrestore":
2660 (restore,
2663 (restore,
2661 [('d', 'delete', None, _('delete save entry')),
2664 [('d', 'delete', None, _('delete save entry')),
2662 ('u', 'update', None, _('update queue working directory'))],
2665 ('u', 'update', None, _('update queue working directory'))],
2663 _('hg qrestore [-d] [-u] REV')),
2666 _('hg qrestore [-d] [-u] REV')),
2664 "qsave":
2667 "qsave":
2665 (save,
2668 (save,
2666 [('c', 'copy', None, _('copy patch directory')),
2669 [('c', 'copy', None, _('copy patch directory')),
2667 ('n', 'name', '', _('copy directory name')),
2670 ('n', 'name', '', _('copy directory name')),
2668 ('e', 'empty', None, _('clear queue status file')),
2671 ('e', 'empty', None, _('clear queue status file')),
2669 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2672 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2670 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2673 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2671 "qselect":
2674 "qselect":
2672 (select,
2675 (select,
2673 [('n', 'none', None, _('disable all guards')),
2676 [('n', 'none', None, _('disable all guards')),
2674 ('s', 'series', None, _('list all guards in series file')),
2677 ('s', 'series', None, _('list all guards in series file')),
2675 ('', 'pop', None, _('pop to before first guarded applied patch')),
2678 ('', 'pop', None, _('pop to before first guarded applied patch')),
2676 ('', 'reapply', None, _('pop, then reapply patches'))],
2679 ('', 'reapply', None, _('pop, then reapply patches'))],
2677 _('hg qselect [OPTION]... [GUARD]...')),
2680 _('hg qselect [OPTION]... [GUARD]...')),
2678 "qseries":
2681 "qseries":
2679 (series,
2682 (series,
2680 [('m', 'missing', None, _('print patches not in series')),
2683 [('m', 'missing', None, _('print patches not in series')),
2681 ] + seriesopts,
2684 ] + seriesopts,
2682 _('hg qseries [-ms]')),
2685 _('hg qseries [-ms]')),
2683 "^strip":
2686 "^strip":
2684 (strip,
2687 (strip,
2685 [('f', 'force', None, _('force removal with local changes')),
2688 [('f', 'force', None, _('force removal with local changes')),
2686 ('b', 'backup', None, _('bundle unrelated changesets')),
2689 ('b', 'backup', None, _('bundle unrelated changesets')),
2687 ('n', 'nobackup', None, _('no backups'))],
2690 ('n', 'nobackup', None, _('no backups'))],
2688 _('hg strip [-f] [-b] [-n] REV')),
2691 _('hg strip [-f] [-b] [-n] REV')),
2689 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2692 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2690 "qunapplied":
2693 "qunapplied":
2691 (unapplied,
2694 (unapplied,
2692 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2695 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2693 _('hg qunapplied [-1] [-s] [PATCH]')),
2696 _('hg qunapplied [-1] [-s] [PATCH]')),
2694 "qfinish":
2697 "qfinish":
2695 (finish,
2698 (finish,
2696 [('a', 'applied', None, _('finish all applied changesets'))],
2699 [('a', 'applied', None, _('finish all applied changesets'))],
2697 _('hg qfinish [-a] [REV]...')),
2700 _('hg qfinish [-a] [REV]...')),
2698 }
2701 }
@@ -1,561 +1,563
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 # setting columns & interactive tests truncating (issue1912)
146 echo % qseries
147 echo % qseries
147 hg qseries
148 COLUMNS=4 hg qseries --config ui.interactive=true
149 COLUMNS=20 hg qseries --config ui.interactive=true -vs
148 hg qpop
150 hg qpop
149 hg qseries -vs
151 hg qseries -vs
150 hg qpush
152 hg qpush
151
153
152 echo % qapplied
154 echo % qapplied
153 hg qapplied
155 hg qapplied
154
156
155 echo % qtop
157 echo % qtop
156 hg qtop
158 hg qtop
157
159
158 echo % prev
160 echo % prev
159 hg qapp -1
161 hg qapp -1
160
162
161 echo % next
163 echo % next
162 hg qunapp -1
164 hg qunapp -1
163
165
164 hg qpop
166 hg qpop
165 echo % commit should fail
167 echo % commit should fail
166 hg commit
168 hg commit
167
169
168 echo % push should fail
170 echo % push should fail
169 hg push ../../k
171 hg push ../../k
170
172
171 echo % import should fail
173 echo % import should fail
172 hg st .
174 hg st .
173 echo foo >> ../a
175 echo foo >> ../a
174 hg diff > ../../import.diff
176 hg diff > ../../import.diff
175 hg revert --no-backup ../a
177 hg revert --no-backup ../a
176 hg import ../../import.diff
178 hg import ../../import.diff
177 hg st
179 hg st
178 echo % import --no-commit should succeed
180 echo % import --no-commit should succeed
179 hg import --no-commit ../../import.diff
181 hg import --no-commit ../../import.diff
180 hg st
182 hg st
181 hg revert --no-backup ../a
183 hg revert --no-backup ../a
182
184
183 echo % qunapplied
185 echo % qunapplied
184 hg qunapplied
186 hg qunapplied
185
187
186 echo % qpush/qpop with index
188 echo % qpush/qpop with index
187 hg qnew test1b.patch
189 hg qnew test1b.patch
188 echo 1b > 1b
190 echo 1b > 1b
189 hg add 1b
191 hg add 1b
190 hg qrefresh
192 hg qrefresh
191 hg qpush 2
193 hg qpush 2
192 hg qpop 0
194 hg qpop 0
193 hg qpush test.patch+1
195 hg qpush test.patch+1
194 hg qpush test.patch+2
196 hg qpush test.patch+2
195 hg qpop test2.patch-1
197 hg qpop test2.patch-1
196 hg qpop test2.patch-2
198 hg qpop test2.patch-2
197 hg qpush test1b.patch+1
199 hg qpush test1b.patch+1
198
200
199 echo % pop, qapplied, qunapplied
201 echo % pop, qapplied, qunapplied
200 hg qseries -v
202 hg qseries -v
201 echo % qapplied -1 test.patch
203 echo % qapplied -1 test.patch
202 hg qapplied -1 test.patch
204 hg qapplied -1 test.patch
203 echo % qapplied -1 test1b.patch
205 echo % qapplied -1 test1b.patch
204 hg qapplied -1 test1b.patch
206 hg qapplied -1 test1b.patch
205 echo % qapplied -1 test2.patch
207 echo % qapplied -1 test2.patch
206 hg qapplied -1 test2.patch
208 hg qapplied -1 test2.patch
207 echo % qapplied -1
209 echo % qapplied -1
208 hg qapplied -1
210 hg qapplied -1
209 echo % qapplied
211 echo % qapplied
210 hg qapplied
212 hg qapplied
211 echo % qapplied test1b.patch
213 echo % qapplied test1b.patch
212 hg qapplied test1b.patch
214 hg qapplied test1b.patch
213 echo % qunapplied -1
215 echo % qunapplied -1
214 hg qunapplied -1
216 hg qunapplied -1
215 echo % qunapplied
217 echo % qunapplied
216 hg qunapplied
218 hg qunapplied
217 echo % popping
219 echo % popping
218 hg qpop
220 hg qpop
219 echo % qunapplied -1
221 echo % qunapplied -1
220 hg qunapplied -1
222 hg qunapplied -1
221 echo % qunapplied
223 echo % qunapplied
222 hg qunapplied
224 hg qunapplied
223 echo % qunapplied test2.patch
225 echo % qunapplied test2.patch
224 hg qunapplied test2.patch
226 hg qunapplied test2.patch
225 echo % qunapplied -1 test2.patch
227 echo % qunapplied -1 test2.patch
226 hg qunapplied -1 test2.patch
228 hg qunapplied -1 test2.patch
227 echo % popping -a
229 echo % popping -a
228 hg qpop -a
230 hg qpop -a
229 echo % qapplied
231 echo % qapplied
230 hg qapplied
232 hg qapplied
231 echo % qapplied -1
233 echo % qapplied -1
232 hg qapplied -1
234 hg qapplied -1
233 hg qpush
235 hg qpush
234
236
235 echo % push should succeed
237 echo % push should succeed
236 hg qpop -a
238 hg qpop -a
237 hg push ../../k
239 hg push ../../k
238
240
239 echo % qpush/qpop error codes
241 echo % qpush/qpop error codes
240 errorcode()
242 errorcode()
241 {
243 {
242 hg "$@" && echo " $@ succeeds" || echo " $@ fails"
244 hg "$@" && echo " $@ succeeds" || echo " $@ fails"
243 }
245 }
244
246
245 # we want to start with some patches applied
247 # we want to start with some patches applied
246 hg qpush -a
248 hg qpush -a
247 echo " % pops all patches and succeeds"
249 echo " % pops all patches and succeeds"
248 errorcode qpop -a
250 errorcode qpop -a
249 echo " % does nothing and succeeds"
251 echo " % does nothing and succeeds"
250 errorcode qpop -a
252 errorcode qpop -a
251 echo " % fails - nothing else to pop"
253 echo " % fails - nothing else to pop"
252 errorcode qpop
254 errorcode qpop
253 echo " % pushes a patch and succeeds"
255 echo " % pushes a patch and succeeds"
254 errorcode qpush
256 errorcode qpush
255 echo " % pops a patch and succeeds"
257 echo " % pops a patch and succeeds"
256 errorcode qpop
258 errorcode qpop
257 echo " % pushes up to test1b.patch and succeeds"
259 echo " % pushes up to test1b.patch and succeeds"
258 errorcode qpush test1b.patch
260 errorcode qpush test1b.patch
259 echo " % does nothing and succeeds"
261 echo " % does nothing and succeeds"
260 errorcode qpush test1b.patch
262 errorcode qpush test1b.patch
261 echo " % does nothing and succeeds"
263 echo " % does nothing and succeeds"
262 errorcode qpop test1b.patch
264 errorcode qpop test1b.patch
263 echo " % fails - can't push to this patch"
265 echo " % fails - can't push to this patch"
264 errorcode qpush test.patch
266 errorcode qpush test.patch
265 echo " % fails - can't pop to this patch"
267 echo " % fails - can't pop to this patch"
266 errorcode qpop test2.patch
268 errorcode qpop test2.patch
267 echo " % pops up to test.patch and succeeds"
269 echo " % pops up to test.patch and succeeds"
268 errorcode qpop test.patch
270 errorcode qpop test.patch
269 echo " % pushes all patches and succeeds"
271 echo " % pushes all patches and succeeds"
270 errorcode qpush -a
272 errorcode qpush -a
271 echo " % does nothing and succeeds"
273 echo " % does nothing and succeeds"
272 errorcode qpush -a
274 errorcode qpush -a
273 echo " % fails - nothing else to push"
275 echo " % fails - nothing else to push"
274 errorcode qpush
276 errorcode qpush
275 echo " % does nothing and succeeds"
277 echo " % does nothing and succeeds"
276 errorcode qpush test2.patch
278 errorcode qpush test2.patch
277
279
278
280
279 echo % strip
281 echo % strip
280 cd ../../b
282 cd ../../b
281 echo x>x
283 echo x>x
282 hg ci -Ama
284 hg ci -Ama
283 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
285 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
284 hg unbundle .hg/strip-backup/*
286 hg unbundle .hg/strip-backup/*
285
287
286 echo % strip with local changes, should complain
288 echo % strip with local changes, should complain
287 hg up
289 hg up
288 echo y>y
290 echo y>y
289 hg add y
291 hg add y
290 hg strip tip | sed 's/\(saving bundle to \).*/\1/'
292 hg strip tip | sed 's/\(saving bundle to \).*/\1/'
291 echo % --force strip with local changes
293 echo % --force strip with local changes
292 hg strip -f tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
294 hg strip -f tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
293
295
294 echo '% cd b; hg qrefresh'
296 echo '% cd b; hg qrefresh'
295 hg init refresh
297 hg init refresh
296 cd refresh
298 cd refresh
297 echo a > a
299 echo a > a
298 hg ci -Ama
300 hg ci -Ama
299 hg qnew -mfoo foo
301 hg qnew -mfoo foo
300 echo a >> a
302 echo a >> a
301 hg qrefresh
303 hg qrefresh
302 mkdir b
304 mkdir b
303 cd b
305 cd b
304 echo f > f
306 echo f > f
305 hg add f
307 hg add f
306 hg qrefresh
308 hg qrefresh
307 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
309 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
308 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
310 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
309 echo % hg qrefresh .
311 echo % hg qrefresh .
310 hg qrefresh .
312 hg qrefresh .
311 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
313 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
312 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
314 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
313 hg status
315 hg status
314
316
315 echo % qpush failure
317 echo % qpush failure
316 cd ..
318 cd ..
317 hg qrefresh
319 hg qrefresh
318 hg qnew -mbar bar
320 hg qnew -mbar bar
319 echo foo > foo
321 echo foo > foo
320 echo bar > bar
322 echo bar > bar
321 hg add foo bar
323 hg add foo bar
322 hg qrefresh
324 hg qrefresh
323 hg qpop -a
325 hg qpop -a
324 echo bar > foo
326 echo bar > foo
325 hg qpush -a
327 hg qpush -a
326 hg st
328 hg st
327
329
328 echo % mq tags
330 echo % mq tags
329 hg log --template '{rev} {tags}\n' -r qparent:qtip
331 hg log --template '{rev} {tags}\n' -r qparent:qtip
330
332
331 echo % bad node in status
333 echo % bad node in status
332 hg qpop
334 hg qpop
333 hg strip -qn tip
335 hg strip -qn tip
334 hg tip 2>&1 | sed -e 's/unknown node .*/unknown node/'
336 hg tip 2>&1 | sed -e 's/unknown node .*/unknown node/'
335 hg branches 2>&1 | sed -e 's/unknown node .*/unknown node/'
337 hg branches 2>&1 | sed -e 's/unknown node .*/unknown node/'
336 hg qpop 2>&1 | sed -e 's/unknown node .*/unknown node/'
338 hg qpop 2>&1 | sed -e 's/unknown node .*/unknown node/'
337
339
338 cat >>$HGRCPATH <<EOF
340 cat >>$HGRCPATH <<EOF
339 [diff]
341 [diff]
340 git = True
342 git = True
341 EOF
343 EOF
342 cd ..
344 cd ..
343 hg init git
345 hg init git
344 cd git
346 cd git
345 hg qinit
347 hg qinit
346
348
347 hg qnew -m'new file' new
349 hg qnew -m'new file' new
348 echo foo > new
350 echo foo > new
349 chmod +x new
351 chmod +x new
350 hg add new
352 hg add new
351 hg qrefresh
353 hg qrefresh
352 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
354 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
353 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
355 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
354
356
355 hg qnew -m'copy file' copy
357 hg qnew -m'copy file' copy
356 hg cp new copy
358 hg cp new copy
357 hg qrefresh
359 hg qrefresh
358 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
360 sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
359 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
361 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
360
362
361 hg qpop
363 hg qpop
362 hg qpush
364 hg qpush
363 hg qdiff
365 hg qdiff
364 cat >>$HGRCPATH <<EOF
366 cat >>$HGRCPATH <<EOF
365 [diff]
367 [diff]
366 git = False
368 git = False
367 EOF
369 EOF
368 hg qdiff --git
370 hg qdiff --git
369
371
370 cd ..
372 cd ..
371 hg init slow
373 hg init slow
372 cd slow
374 cd slow
373 hg qinit
375 hg qinit
374 echo foo > foo
376 echo foo > foo
375 hg add foo
377 hg add foo
376 hg ci -m 'add foo'
378 hg ci -m 'add foo'
377 hg qnew bar
379 hg qnew bar
378 echo bar > bar
380 echo bar > bar
379 hg add bar
381 hg add bar
380 hg mv foo baz
382 hg mv foo baz
381 hg qrefresh --git
383 hg qrefresh --git
382 hg up -C 0
384 hg up -C 0
383 echo >> foo
385 echo >> foo
384 hg ci -m 'change foo'
386 hg ci -m 'change foo'
385 hg up -C 1
387 hg up -C 1
386 hg qrefresh --git 2>&1 | grep -v 'saving bundle'
388 hg qrefresh --git 2>&1 | grep -v 'saving bundle'
387 cat .hg/patches/bar
389 cat .hg/patches/bar
388 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
390 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
389 hg qrefresh --git
391 hg qrefresh --git
390 cat .hg/patches/bar
392 cat .hg/patches/bar
391 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
393 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
392 hg qrefresh
394 hg qrefresh
393 grep 'diff --git' .hg/patches/bar
395 grep 'diff --git' .hg/patches/bar
394
396
395 echo
397 echo
396 hg up -C 1
398 hg up -C 1
397 echo >> foo
399 echo >> foo
398 hg ci -m 'change foo again'
400 hg ci -m 'change foo again'
399 hg up -C 2
401 hg up -C 2
400 hg mv bar quux
402 hg mv bar quux
401 hg mv baz bleh
403 hg mv baz bleh
402 hg qrefresh --git 2>&1 | grep -v 'saving bundle'
404 hg qrefresh --git 2>&1 | grep -v 'saving bundle'
403 cat .hg/patches/bar
405 cat .hg/patches/bar
404 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
406 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
405 hg mv quux fred
407 hg mv quux fred
406 hg mv bleh barney
408 hg mv bleh barney
407 hg qrefresh --git
409 hg qrefresh --git
408 cat .hg/patches/bar
410 cat .hg/patches/bar
409 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
411 hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
410
412
411 echo % refresh omitting an added file
413 echo % refresh omitting an added file
412 hg qnew baz
414 hg qnew baz
413 echo newfile > newfile
415 echo newfile > newfile
414 hg add newfile
416 hg add newfile
415 hg qrefresh
417 hg qrefresh
416 hg st -A newfile
418 hg st -A newfile
417 hg qrefresh -X newfile
419 hg qrefresh -X newfile
418 hg st -A newfile
420 hg st -A newfile
419 hg revert newfile
421 hg revert newfile
420 rm newfile
422 rm newfile
421 hg qpop
423 hg qpop
422 hg qdel baz
424 hg qdel baz
423
425
424 echo % create a git patch
426 echo % create a git patch
425 echo a > alexander
427 echo a > alexander
426 hg add alexander
428 hg add alexander
427 hg qnew -f --git addalexander
429 hg qnew -f --git addalexander
428 grep diff .hg/patches/addalexander
430 grep diff .hg/patches/addalexander
429
431
430 echo % create a git binary patch
432 echo % create a git binary patch
431 cat > writebin.py <<EOF
433 cat > writebin.py <<EOF
432 import sys
434 import sys
433 path = sys.argv[1]
435 path = sys.argv[1]
434 open(path, 'wb').write('BIN\x00ARY')
436 open(path, 'wb').write('BIN\x00ARY')
435 EOF
437 EOF
436 python writebin.py bucephalus
438 python writebin.py bucephalus
437
439
438 python "$TESTDIR/md5sum.py" bucephalus
440 python "$TESTDIR/md5sum.py" bucephalus
439 hg add bucephalus
441 hg add bucephalus
440 hg qnew -f --git addbucephalus
442 hg qnew -f --git addbucephalus
441 grep diff .hg/patches/addbucephalus
443 grep diff .hg/patches/addbucephalus
442
444
443 echo % check binary patches can be popped and pushed
445 echo % check binary patches can be popped and pushed
444 hg qpop
446 hg qpop
445 test -f bucephalus && echo % bucephalus should not be there
447 test -f bucephalus && echo % bucephalus should not be there
446 hg qpush
448 hg qpush
447 test -f bucephalus || echo % bucephalus should be there
449 test -f bucephalus || echo % bucephalus should be there
448 python "$TESTDIR/md5sum.py" bucephalus
450 python "$TESTDIR/md5sum.py" bucephalus
449
451
450
452
451 echo '% strip again'
453 echo '% strip again'
452 cd ..
454 cd ..
453 hg init strip
455 hg init strip
454 cd strip
456 cd strip
455 touch foo
457 touch foo
456 hg add foo
458 hg add foo
457 hg ci -m 'add foo'
459 hg ci -m 'add foo'
458 echo >> foo
460 echo >> foo
459 hg ci -m 'change foo 1'
461 hg ci -m 'change foo 1'
460 hg up -C 0
462 hg up -C 0
461 echo 1 >> foo
463 echo 1 >> foo
462 hg ci -m 'change foo 2'
464 hg ci -m 'change foo 2'
463 HGMERGE=true hg merge
465 HGMERGE=true hg merge
464 hg ci -m merge
466 hg ci -m merge
465 hg log
467 hg log
466 hg strip 1 2>&1 | sed 's/\(saving bundle to \).*/\1/'
468 hg strip 1 2>&1 | sed 's/\(saving bundle to \).*/\1/'
467 checkundo strip
469 checkundo strip
468 hg log
470 hg log
469 cd ..
471 cd ..
470
472
471 echo '% qclone'
473 echo '% qclone'
472 qlog()
474 qlog()
473 {
475 {
474 echo 'main repo:'
476 echo 'main repo:'
475 hg log --template ' rev {rev}: {desc}\n'
477 hg log --template ' rev {rev}: {desc}\n'
476 echo 'patch repo:'
478 echo 'patch repo:'
477 hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
479 hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
478 }
480 }
479 hg init qclonesource
481 hg init qclonesource
480 cd qclonesource
482 cd qclonesource
481 echo foo > foo
483 echo foo > foo
482 hg add foo
484 hg add foo
483 hg ci -m 'add foo'
485 hg ci -m 'add foo'
484 hg qinit
486 hg qinit
485 hg qnew patch1
487 hg qnew patch1
486 echo bar >> foo
488 echo bar >> foo
487 hg qrefresh -m 'change foo'
489 hg qrefresh -m 'change foo'
488 cd ..
490 cd ..
489
491
490 # repo with unversioned patch dir
492 # repo with unversioned patch dir
491 hg qclone qclonesource failure
493 hg qclone qclonesource failure
492
494
493 cd qclonesource
495 cd qclonesource
494 hg qinit -c
496 hg qinit -c
495 hg qci -m checkpoint
497 hg qci -m checkpoint
496 qlog
498 qlog
497 cd ..
499 cd ..
498
500
499 # repo with patches applied
501 # repo with patches applied
500 hg qclone qclonesource qclonedest
502 hg qclone qclonesource qclonedest
501 cd qclonedest
503 cd qclonedest
502 qlog
504 qlog
503 cd ..
505 cd ..
504
506
505 # repo with patches unapplied
507 # repo with patches unapplied
506 cd qclonesource
508 cd qclonesource
507 hg qpop -a
509 hg qpop -a
508 qlog
510 qlog
509 cd ..
511 cd ..
510 hg qclone qclonesource qclonedest2
512 hg qclone qclonesource qclonedest2
511 cd qclonedest2
513 cd qclonedest2
512 qlog
514 qlog
513 cd ..
515 cd ..
514
516
515 echo % 'test applying on an empty file (issue 1033)'
517 echo % 'test applying on an empty file (issue 1033)'
516 hg init empty
518 hg init empty
517 cd empty
519 cd empty
518 touch a
520 touch a
519 hg ci -Am addempty
521 hg ci -Am addempty
520 echo a > a
522 echo a > a
521 hg qnew -f -e changea
523 hg qnew -f -e changea
522 hg qpop
524 hg qpop
523 hg qpush
525 hg qpush
524 cd ..
526 cd ..
525
527
526 echo % test qpush with --force, issue1087
528 echo % test qpush with --force, issue1087
527 hg init forcepush
529 hg init forcepush
528 cd forcepush
530 cd forcepush
529 echo hello > hello.txt
531 echo hello > hello.txt
530 echo bye > bye.txt
532 echo bye > bye.txt
531 hg ci -Ama
533 hg ci -Ama
532 hg qnew -d '0 0' empty
534 hg qnew -d '0 0' empty
533 hg qpop
535 hg qpop
534 echo world >> hello.txt
536 echo world >> hello.txt
535
537
536 echo % qpush should fail, local changes
538 echo % qpush should fail, local changes
537 hg qpush
539 hg qpush
538
540
539 echo % apply force, should not discard changes with empty patch
541 echo % apply force, should not discard changes with empty patch
540 hg qpush -f 2>&1 | sed 's,^.*/patch,patch,g'
542 hg qpush -f 2>&1 | sed 's,^.*/patch,patch,g'
541 hg diff --config diff.nodates=True
543 hg diff --config diff.nodates=True
542 hg qdiff --config diff.nodates=True
544 hg qdiff --config diff.nodates=True
543 hg log -l1 -p
545 hg log -l1 -p
544 hg qref -d '0 0'
546 hg qref -d '0 0'
545 hg qpop
547 hg qpop
546 echo universe >> hello.txt
548 echo universe >> hello.txt
547 echo universe >> bye.txt
549 echo universe >> bye.txt
548
550
549 echo % qpush should fail, local changes
551 echo % qpush should fail, local changes
550 hg qpush
552 hg qpush
551
553
552 echo % apply force, should discard changes in hello, but not bye
554 echo % apply force, should discard changes in hello, but not bye
553 hg qpush -f
555 hg qpush -f
554 hg st
556 hg st
555 hg diff --config diff.nodates=True
557 hg diff --config diff.nodates=True
556 hg qdiff --config diff.nodates=True
558 hg qdiff --config diff.nodates=True
557
559
558 echo % test popping revisions not in working dir ancestry
560 echo % test popping revisions not in working dir ancestry
559 hg qseries -v
561 hg qseries -v
560 hg up qparent
562 hg up qparent
561 hg qpop
563 hg qpop
@@ -1,612 +1,614
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 0 A test.patch: f...
134 1 A test2.patch:
133 popping test2.patch
135 popping test2.patch
134 now at: test.patch
136 now at: test.patch
135 0 A test.patch: foo bar
137 0 A test.patch: foo bar
136 1 U test2.patch:
138 1 U test2.patch:
137 applying test2.patch
139 applying test2.patch
138 now at: test2.patch
140 now at: test2.patch
139 % qapplied
141 % qapplied
140 test.patch
142 test.patch
141 test2.patch
143 test2.patch
142 % qtop
144 % qtop
143 test2.patch
145 test2.patch
144 % prev
146 % prev
145 test.patch
147 test.patch
146 % next
148 % next
147 all patches applied
149 all patches applied
148 popping test2.patch
150 popping test2.patch
149 now at: test.patch
151 now at: test.patch
150 % commit should fail
152 % commit should fail
151 abort: cannot commit over an applied mq patch
153 abort: cannot commit over an applied mq patch
152 % push should fail
154 % push should fail
153 pushing to ../../k
155 pushing to ../../k
154 abort: source has mq patches applied
156 abort: source has mq patches applied
155 % import should fail
157 % import should fail
156 abort: cannot import over an applied patch
158 abort: cannot import over an applied patch
157 % import --no-commit should succeed
159 % import --no-commit should succeed
158 applying ../../import.diff
160 applying ../../import.diff
159 M a
161 M a
160 % qunapplied
162 % qunapplied
161 test2.patch
163 test2.patch
162 % qpush/qpop with index
164 % qpush/qpop with index
163 applying test2.patch
165 applying test2.patch
164 now at: test2.patch
166 now at: test2.patch
165 popping test2.patch
167 popping test2.patch
166 popping test1b.patch
168 popping test1b.patch
167 now at: test.patch
169 now at: test.patch
168 applying test1b.patch
170 applying test1b.patch
169 now at: test1b.patch
171 now at: test1b.patch
170 applying test2.patch
172 applying test2.patch
171 now at: test2.patch
173 now at: test2.patch
172 popping test2.patch
174 popping test2.patch
173 now at: test1b.patch
175 now at: test1b.patch
174 popping test1b.patch
176 popping test1b.patch
175 now at: test.patch
177 now at: test.patch
176 applying test1b.patch
178 applying test1b.patch
177 applying test2.patch
179 applying test2.patch
178 now at: test2.patch
180 now at: test2.patch
179 % pop, qapplied, qunapplied
181 % pop, qapplied, qunapplied
180 0 A test.patch
182 0 A test.patch
181 1 A test1b.patch
183 1 A test1b.patch
182 2 A test2.patch
184 2 A test2.patch
183 % qapplied -1 test.patch
185 % qapplied -1 test.patch
184 only one patch applied
186 only one patch applied
185 % qapplied -1 test1b.patch
187 % qapplied -1 test1b.patch
186 test.patch
188 test.patch
187 % qapplied -1 test2.patch
189 % qapplied -1 test2.patch
188 test1b.patch
190 test1b.patch
189 % qapplied -1
191 % qapplied -1
190 test1b.patch
192 test1b.patch
191 % qapplied
193 % qapplied
192 test.patch
194 test.patch
193 test1b.patch
195 test1b.patch
194 test2.patch
196 test2.patch
195 % qapplied test1b.patch
197 % qapplied test1b.patch
196 test.patch
198 test.patch
197 test1b.patch
199 test1b.patch
198 % qunapplied -1
200 % qunapplied -1
199 all patches applied
201 all patches applied
200 % qunapplied
202 % qunapplied
201 % popping
203 % popping
202 popping test2.patch
204 popping test2.patch
203 now at: test1b.patch
205 now at: test1b.patch
204 % qunapplied -1
206 % qunapplied -1
205 test2.patch
207 test2.patch
206 % qunapplied
208 % qunapplied
207 test2.patch
209 test2.patch
208 % qunapplied test2.patch
210 % qunapplied test2.patch
209 % qunapplied -1 test2.patch
211 % qunapplied -1 test2.patch
210 all patches applied
212 all patches applied
211 % popping -a
213 % popping -a
212 popping test1b.patch
214 popping test1b.patch
213 popping test.patch
215 popping test.patch
214 patch queue now empty
216 patch queue now empty
215 % qapplied
217 % qapplied
216 % qapplied -1
218 % qapplied -1
217 no patches applied
219 no patches applied
218 applying test.patch
220 applying test.patch
219 now at: test.patch
221 now at: test.patch
220 % push should succeed
222 % push should succeed
221 popping test.patch
223 popping test.patch
222 patch queue now empty
224 patch queue now empty
223 pushing to ../../k
225 pushing to ../../k
224 searching for changes
226 searching for changes
225 adding changesets
227 adding changesets
226 adding manifests
228 adding manifests
227 adding file changes
229 adding file changes
228 added 1 changesets with 1 changes to 1 files
230 added 1 changesets with 1 changes to 1 files
229 % qpush/qpop error codes
231 % qpush/qpop error codes
230 applying test.patch
232 applying test.patch
231 applying test1b.patch
233 applying test1b.patch
232 applying test2.patch
234 applying test2.patch
233 now at: test2.patch
235 now at: test2.patch
234 % pops all patches and succeeds
236 % pops all patches and succeeds
235 popping test2.patch
237 popping test2.patch
236 popping test1b.patch
238 popping test1b.patch
237 popping test.patch
239 popping test.patch
238 patch queue now empty
240 patch queue now empty
239 qpop -a succeeds
241 qpop -a succeeds
240 % does nothing and succeeds
242 % does nothing and succeeds
241 no patches applied
243 no patches applied
242 qpop -a succeeds
244 qpop -a succeeds
243 % fails - nothing else to pop
245 % fails - nothing else to pop
244 no patches applied
246 no patches applied
245 qpop fails
247 qpop fails
246 % pushes a patch and succeeds
248 % pushes a patch and succeeds
247 applying test.patch
249 applying test.patch
248 now at: test.patch
250 now at: test.patch
249 qpush succeeds
251 qpush succeeds
250 % pops a patch and succeeds
252 % pops a patch and succeeds
251 popping test.patch
253 popping test.patch
252 patch queue now empty
254 patch queue now empty
253 qpop succeeds
255 qpop succeeds
254 % pushes up to test1b.patch and succeeds
256 % pushes up to test1b.patch and succeeds
255 applying test.patch
257 applying test.patch
256 applying test1b.patch
258 applying test1b.patch
257 now at: test1b.patch
259 now at: test1b.patch
258 qpush test1b.patch succeeds
260 qpush test1b.patch succeeds
259 % does nothing and succeeds
261 % does nothing and succeeds
260 qpush: test1b.patch is already at the top
262 qpush: test1b.patch is already at the top
261 qpush test1b.patch succeeds
263 qpush test1b.patch succeeds
262 % does nothing and succeeds
264 % does nothing and succeeds
263 qpop: test1b.patch is already at the top
265 qpop: test1b.patch is already at the top
264 qpop test1b.patch succeeds
266 qpop test1b.patch succeeds
265 % fails - can't push to this patch
267 % fails - can't push to this patch
266 abort: cannot push to a previous patch: test.patch
268 abort: cannot push to a previous patch: test.patch
267 qpush test.patch fails
269 qpush test.patch fails
268 % fails - can't pop to this patch
270 % fails - can't pop to this patch
269 abort: patch test2.patch is not applied
271 abort: patch test2.patch is not applied
270 qpop test2.patch fails
272 qpop test2.patch fails
271 % pops up to test.patch and succeeds
273 % pops up to test.patch and succeeds
272 popping test1b.patch
274 popping test1b.patch
273 now at: test.patch
275 now at: test.patch
274 qpop test.patch succeeds
276 qpop test.patch succeeds
275 % pushes all patches and succeeds
277 % pushes all patches and succeeds
276 applying test1b.patch
278 applying test1b.patch
277 applying test2.patch
279 applying test2.patch
278 now at: test2.patch
280 now at: test2.patch
279 qpush -a succeeds
281 qpush -a succeeds
280 % does nothing and succeeds
282 % does nothing and succeeds
281 all patches are currently applied
283 all patches are currently applied
282 qpush -a succeeds
284 qpush -a succeeds
283 % fails - nothing else to push
285 % fails - nothing else to push
284 patch series already fully applied
286 patch series already fully applied
285 qpush fails
287 qpush fails
286 % does nothing and succeeds
288 % does nothing and succeeds
287 qpush: test2.patch is already at the top
289 qpush: test2.patch is already at the top
288 qpush test2.patch succeeds
290 qpush test2.patch succeeds
289 % strip
291 % strip
290 adding x
292 adding x
291 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
293 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
292 saving bundle to
294 saving bundle to
293 adding changesets
295 adding changesets
294 adding manifests
296 adding manifests
295 adding file changes
297 adding file changes
296 added 1 changesets with 1 changes to 1 files
298 added 1 changesets with 1 changes to 1 files
297 (run 'hg update' to get a working copy)
299 (run 'hg update' to get a working copy)
298 % strip with local changes, should complain
300 % strip with local changes, should complain
299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 abort: local changes found
302 abort: local changes found
301 % --force strip with local changes
303 % --force strip with local changes
302 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
304 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
303 saving bundle to
305 saving bundle to
304 % cd b; hg qrefresh
306 % cd b; hg qrefresh
305 adding a
307 adding a
306 foo
308 foo
307
309
308 diff -r cb9a9f314b8b a
310 diff -r cb9a9f314b8b a
309 --- a/a
311 --- a/a
310 +++ b/a
312 +++ b/a
311 @@ -1,1 +1,2 @@
313 @@ -1,1 +1,2 @@
312 a
314 a
313 +a
315 +a
314 diff -r cb9a9f314b8b b/f
316 diff -r cb9a9f314b8b b/f
315 --- /dev/null
317 --- /dev/null
316 +++ b/b/f
318 +++ b/b/f
317 @@ -0,0 +1,1 @@
319 @@ -0,0 +1,1 @@
318 +f
320 +f
319 % hg qrefresh .
321 % hg qrefresh .
320 foo
322 foo
321
323
322 diff -r cb9a9f314b8b b/f
324 diff -r cb9a9f314b8b b/f
323 --- /dev/null
325 --- /dev/null
324 +++ b/b/f
326 +++ b/b/f
325 @@ -0,0 +1,1 @@
327 @@ -0,0 +1,1 @@
326 +f
328 +f
327 M a
329 M a
328 % qpush failure
330 % qpush failure
329 popping bar
331 popping bar
330 popping foo
332 popping foo
331 patch queue now empty
333 patch queue now empty
332 applying foo
334 applying foo
333 applying bar
335 applying bar
334 file foo already exists
336 file foo already exists
335 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
337 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
336 patch failed, unable to continue (try -v)
338 patch failed, unable to continue (try -v)
337 patch failed, rejects left in working dir
339 patch failed, rejects left in working dir
338 errors during apply, please fix and refresh bar
340 errors during apply, please fix and refresh bar
339 ? foo
341 ? foo
340 ? foo.rej
342 ? foo.rej
341 % mq tags
343 % mq tags
342 0 qparent
344 0 qparent
343 1 qbase foo
345 1 qbase foo
344 2 qtip bar tip
346 2 qtip bar tip
345 % bad node in status
347 % bad node in status
346 popping bar
348 popping bar
347 now at: foo
349 now at: foo
348 changeset: 0:cb9a9f314b8b
350 changeset: 0:cb9a9f314b8b
349 mq status file refers to unknown node
351 mq status file refers to unknown node
350 tag: tip
352 tag: tip
351 user: test
353 user: test
352 date: Thu Jan 01 00:00:00 1970 +0000
354 date: Thu Jan 01 00:00:00 1970 +0000
353 summary: a
355 summary: a
354
356
355 mq status file refers to unknown node
357 mq status file refers to unknown node
356 default 0:cb9a9f314b8b
358 default 0:cb9a9f314b8b
357 abort: trying to pop unknown node
359 abort: trying to pop unknown node
358 new file
360 new file
359
361
360 diff --git a/new b/new
362 diff --git a/new b/new
361 new file mode 100755
363 new file mode 100755
362 --- /dev/null
364 --- /dev/null
363 +++ b/new
365 +++ b/new
364 @@ -0,0 +1,1 @@
366 @@ -0,0 +1,1 @@
365 +foo
367 +foo
366 copy file
368 copy file
367
369
368 diff --git a/new b/copy
370 diff --git a/new b/copy
369 copy from new
371 copy from new
370 copy to copy
372 copy to copy
371 popping copy
373 popping copy
372 now at: new
374 now at: new
373 applying copy
375 applying copy
374 now at: copy
376 now at: copy
375 diff --git a/new b/copy
377 diff --git a/new b/copy
376 copy from new
378 copy from new
377 copy to copy
379 copy to copy
378 diff --git a/new b/copy
380 diff --git a/new b/copy
379 copy from new
381 copy from new
380 copy to copy
382 copy to copy
381 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
383 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
382 created new head
384 created new head
383 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
385 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
384 popping bar
386 popping bar
385 adding branch
387 adding branch
386 adding changesets
388 adding changesets
387 adding manifests
389 adding manifests
388 adding file changes
390 adding file changes
389 added 1 changesets with 1 changes to 1 files
391 added 1 changesets with 1 changes to 1 files
390 patch queue now empty
392 patch queue now empty
391 (working directory not at a head)
393 (working directory not at a head)
392 applying bar
394 applying bar
393 now at: bar
395 now at: bar
394 diff --git a/bar b/bar
396 diff --git a/bar b/bar
395 new file mode 100644
397 new file mode 100644
396 --- /dev/null
398 --- /dev/null
397 +++ b/bar
399 +++ b/bar
398 @@ -0,0 +1,1 @@
400 @@ -0,0 +1,1 @@
399 +bar
401 +bar
400 diff --git a/foo b/baz
402 diff --git a/foo b/baz
401 rename from foo
403 rename from foo
402 rename to baz
404 rename to baz
403 2 baz (foo)
405 2 baz (foo)
404 diff --git a/bar b/bar
406 diff --git a/bar b/bar
405 new file mode 100644
407 new file mode 100644
406 --- /dev/null
408 --- /dev/null
407 +++ b/bar
409 +++ b/bar
408 @@ -0,0 +1,1 @@
410 @@ -0,0 +1,1 @@
409 +bar
411 +bar
410 diff --git a/foo b/baz
412 diff --git a/foo b/baz
411 rename from foo
413 rename from foo
412 rename to baz
414 rename to baz
413 2 baz (foo)
415 2 baz (foo)
414 diff --git a/bar b/bar
416 diff --git a/bar b/bar
415 diff --git a/foo b/baz
417 diff --git a/foo b/baz
416
418
417 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
419 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
418 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 popping bar
421 popping bar
420 adding branch
422 adding branch
421 adding changesets
423 adding changesets
422 adding manifests
424 adding manifests
423 adding file changes
425 adding file changes
424 added 1 changesets with 1 changes to 1 files
426 added 1 changesets with 1 changes to 1 files
425 patch queue now empty
427 patch queue now empty
426 (working directory not at a head)
428 (working directory not at a head)
427 applying bar
429 applying bar
428 now at: bar
430 now at: bar
429 diff --git a/foo b/bleh
431 diff --git a/foo b/bleh
430 rename from foo
432 rename from foo
431 rename to bleh
433 rename to bleh
432 diff --git a/quux b/quux
434 diff --git a/quux b/quux
433 new file mode 100644
435 new file mode 100644
434 --- /dev/null
436 --- /dev/null
435 +++ b/quux
437 +++ b/quux
436 @@ -0,0 +1,1 @@
438 @@ -0,0 +1,1 @@
437 +bar
439 +bar
438 3 bleh (foo)
440 3 bleh (foo)
439 diff --git a/foo b/barney
441 diff --git a/foo b/barney
440 rename from foo
442 rename from foo
441 rename to barney
443 rename to barney
442 diff --git a/fred b/fred
444 diff --git a/fred b/fred
443 new file mode 100644
445 new file mode 100644
444 --- /dev/null
446 --- /dev/null
445 +++ b/fred
447 +++ b/fred
446 @@ -0,0 +1,1 @@
448 @@ -0,0 +1,1 @@
447 +bar
449 +bar
448 3 barney (foo)
450 3 barney (foo)
449 % refresh omitting an added file
451 % refresh omitting an added file
450 C newfile
452 C newfile
451 A newfile
453 A newfile
452 popping baz
454 popping baz
453 now at: bar
455 now at: bar
454 % create a git patch
456 % create a git patch
455 diff --git a/alexander b/alexander
457 diff --git a/alexander b/alexander
456 % create a git binary patch
458 % create a git binary patch
457 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
459 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
458 diff --git a/bucephalus b/bucephalus
460 diff --git a/bucephalus b/bucephalus
459 % check binary patches can be popped and pushed
461 % check binary patches can be popped and pushed
460 popping addbucephalus
462 popping addbucephalus
461 now at: addalexander
463 now at: addalexander
462 applying addbucephalus
464 applying addbucephalus
463 now at: addbucephalus
465 now at: addbucephalus
464 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
466 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
465 % strip again
467 % strip again
466 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
468 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
467 created new head
469 created new head
468 merging foo
470 merging foo
469 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
471 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
470 (branch merge, don't forget to commit)
472 (branch merge, don't forget to commit)
471 changeset: 3:99615015637b
473 changeset: 3:99615015637b
472 tag: tip
474 tag: tip
473 parent: 2:20cbbe65cff7
475 parent: 2:20cbbe65cff7
474 parent: 1:d2871fc282d4
476 parent: 1:d2871fc282d4
475 user: test
477 user: test
476 date: Thu Jan 01 00:00:00 1970 +0000
478 date: Thu Jan 01 00:00:00 1970 +0000
477 summary: merge
479 summary: merge
478
480
479 changeset: 2:20cbbe65cff7
481 changeset: 2:20cbbe65cff7
480 parent: 0:53245c60e682
482 parent: 0:53245c60e682
481 user: test
483 user: test
482 date: Thu Jan 01 00:00:00 1970 +0000
484 date: Thu Jan 01 00:00:00 1970 +0000
483 summary: change foo 2
485 summary: change foo 2
484
486
485 changeset: 1:d2871fc282d4
487 changeset: 1:d2871fc282d4
486 user: test
488 user: test
487 date: Thu Jan 01 00:00:00 1970 +0000
489 date: Thu Jan 01 00:00:00 1970 +0000
488 summary: change foo 1
490 summary: change foo 1
489
491
490 changeset: 0:53245c60e682
492 changeset: 0:53245c60e682
491 user: test
493 user: test
492 date: Thu Jan 01 00:00:00 1970 +0000
494 date: Thu Jan 01 00:00:00 1970 +0000
493 summary: add foo
495 summary: add foo
494
496
495 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
497 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 saving bundle to
498 saving bundle to
497 saving bundle to
499 saving bundle to
498 adding branch
500 adding branch
499 adding changesets
501 adding changesets
500 adding manifests
502 adding manifests
501 adding file changes
503 adding file changes
502 added 1 changesets with 1 changes to 1 files
504 added 1 changesets with 1 changes to 1 files
503 changeset: 1:20cbbe65cff7
505 changeset: 1:20cbbe65cff7
504 tag: tip
506 tag: tip
505 user: test
507 user: test
506 date: Thu Jan 01 00:00:00 1970 +0000
508 date: Thu Jan 01 00:00:00 1970 +0000
507 summary: change foo 2
509 summary: change foo 2
508
510
509 changeset: 0:53245c60e682
511 changeset: 0:53245c60e682
510 user: test
512 user: test
511 date: Thu Jan 01 00:00:00 1970 +0000
513 date: Thu Jan 01 00:00:00 1970 +0000
512 summary: add foo
514 summary: add foo
513
515
514 % qclone
516 % qclone
515 abort: versioned patch repository not found (see qinit -c)
517 abort: versioned patch repository not found (see qinit -c)
516 adding .hg/patches/patch1
518 adding .hg/patches/patch1
517 main repo:
519 main repo:
518 rev 1: change foo
520 rev 1: change foo
519 rev 0: add foo
521 rev 0: add foo
520 patch repo:
522 patch repo:
521 rev 0: checkpoint
523 rev 0: checkpoint
522 updating to branch default
524 updating to branch default
523 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
525 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
524 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
526 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
525 main repo:
527 main repo:
526 rev 0: add foo
528 rev 0: add foo
527 patch repo:
529 patch repo:
528 rev 0: checkpoint
530 rev 0: checkpoint
529 popping patch1
531 popping patch1
530 patch queue now empty
532 patch queue now empty
531 main repo:
533 main repo:
532 rev 0: add foo
534 rev 0: add foo
533 patch repo:
535 patch repo:
534 rev 0: checkpoint
536 rev 0: checkpoint
535 updating to branch default
537 updating to branch default
536 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
537 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 main repo:
540 main repo:
539 rev 0: add foo
541 rev 0: add foo
540 patch repo:
542 patch repo:
541 rev 0: checkpoint
543 rev 0: checkpoint
542 % test applying on an empty file (issue 1033)
544 % test applying on an empty file (issue 1033)
543 adding a
545 adding a
544 popping changea
546 popping changea
545 patch queue now empty
547 patch queue now empty
546 applying changea
548 applying changea
547 now at: changea
549 now at: changea
548 % test qpush with --force, issue1087
550 % test qpush with --force, issue1087
549 adding bye.txt
551 adding bye.txt
550 adding hello.txt
552 adding hello.txt
551 popping empty
553 popping empty
552 patch queue now empty
554 patch queue now empty
553 % qpush should fail, local changes
555 % qpush should fail, local changes
554 abort: local changes found, refresh first
556 abort: local changes found, refresh first
555 % apply force, should not discard changes with empty patch
557 % apply force, should not discard changes with empty patch
556 applying empty
558 applying empty
557 patch empty is empty
559 patch empty is empty
558 now at: empty
560 now at: empty
559 diff -r bf5fc3f07a0a hello.txt
561 diff -r bf5fc3f07a0a hello.txt
560 --- a/hello.txt
562 --- a/hello.txt
561 +++ b/hello.txt
563 +++ b/hello.txt
562 @@ -1,1 +1,2 @@
564 @@ -1,1 +1,2 @@
563 hello
565 hello
564 +world
566 +world
565 diff -r 9ecee4f634e3 hello.txt
567 diff -r 9ecee4f634e3 hello.txt
566 --- a/hello.txt
568 --- a/hello.txt
567 +++ b/hello.txt
569 +++ b/hello.txt
568 @@ -1,1 +1,2 @@
570 @@ -1,1 +1,2 @@
569 hello
571 hello
570 +world
572 +world
571 changeset: 1:bf5fc3f07a0a
573 changeset: 1:bf5fc3f07a0a
572 tag: qtip
574 tag: qtip
573 tag: tip
575 tag: tip
574 tag: empty
576 tag: empty
575 tag: qbase
577 tag: qbase
576 user: test
578 user: test
577 date: Thu Jan 01 00:00:00 1970 +0000
579 date: Thu Jan 01 00:00:00 1970 +0000
578 summary: imported patch empty
580 summary: imported patch empty
579
581
580
582
581 popping empty
583 popping empty
582 patch queue now empty
584 patch queue now empty
583 % qpush should fail, local changes
585 % qpush should fail, local changes
584 abort: local changes found, refresh first
586 abort: local changes found, refresh first
585 % apply force, should discard changes in hello, but not bye
587 % apply force, should discard changes in hello, but not bye
586 applying empty
588 applying empty
587 now at: empty
589 now at: empty
588 M bye.txt
590 M bye.txt
589 diff -r ba252371dbc1 bye.txt
591 diff -r ba252371dbc1 bye.txt
590 --- a/bye.txt
592 --- a/bye.txt
591 +++ b/bye.txt
593 +++ b/bye.txt
592 @@ -1,1 +1,2 @@
594 @@ -1,1 +1,2 @@
593 bye
595 bye
594 +universe
596 +universe
595 diff -r 9ecee4f634e3 bye.txt
597 diff -r 9ecee4f634e3 bye.txt
596 --- a/bye.txt
598 --- a/bye.txt
597 +++ b/bye.txt
599 +++ b/bye.txt
598 @@ -1,1 +1,2 @@
600 @@ -1,1 +1,2 @@
599 bye
601 bye
600 +universe
602 +universe
601 diff -r 9ecee4f634e3 hello.txt
603 diff -r 9ecee4f634e3 hello.txt
602 --- a/hello.txt
604 --- a/hello.txt
603 +++ b/hello.txt
605 +++ b/hello.txt
604 @@ -1,1 +1,3 @@
606 @@ -1,1 +1,3 @@
605 hello
607 hello
606 +world
608 +world
607 +universe
609 +universe
608 % test popping revisions not in working dir ancestry
610 % test popping revisions not in working dir ancestry
609 0 A empty
611 0 A empty
610 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
612 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
611 popping empty
613 popping empty
612 patch queue now empty
614 patch queue now empty
General Comments 0
You need to be logged in to leave comments. Login now