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