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