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