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