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