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