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