##// END OF EJS Templates
mq: add qnew --git option
Patrick Mezard -
r5025:7041869a default
parent child Browse files
Show More
@@ -1,2249 +1,2250 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 lock, wlock, tr
458 del lock, wlock, tr
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(_("queue top not at same revision as working directory"))
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)
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):
813 def getfile(f, rev):
814 t = repo.file(f).read(rev)
814 t = repo.file(f).read(rev)
815 repo.wfile(f, "w").write(t)
815 repo.wfile(f, "w").write(t)
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])
873 getfile(f, mmap[f])
874 for f in r:
874 for f in r:
875 getfile(f, mmap[f])
875 getfile(f, mmap[f])
876 util.set_exec(repo.wjoin(f), mmap.execf(f))
876 util.set_exec(repo.wjoin(f), mmap.execf(f))
877 for f in m + r:
877 for f in m + r:
878 repo.dirstate.normal(f)
878 repo.dirstate.normal(f)
879 for f in a:
879 for f in a:
880 try:
880 try:
881 os.unlink(repo.wjoin(f))
881 os.unlink(repo.wjoin(f))
882 except OSError, e:
882 except OSError, e:
883 if e.errno != errno.ENOENT:
883 if e.errno != errno.ENOENT:
884 raise
884 raise
885 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
885 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
886 except: pass
886 except: pass
887 repo.dirstate.forget(f)
887 repo.dirstate.forget(f)
888 repo.dirstate.setparents(qp, revlog.nullid)
888 repo.dirstate.setparents(qp, revlog.nullid)
889 self.strip(repo, rev, update=False, backup='strip')
889 self.strip(repo, rev, update=False, backup='strip')
890 del self.applied[start:end]
890 del self.applied[start:end]
891 if len(self.applied):
891 if len(self.applied):
892 self.ui.write("Now at: %s\n" % self.applied[-1].name)
892 self.ui.write("Now at: %s\n" % self.applied[-1].name)
893 else:
893 else:
894 self.ui.write("Patch queue now empty\n")
894 self.ui.write("Patch queue now empty\n")
895 finally:
895 finally:
896 del wlock
896 del wlock
897
897
898 def diff(self, repo, pats, opts):
898 def diff(self, repo, pats, opts):
899 top = self.check_toppatch(repo)
899 top = self.check_toppatch(repo)
900 if not top:
900 if not top:
901 self.ui.write("No patches applied\n")
901 self.ui.write("No patches applied\n")
902 return
902 return
903 qp = self.qparents(repo, top)
903 qp = self.qparents(repo, top)
904 if opts.get('git'):
904 if opts.get('git'):
905 self.diffopts().git = True
905 self.diffopts().git = True
906 self.printdiff(repo, qp, files=pats, opts=opts)
906 self.printdiff(repo, qp, files=pats, opts=opts)
907
907
908 def refresh(self, repo, pats=None, **opts):
908 def refresh(self, repo, pats=None, **opts):
909 if len(self.applied) == 0:
909 if len(self.applied) == 0:
910 self.ui.write("No patches applied\n")
910 self.ui.write("No patches applied\n")
911 return 1
911 return 1
912 wlock = repo.wlock()
912 wlock = repo.wlock()
913 try:
913 try:
914 self.check_toppatch(repo)
914 self.check_toppatch(repo)
915 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
915 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
916 top = revlog.bin(top)
916 top = revlog.bin(top)
917 cparents = repo.changelog.parents(top)
917 cparents = repo.changelog.parents(top)
918 patchparent = self.qparents(repo, top)
918 patchparent = self.qparents(repo, top)
919 message, comments, user, date, patchfound = self.readheaders(patchfn)
919 message, comments, user, date, patchfound = self.readheaders(patchfn)
920
920
921 patchf = self.opener(patchfn, 'r+')
921 patchf = self.opener(patchfn, 'r+')
922
922
923 # if the patch was a git patch, refresh it as a git patch
923 # if the patch was a git patch, refresh it as a git patch
924 for line in patchf:
924 for line in patchf:
925 if line.startswith('diff --git'):
925 if line.startswith('diff --git'):
926 self.diffopts().git = True
926 self.diffopts().git = True
927 break
927 break
928 patchf.seek(0)
928 patchf.seek(0)
929 patchf.truncate()
929 patchf.truncate()
930
930
931 msg = opts.get('msg', '').rstrip()
931 msg = opts.get('msg', '').rstrip()
932 if msg:
932 if msg:
933 if comments:
933 if comments:
934 # Remove existing message.
934 # Remove existing message.
935 ci = 0
935 ci = 0
936 subj = None
936 subj = None
937 for mi in xrange(len(message)):
937 for mi in xrange(len(message)):
938 if comments[ci].lower().startswith('subject: '):
938 if comments[ci].lower().startswith('subject: '):
939 subj = comments[ci][9:]
939 subj = comments[ci][9:]
940 while message[mi] != comments[ci] and message[mi] != subj:
940 while message[mi] != comments[ci] and message[mi] != subj:
941 ci += 1
941 ci += 1
942 del comments[ci]
942 del comments[ci]
943 comments.append(msg)
943 comments.append(msg)
944 if comments:
944 if comments:
945 comments = "\n".join(comments) + '\n\n'
945 comments = "\n".join(comments) + '\n\n'
946 patchf.write(comments)
946 patchf.write(comments)
947
947
948 if opts.get('git'):
948 if opts.get('git'):
949 self.diffopts().git = True
949 self.diffopts().git = True
950 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
950 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
951 tip = repo.changelog.tip()
951 tip = repo.changelog.tip()
952 if top == tip:
952 if top == tip:
953 # if the top of our patch queue is also the tip, there is an
953 # if the top of our patch queue is also the tip, there is an
954 # optimization here. We update the dirstate in place and strip
954 # optimization here. We update the dirstate in place and strip
955 # off the tip commit. Then just commit the current directory
955 # off the tip commit. Then just commit the current directory
956 # tree. We can also send repo.commit the list of files
956 # tree. We can also send repo.commit the list of files
957 # changed to speed up the diff
957 # changed to speed up the diff
958 #
958 #
959 # in short mode, we only diff the files included in the
959 # in short mode, we only diff the files included in the
960 # patch already
960 # patch already
961 #
961 #
962 # this should really read:
962 # this should really read:
963 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
963 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
964 # but we do it backwards to take advantage of manifest/chlog
964 # but we do it backwards to take advantage of manifest/chlog
965 # caching against the next repo.status call
965 # caching against the next repo.status call
966 #
966 #
967 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
967 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
968 changes = repo.changelog.read(tip)
968 changes = repo.changelog.read(tip)
969 man = repo.manifest.read(changes[0])
969 man = repo.manifest.read(changes[0])
970 aaa = aa[:]
970 aaa = aa[:]
971 if opts.get('short'):
971 if opts.get('short'):
972 filelist = mm + aa + dd
972 filelist = mm + aa + dd
973 match = dict.fromkeys(filelist).__contains__
973 match = dict.fromkeys(filelist).__contains__
974 else:
974 else:
975 filelist = None
975 filelist = None
976 match = util.always
976 match = util.always
977 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
977 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
978
978
979 # we might end up with files that were added between
979 # we might end up with files that were added between
980 # tip and the dirstate parent, but then changed in the
980 # tip and the dirstate parent, but then changed in the
981 # local dirstate. in this case, we want them to only
981 # local dirstate. in this case, we want them to only
982 # show up in the added section
982 # show up in the added section
983 for x in m:
983 for x in m:
984 if x not in aa:
984 if x not in aa:
985 mm.append(x)
985 mm.append(x)
986 # we might end up with files added by the local dirstate that
986 # we might end up with files added by the local dirstate that
987 # were deleted by the patch. In this case, they should only
987 # were deleted by the patch. In this case, they should only
988 # show up in the changed section.
988 # show up in the changed section.
989 for x in a:
989 for x in a:
990 if x in dd:
990 if x in dd:
991 del dd[dd.index(x)]
991 del dd[dd.index(x)]
992 mm.append(x)
992 mm.append(x)
993 else:
993 else:
994 aa.append(x)
994 aa.append(x)
995 # make sure any files deleted in the local dirstate
995 # make sure any files deleted in the local dirstate
996 # are not in the add or change column of the patch
996 # are not in the add or change column of the patch
997 forget = []
997 forget = []
998 for x in d + r:
998 for x in d + r:
999 if x in aa:
999 if x in aa:
1000 del aa[aa.index(x)]
1000 del aa[aa.index(x)]
1001 forget.append(x)
1001 forget.append(x)
1002 continue
1002 continue
1003 elif x in mm:
1003 elif x in mm:
1004 del mm[mm.index(x)]
1004 del mm[mm.index(x)]
1005 dd.append(x)
1005 dd.append(x)
1006
1006
1007 m = util.unique(mm)
1007 m = util.unique(mm)
1008 r = util.unique(dd)
1008 r = util.unique(dd)
1009 a = util.unique(aa)
1009 a = util.unique(aa)
1010 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1010 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1011 filelist = util.unique(c[0] + c[1] + c[2])
1011 filelist = util.unique(c[0] + c[1] + c[2])
1012 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1012 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1013 fp=patchf, changes=c, opts=self.diffopts())
1013 fp=patchf, changes=c, opts=self.diffopts())
1014 patchf.close()
1014 patchf.close()
1015
1015
1016 repo.dirstate.setparents(*cparents)
1016 repo.dirstate.setparents(*cparents)
1017 copies = {}
1017 copies = {}
1018 for dst in a:
1018 for dst in a:
1019 src = repo.dirstate.copied(dst)
1019 src = repo.dirstate.copied(dst)
1020 if src is None:
1020 if src is None:
1021 continue
1021 continue
1022 copies.setdefault(src, []).append(dst)
1022 copies.setdefault(src, []).append(dst)
1023 repo.dirstate.add(dst)
1023 repo.dirstate.add(dst)
1024 # remember the copies between patchparent and tip
1024 # remember the copies between patchparent and tip
1025 # this may be slow, so don't do it if we're not tracking copies
1025 # this may be slow, so don't do it if we're not tracking copies
1026 if self.diffopts().git:
1026 if self.diffopts().git:
1027 for dst in aaa:
1027 for dst in aaa:
1028 f = repo.file(dst)
1028 f = repo.file(dst)
1029 src = f.renamed(man[dst])
1029 src = f.renamed(man[dst])
1030 if src:
1030 if src:
1031 copies[src[0]] = copies.get(dst, [])
1031 copies[src[0]] = copies.get(dst, [])
1032 if dst in a:
1032 if dst in a:
1033 copies[src[0]].append(dst)
1033 copies[src[0]].append(dst)
1034 # we can't copy a file created by the patch itself
1034 # we can't copy a file created by the patch itself
1035 if dst in copies:
1035 if dst in copies:
1036 del copies[dst]
1036 del copies[dst]
1037 for src, dsts in copies.iteritems():
1037 for src, dsts in copies.iteritems():
1038 for dst in dsts:
1038 for dst in dsts:
1039 repo.dirstate.copy(src, dst)
1039 repo.dirstate.copy(src, dst)
1040 for f in r:
1040 for f in r:
1041 repo.dirstate.remove(f)
1041 repo.dirstate.remove(f)
1042 # if the patch excludes a modified file, mark that
1042 # if the patch excludes a modified file, mark that
1043 # file with mtime=0 so status can see it.
1043 # file with mtime=0 so status can see it.
1044 mm = []
1044 mm = []
1045 for i in xrange(len(m)-1, -1, -1):
1045 for i in xrange(len(m)-1, -1, -1):
1046 if not matchfn(m[i]):
1046 if not matchfn(m[i]):
1047 mm.append(m[i])
1047 mm.append(m[i])
1048 del m[i]
1048 del m[i]
1049 for f in m:
1049 for f in m:
1050 repo.dirstate.normal(f)
1050 repo.dirstate.normal(f)
1051 for f in mm:
1051 for f in mm:
1052 repo.dirstate.normaldirty(f)
1052 repo.dirstate.normaldirty(f)
1053 for f in forget:
1053 for f in forget:
1054 repo.dirstate.forget(f)
1054 repo.dirstate.forget(f)
1055
1055
1056 if not msg:
1056 if not msg:
1057 if not message:
1057 if not message:
1058 message = "[mq]: %s\n" % patchfn
1058 message = "[mq]: %s\n" % patchfn
1059 else:
1059 else:
1060 message = "\n".join(message)
1060 message = "\n".join(message)
1061 else:
1061 else:
1062 message = msg
1062 message = msg
1063
1063
1064 self.strip(repo, top, update=False,
1064 self.strip(repo, top, update=False,
1065 backup='strip')
1065 backup='strip')
1066 n = repo.commit(filelist, message, changes[1], match=matchfn,
1066 n = repo.commit(filelist, message, changes[1], match=matchfn,
1067 force=1)
1067 force=1)
1068 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1068 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1069 self.applied_dirty = 1
1069 self.applied_dirty = 1
1070 self.removeundo(repo)
1070 self.removeundo(repo)
1071 else:
1071 else:
1072 self.printdiff(repo, patchparent, fp=patchf)
1072 self.printdiff(repo, patchparent, fp=patchf)
1073 patchf.close()
1073 patchf.close()
1074 added = repo.status()[1]
1074 added = repo.status()[1]
1075 for a in added:
1075 for a in added:
1076 f = repo.wjoin(a)
1076 f = repo.wjoin(a)
1077 try:
1077 try:
1078 os.unlink(f)
1078 os.unlink(f)
1079 except OSError, e:
1079 except OSError, e:
1080 if e.errno != errno.ENOENT:
1080 if e.errno != errno.ENOENT:
1081 raise
1081 raise
1082 try: os.removedirs(os.path.dirname(f))
1082 try: os.removedirs(os.path.dirname(f))
1083 except: pass
1083 except: pass
1084 # forget the file copies in the dirstate
1084 # forget the file copies in the dirstate
1085 # push should readd the files later on
1085 # push should readd the files later on
1086 repo.dirstate.forget(a)
1086 repo.dirstate.forget(a)
1087 self.pop(repo, force=True)
1087 self.pop(repo, force=True)
1088 self.push(repo, force=True)
1088 self.push(repo, force=True)
1089 finally:
1089 finally:
1090 del wlock
1090 del wlock
1091
1091
1092 def init(self, repo, create=False):
1092 def init(self, repo, create=False):
1093 if not create and os.path.isdir(self.path):
1093 if not create and os.path.isdir(self.path):
1094 raise util.Abort(_("patch queue directory already exists"))
1094 raise util.Abort(_("patch queue directory already exists"))
1095 try:
1095 try:
1096 os.mkdir(self.path)
1096 os.mkdir(self.path)
1097 except OSError, inst:
1097 except OSError, inst:
1098 if inst.errno != errno.EEXIST or not create:
1098 if inst.errno != errno.EEXIST or not create:
1099 raise
1099 raise
1100 if create:
1100 if create:
1101 return self.qrepo(create=True)
1101 return self.qrepo(create=True)
1102
1102
1103 def unapplied(self, repo, patch=None):
1103 def unapplied(self, repo, patch=None):
1104 if patch and patch not in self.series:
1104 if patch and patch not in self.series:
1105 raise util.Abort(_("patch %s is not in series file") % patch)
1105 raise util.Abort(_("patch %s is not in series file") % patch)
1106 if not patch:
1106 if not patch:
1107 start = self.series_end()
1107 start = self.series_end()
1108 else:
1108 else:
1109 start = self.series.index(patch) + 1
1109 start = self.series.index(patch) + 1
1110 unapplied = []
1110 unapplied = []
1111 for i in xrange(start, len(self.series)):
1111 for i in xrange(start, len(self.series)):
1112 pushable, reason = self.pushable(i)
1112 pushable, reason = self.pushable(i)
1113 if pushable:
1113 if pushable:
1114 unapplied.append((i, self.series[i]))
1114 unapplied.append((i, self.series[i]))
1115 self.explain_pushable(i)
1115 self.explain_pushable(i)
1116 return unapplied
1116 return unapplied
1117
1117
1118 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1118 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1119 summary=False):
1119 summary=False):
1120 def displayname(patchname):
1120 def displayname(patchname):
1121 if summary:
1121 if summary:
1122 msg = self.readheaders(patchname)[0]
1122 msg = self.readheaders(patchname)[0]
1123 msg = msg and ': ' + msg[0] or ': '
1123 msg = msg and ': ' + msg[0] or ': '
1124 else:
1124 else:
1125 msg = ''
1125 msg = ''
1126 return '%s%s' % (patchname, msg)
1126 return '%s%s' % (patchname, msg)
1127
1127
1128 applied = dict.fromkeys([p.name for p in self.applied])
1128 applied = dict.fromkeys([p.name for p in self.applied])
1129 if length is None:
1129 if length is None:
1130 length = len(self.series) - start
1130 length = len(self.series) - start
1131 if not missing:
1131 if not missing:
1132 for i in xrange(start, start+length):
1132 for i in xrange(start, start+length):
1133 patch = self.series[i]
1133 patch = self.series[i]
1134 if patch in applied:
1134 if patch in applied:
1135 stat = 'A'
1135 stat = 'A'
1136 elif self.pushable(i)[0]:
1136 elif self.pushable(i)[0]:
1137 stat = 'U'
1137 stat = 'U'
1138 else:
1138 else:
1139 stat = 'G'
1139 stat = 'G'
1140 pfx = ''
1140 pfx = ''
1141 if self.ui.verbose:
1141 if self.ui.verbose:
1142 pfx = '%d %s ' % (i, stat)
1142 pfx = '%d %s ' % (i, stat)
1143 elif status and status != stat:
1143 elif status and status != stat:
1144 continue
1144 continue
1145 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1145 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1146 else:
1146 else:
1147 msng_list = []
1147 msng_list = []
1148 for root, dirs, files in os.walk(self.path):
1148 for root, dirs, files in os.walk(self.path):
1149 d = root[len(self.path) + 1:]
1149 d = root[len(self.path) + 1:]
1150 for f in files:
1150 for f in files:
1151 fl = os.path.join(d, f)
1151 fl = os.path.join(d, f)
1152 if (fl not in self.series and
1152 if (fl not in self.series and
1153 fl not in (self.status_path, self.series_path,
1153 fl not in (self.status_path, self.series_path,
1154 self.guards_path)
1154 self.guards_path)
1155 and not fl.startswith('.')):
1155 and not fl.startswith('.')):
1156 msng_list.append(fl)
1156 msng_list.append(fl)
1157 msng_list.sort()
1157 msng_list.sort()
1158 for x in msng_list:
1158 for x in msng_list:
1159 pfx = self.ui.verbose and ('D ') or ''
1159 pfx = self.ui.verbose and ('D ') or ''
1160 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1160 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1161
1161
1162 def issaveline(self, l):
1162 def issaveline(self, l):
1163 if l.name == '.hg.patches.save.line':
1163 if l.name == '.hg.patches.save.line':
1164 return True
1164 return True
1165
1165
1166 def qrepo(self, create=False):
1166 def qrepo(self, create=False):
1167 if create or os.path.isdir(self.join(".hg")):
1167 if create or os.path.isdir(self.join(".hg")):
1168 return hg.repository(self.ui, path=self.path, create=create)
1168 return hg.repository(self.ui, path=self.path, create=create)
1169
1169
1170 def restore(self, repo, rev, delete=None, qupdate=None):
1170 def restore(self, repo, rev, delete=None, qupdate=None):
1171 c = repo.changelog.read(rev)
1171 c = repo.changelog.read(rev)
1172 desc = c[4].strip()
1172 desc = c[4].strip()
1173 lines = desc.splitlines()
1173 lines = desc.splitlines()
1174 i = 0
1174 i = 0
1175 datastart = None
1175 datastart = None
1176 series = []
1176 series = []
1177 applied = []
1177 applied = []
1178 qpp = None
1178 qpp = None
1179 for i in xrange(0, len(lines)):
1179 for i in xrange(0, len(lines)):
1180 if lines[i] == 'Patch Data:':
1180 if lines[i] == 'Patch Data:':
1181 datastart = i + 1
1181 datastart = i + 1
1182 elif lines[i].startswith('Dirstate:'):
1182 elif lines[i].startswith('Dirstate:'):
1183 l = lines[i].rstrip()
1183 l = lines[i].rstrip()
1184 l = l[10:].split(' ')
1184 l = l[10:].split(' ')
1185 qpp = [ hg.bin(x) for x in l ]
1185 qpp = [ hg.bin(x) for x in l ]
1186 elif datastart != None:
1186 elif datastart != None:
1187 l = lines[i].rstrip()
1187 l = lines[i].rstrip()
1188 se = statusentry(l)
1188 se = statusentry(l)
1189 file_ = se.name
1189 file_ = se.name
1190 if se.rev:
1190 if se.rev:
1191 applied.append(se)
1191 applied.append(se)
1192 else:
1192 else:
1193 series.append(file_)
1193 series.append(file_)
1194 if datastart == None:
1194 if datastart == None:
1195 self.ui.warn("No saved patch data found\n")
1195 self.ui.warn("No saved patch data found\n")
1196 return 1
1196 return 1
1197 self.ui.warn("restoring status: %s\n" % lines[0])
1197 self.ui.warn("restoring status: %s\n" % lines[0])
1198 self.full_series = series
1198 self.full_series = series
1199 self.applied = applied
1199 self.applied = applied
1200 self.parse_series()
1200 self.parse_series()
1201 self.series_dirty = 1
1201 self.series_dirty = 1
1202 self.applied_dirty = 1
1202 self.applied_dirty = 1
1203 heads = repo.changelog.heads()
1203 heads = repo.changelog.heads()
1204 if delete:
1204 if delete:
1205 if rev not in heads:
1205 if rev not in heads:
1206 self.ui.warn("save entry has children, leaving it alone\n")
1206 self.ui.warn("save entry has children, leaving it alone\n")
1207 else:
1207 else:
1208 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1208 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1209 pp = repo.dirstate.parents()
1209 pp = repo.dirstate.parents()
1210 if rev in pp:
1210 if rev in pp:
1211 update = True
1211 update = True
1212 else:
1212 else:
1213 update = False
1213 update = False
1214 self.strip(repo, rev, update=update, backup='strip')
1214 self.strip(repo, rev, update=update, backup='strip')
1215 if qpp:
1215 if qpp:
1216 self.ui.warn("saved queue repository parents: %s %s\n" %
1216 self.ui.warn("saved queue repository parents: %s %s\n" %
1217 (hg.short(qpp[0]), hg.short(qpp[1])))
1217 (hg.short(qpp[0]), hg.short(qpp[1])))
1218 if qupdate:
1218 if qupdate:
1219 print "queue directory updating"
1219 print "queue directory updating"
1220 r = self.qrepo()
1220 r = self.qrepo()
1221 if not r:
1221 if not r:
1222 self.ui.warn("Unable to load queue repository\n")
1222 self.ui.warn("Unable to load queue repository\n")
1223 return 1
1223 return 1
1224 hg.clean(r, qpp[0])
1224 hg.clean(r, qpp[0])
1225
1225
1226 def save(self, repo, msg=None):
1226 def save(self, repo, msg=None):
1227 if len(self.applied) == 0:
1227 if len(self.applied) == 0:
1228 self.ui.warn("save: no patches applied, exiting\n")
1228 self.ui.warn("save: no patches applied, exiting\n")
1229 return 1
1229 return 1
1230 if self.issaveline(self.applied[-1]):
1230 if self.issaveline(self.applied[-1]):
1231 self.ui.warn("status is already saved\n")
1231 self.ui.warn("status is already saved\n")
1232 return 1
1232 return 1
1233
1233
1234 ar = [ ':' + x for x in self.full_series ]
1234 ar = [ ':' + x for x in self.full_series ]
1235 if not msg:
1235 if not msg:
1236 msg = "hg patches saved state"
1236 msg = "hg patches saved state"
1237 else:
1237 else:
1238 msg = "hg patches: " + msg.rstrip('\r\n')
1238 msg = "hg patches: " + msg.rstrip('\r\n')
1239 r = self.qrepo()
1239 r = self.qrepo()
1240 if r:
1240 if r:
1241 pp = r.dirstate.parents()
1241 pp = r.dirstate.parents()
1242 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1242 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1243 msg += "\n\nPatch Data:\n"
1243 msg += "\n\nPatch Data:\n"
1244 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1244 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1245 "\n".join(ar) + '\n' or "")
1245 "\n".join(ar) + '\n' or "")
1246 n = repo.commit(None, text, user=None, force=1)
1246 n = repo.commit(None, text, user=None, force=1)
1247 if not n:
1247 if not n:
1248 self.ui.warn("repo commit failed\n")
1248 self.ui.warn("repo commit failed\n")
1249 return 1
1249 return 1
1250 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1250 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1251 self.applied_dirty = 1
1251 self.applied_dirty = 1
1252 self.removeundo(repo)
1252 self.removeundo(repo)
1253
1253
1254 def full_series_end(self):
1254 def full_series_end(self):
1255 if len(self.applied) > 0:
1255 if len(self.applied) > 0:
1256 p = self.applied[-1].name
1256 p = self.applied[-1].name
1257 end = self.find_series(p)
1257 end = self.find_series(p)
1258 if end == None:
1258 if end == None:
1259 return len(self.full_series)
1259 return len(self.full_series)
1260 return end + 1
1260 return end + 1
1261 return 0
1261 return 0
1262
1262
1263 def series_end(self, all_patches=False):
1263 def series_end(self, all_patches=False):
1264 """If all_patches is False, return the index of the next pushable patch
1264 """If all_patches is False, return the index of the next pushable patch
1265 in the series, or the series length. If all_patches is True, return the
1265 in the series, or the series length. If all_patches is True, return the
1266 index of the first patch past the last applied one.
1266 index of the first patch past the last applied one.
1267 """
1267 """
1268 end = 0
1268 end = 0
1269 def next(start):
1269 def next(start):
1270 if all_patches:
1270 if all_patches:
1271 return start
1271 return start
1272 i = start
1272 i = start
1273 while i < len(self.series):
1273 while i < len(self.series):
1274 p, reason = self.pushable(i)
1274 p, reason = self.pushable(i)
1275 if p:
1275 if p:
1276 break
1276 break
1277 self.explain_pushable(i)
1277 self.explain_pushable(i)
1278 i += 1
1278 i += 1
1279 return i
1279 return i
1280 if len(self.applied) > 0:
1280 if len(self.applied) > 0:
1281 p = self.applied[-1].name
1281 p = self.applied[-1].name
1282 try:
1282 try:
1283 end = self.series.index(p)
1283 end = self.series.index(p)
1284 except ValueError:
1284 except ValueError:
1285 return 0
1285 return 0
1286 return next(end + 1)
1286 return next(end + 1)
1287 return next(end)
1287 return next(end)
1288
1288
1289 def appliedname(self, index):
1289 def appliedname(self, index):
1290 pname = self.applied[index].name
1290 pname = self.applied[index].name
1291 if not self.ui.verbose:
1291 if not self.ui.verbose:
1292 p = pname
1292 p = pname
1293 else:
1293 else:
1294 p = str(self.series.index(pname)) + " " + pname
1294 p = str(self.series.index(pname)) + " " + pname
1295 return p
1295 return p
1296
1296
1297 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1297 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1298 force=None, git=False):
1298 force=None, git=False):
1299 def checkseries(patchname):
1299 def checkseries(patchname):
1300 if patchname in self.series:
1300 if patchname in self.series:
1301 raise util.Abort(_('patch %s is already in the series file')
1301 raise util.Abort(_('patch %s is already in the series file')
1302 % patchname)
1302 % patchname)
1303 def checkfile(patchname):
1303 def checkfile(patchname):
1304 if not force and os.path.exists(self.join(patchname)):
1304 if not force and os.path.exists(self.join(patchname)):
1305 raise util.Abort(_('patch "%s" already exists')
1305 raise util.Abort(_('patch "%s" already exists')
1306 % patchname)
1306 % patchname)
1307
1307
1308 if rev:
1308 if rev:
1309 if files:
1309 if files:
1310 raise util.Abort(_('option "-r" not valid when importing '
1310 raise util.Abort(_('option "-r" not valid when importing '
1311 'files'))
1311 'files'))
1312 rev = cmdutil.revrange(repo, rev)
1312 rev = cmdutil.revrange(repo, rev)
1313 rev.sort(lambda x, y: cmp(y, x))
1313 rev.sort(lambda x, y: cmp(y, x))
1314 if (len(files) > 1 or len(rev) > 1) and patchname:
1314 if (len(files) > 1 or len(rev) > 1) and patchname:
1315 raise util.Abort(_('option "-n" not valid when importing multiple '
1315 raise util.Abort(_('option "-n" not valid when importing multiple '
1316 'patches'))
1316 'patches'))
1317 i = 0
1317 i = 0
1318 added = []
1318 added = []
1319 if rev:
1319 if rev:
1320 # If mq patches are applied, we can only import revisions
1320 # If mq patches are applied, we can only import revisions
1321 # that form a linear path to qbase.
1321 # that form a linear path to qbase.
1322 # Otherwise, they should form a linear path to a head.
1322 # Otherwise, they should form a linear path to a head.
1323 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1323 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1324 if len(heads) > 1:
1324 if len(heads) > 1:
1325 raise util.Abort(_('revision %d is the root of more than one '
1325 raise util.Abort(_('revision %d is the root of more than one '
1326 'branch') % rev[-1])
1326 'branch') % rev[-1])
1327 if self.applied:
1327 if self.applied:
1328 base = revlog.hex(repo.changelog.node(rev[0]))
1328 base = revlog.hex(repo.changelog.node(rev[0]))
1329 if base in [n.rev for n in self.applied]:
1329 if base in [n.rev for n in self.applied]:
1330 raise util.Abort(_('revision %d is already managed')
1330 raise util.Abort(_('revision %d is already managed')
1331 % rev[0])
1331 % rev[0])
1332 if heads != [revlog.bin(self.applied[-1].rev)]:
1332 if heads != [revlog.bin(self.applied[-1].rev)]:
1333 raise util.Abort(_('revision %d is not the parent of '
1333 raise util.Abort(_('revision %d is not the parent of '
1334 'the queue') % rev[0])
1334 'the queue') % rev[0])
1335 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1335 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1336 lastparent = repo.changelog.parentrevs(base)[0]
1336 lastparent = repo.changelog.parentrevs(base)[0]
1337 else:
1337 else:
1338 if heads != [repo.changelog.node(rev[0])]:
1338 if heads != [repo.changelog.node(rev[0])]:
1339 raise util.Abort(_('revision %d has unmanaged children')
1339 raise util.Abort(_('revision %d has unmanaged children')
1340 % rev[0])
1340 % rev[0])
1341 lastparent = None
1341 lastparent = None
1342
1342
1343 if git:
1343 if git:
1344 self.diffopts().git = True
1344 self.diffopts().git = True
1345
1345
1346 for r in rev:
1346 for r in rev:
1347 p1, p2 = repo.changelog.parentrevs(r)
1347 p1, p2 = repo.changelog.parentrevs(r)
1348 n = repo.changelog.node(r)
1348 n = repo.changelog.node(r)
1349 if p2 != revlog.nullrev:
1349 if p2 != revlog.nullrev:
1350 raise util.Abort(_('cannot import merge revision %d') % r)
1350 raise util.Abort(_('cannot import merge revision %d') % r)
1351 if lastparent and lastparent != r:
1351 if lastparent and lastparent != r:
1352 raise util.Abort(_('revision %d is not the parent of %d')
1352 raise util.Abort(_('revision %d is not the parent of %d')
1353 % (r, lastparent))
1353 % (r, lastparent))
1354 lastparent = p1
1354 lastparent = p1
1355
1355
1356 if not patchname:
1356 if not patchname:
1357 patchname = normname('%d.diff' % r)
1357 patchname = normname('%d.diff' % r)
1358 checkseries(patchname)
1358 checkseries(patchname)
1359 checkfile(patchname)
1359 checkfile(patchname)
1360 self.full_series.insert(0, patchname)
1360 self.full_series.insert(0, patchname)
1361
1361
1362 patchf = self.opener(patchname, "w")
1362 patchf = self.opener(patchname, "w")
1363 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1363 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1364 patchf.close()
1364 patchf.close()
1365
1365
1366 se = statusentry(revlog.hex(n), patchname)
1366 se = statusentry(revlog.hex(n), patchname)
1367 self.applied.insert(0, se)
1367 self.applied.insert(0, se)
1368
1368
1369 added.append(patchname)
1369 added.append(patchname)
1370 patchname = None
1370 patchname = None
1371 self.parse_series()
1371 self.parse_series()
1372 self.applied_dirty = 1
1372 self.applied_dirty = 1
1373
1373
1374 for filename in files:
1374 for filename in files:
1375 if existing:
1375 if existing:
1376 if filename == '-':
1376 if filename == '-':
1377 raise util.Abort(_('-e is incompatible with import from -'))
1377 raise util.Abort(_('-e is incompatible with import from -'))
1378 if not patchname:
1378 if not patchname:
1379 patchname = normname(filename)
1379 patchname = normname(filename)
1380 if not os.path.isfile(self.join(patchname)):
1380 if not os.path.isfile(self.join(patchname)):
1381 raise util.Abort(_("patch %s does not exist") % patchname)
1381 raise util.Abort(_("patch %s does not exist") % patchname)
1382 else:
1382 else:
1383 try:
1383 try:
1384 if filename == '-':
1384 if filename == '-':
1385 if not patchname:
1385 if not patchname:
1386 raise util.Abort(_('need --name to import a patch from -'))
1386 raise util.Abort(_('need --name to import a patch from -'))
1387 text = sys.stdin.read()
1387 text = sys.stdin.read()
1388 else:
1388 else:
1389 text = file(filename).read()
1389 text = file(filename).read()
1390 except IOError:
1390 except IOError:
1391 raise util.Abort(_("unable to read %s") % patchname)
1391 raise util.Abort(_("unable to read %s") % patchname)
1392 if not patchname:
1392 if not patchname:
1393 patchname = normname(os.path.basename(filename))
1393 patchname = normname(os.path.basename(filename))
1394 checkfile(patchname)
1394 checkfile(patchname)
1395 patchf = self.opener(patchname, "w")
1395 patchf = self.opener(patchname, "w")
1396 patchf.write(text)
1396 patchf.write(text)
1397 checkseries(patchname)
1397 checkseries(patchname)
1398 index = self.full_series_end() + i
1398 index = self.full_series_end() + i
1399 self.full_series[index:index] = [patchname]
1399 self.full_series[index:index] = [patchname]
1400 self.parse_series()
1400 self.parse_series()
1401 self.ui.warn("adding %s to series file\n" % patchname)
1401 self.ui.warn("adding %s to series file\n" % patchname)
1402 i += 1
1402 i += 1
1403 added.append(patchname)
1403 added.append(patchname)
1404 patchname = None
1404 patchname = None
1405 self.series_dirty = 1
1405 self.series_dirty = 1
1406 qrepo = self.qrepo()
1406 qrepo = self.qrepo()
1407 if qrepo:
1407 if qrepo:
1408 qrepo.add(added)
1408 qrepo.add(added)
1409
1409
1410 def delete(ui, repo, *patches, **opts):
1410 def delete(ui, repo, *patches, **opts):
1411 """remove patches from queue
1411 """remove patches from queue
1412
1412
1413 The patches must not be applied, unless they are arguments to
1413 The patches must not be applied, unless they are arguments to
1414 the --rev parameter. At least one patch or revision is required.
1414 the --rev parameter. At least one patch or revision is required.
1415
1415
1416 With --rev, mq will stop managing the named revisions (converting
1416 With --rev, mq will stop managing the named revisions (converting
1417 them to regular mercurial changesets). The patches must be applied
1417 them to regular mercurial changesets). The patches must be applied
1418 and at the base of the stack. This option is useful when the patches
1418 and at the base of the stack. This option is useful when the patches
1419 have been applied upstream.
1419 have been applied upstream.
1420
1420
1421 With --keep, the patch files are preserved in the patch directory."""
1421 With --keep, the patch files are preserved in the patch directory."""
1422 q = repo.mq
1422 q = repo.mq
1423 q.delete(repo, patches, opts)
1423 q.delete(repo, patches, opts)
1424 q.save_dirty()
1424 q.save_dirty()
1425 return 0
1425 return 0
1426
1426
1427 def applied(ui, repo, patch=None, **opts):
1427 def applied(ui, repo, patch=None, **opts):
1428 """print the patches already applied"""
1428 """print the patches already applied"""
1429 q = repo.mq
1429 q = repo.mq
1430 if patch:
1430 if patch:
1431 if patch not in q.series:
1431 if patch not in q.series:
1432 raise util.Abort(_("patch %s is not in series file") % patch)
1432 raise util.Abort(_("patch %s is not in series file") % patch)
1433 end = q.series.index(patch) + 1
1433 end = q.series.index(patch) + 1
1434 else:
1434 else:
1435 end = q.series_end(True)
1435 end = q.series_end(True)
1436 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1436 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1437
1437
1438 def unapplied(ui, repo, patch=None, **opts):
1438 def unapplied(ui, repo, patch=None, **opts):
1439 """print the patches not yet applied"""
1439 """print the patches not yet applied"""
1440 q = repo.mq
1440 q = repo.mq
1441 if patch:
1441 if patch:
1442 if patch not in q.series:
1442 if patch not in q.series:
1443 raise util.Abort(_("patch %s is not in series file") % patch)
1443 raise util.Abort(_("patch %s is not in series file") % patch)
1444 start = q.series.index(patch) + 1
1444 start = q.series.index(patch) + 1
1445 else:
1445 else:
1446 start = q.series_end(True)
1446 start = q.series_end(True)
1447 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1447 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1448
1448
1449 def qimport(ui, repo, *filename, **opts):
1449 def qimport(ui, repo, *filename, **opts):
1450 """import a patch
1450 """import a patch
1451
1451
1452 The patch will have the same name as its source file unless you
1452 The patch will have the same name as its source file unless you
1453 give it a new one with --name.
1453 give it a new one with --name.
1454
1454
1455 You can register an existing patch inside the patch directory
1455 You can register an existing patch inside the patch directory
1456 with the --existing flag.
1456 with the --existing flag.
1457
1457
1458 With --force, an existing patch of the same name will be overwritten.
1458 With --force, an existing patch of the same name will be overwritten.
1459
1459
1460 An existing changeset may be placed under mq control with --rev
1460 An existing changeset may be placed under mq control with --rev
1461 (e.g. qimport --rev tip -n patch will place tip under mq control).
1461 (e.g. qimport --rev tip -n patch will place tip under mq control).
1462 With --git, patches imported with --rev will use the git diff
1462 With --git, patches imported with --rev will use the git diff
1463 format.
1463 format.
1464 """
1464 """
1465 q = repo.mq
1465 q = repo.mq
1466 q.qimport(repo, filename, patchname=opts['name'],
1466 q.qimport(repo, filename, patchname=opts['name'],
1467 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1467 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1468 git=opts['git'])
1468 git=opts['git'])
1469 q.save_dirty()
1469 q.save_dirty()
1470 return 0
1470 return 0
1471
1471
1472 def init(ui, repo, **opts):
1472 def init(ui, repo, **opts):
1473 """init a new queue repository
1473 """init a new queue repository
1474
1474
1475 The queue repository is unversioned by default. If -c is
1475 The queue repository is unversioned by default. If -c is
1476 specified, qinit will create a separate nested repository
1476 specified, qinit will create a separate nested repository
1477 for patches (qinit -c may also be run later to convert
1477 for patches (qinit -c may also be run later to convert
1478 an unversioned patch repository into a versioned one).
1478 an unversioned patch repository into a versioned one).
1479 You can use qcommit to commit changes to this queue repository."""
1479 You can use qcommit to commit changes to this queue repository."""
1480 q = repo.mq
1480 q = repo.mq
1481 r = q.init(repo, create=opts['create_repo'])
1481 r = q.init(repo, create=opts['create_repo'])
1482 q.save_dirty()
1482 q.save_dirty()
1483 if r:
1483 if r:
1484 if not os.path.exists(r.wjoin('.hgignore')):
1484 if not os.path.exists(r.wjoin('.hgignore')):
1485 fp = r.wopener('.hgignore', 'w')
1485 fp = r.wopener('.hgignore', 'w')
1486 fp.write('syntax: glob\n')
1486 fp.write('syntax: glob\n')
1487 fp.write('status\n')
1487 fp.write('status\n')
1488 fp.write('guards\n')
1488 fp.write('guards\n')
1489 fp.close()
1489 fp.close()
1490 if not os.path.exists(r.wjoin('series')):
1490 if not os.path.exists(r.wjoin('series')):
1491 r.wopener('series', 'w').close()
1491 r.wopener('series', 'w').close()
1492 r.add(['.hgignore', 'series'])
1492 r.add(['.hgignore', 'series'])
1493 commands.add(ui, r)
1493 commands.add(ui, r)
1494 return 0
1494 return 0
1495
1495
1496 def clone(ui, source, dest=None, **opts):
1496 def clone(ui, source, dest=None, **opts):
1497 '''clone main and patch repository at same time
1497 '''clone main and patch repository at same time
1498
1498
1499 If source is local, destination will have no patches applied. If
1499 If source is local, destination will have no patches applied. If
1500 source is remote, this command can not check if patches are
1500 source is remote, this command can not check if patches are
1501 applied in source, so cannot guarantee that patches are not
1501 applied in source, so cannot guarantee that patches are not
1502 applied in destination. If you clone remote repository, be sure
1502 applied in destination. If you clone remote repository, be sure
1503 before that it has no patches applied.
1503 before that it has no patches applied.
1504
1504
1505 Source patch repository is looked for in <src>/.hg/patches by
1505 Source patch repository is looked for in <src>/.hg/patches by
1506 default. Use -p <url> to change.
1506 default. Use -p <url> to change.
1507
1507
1508 The patch directory must be a nested mercurial repository, as
1508 The patch directory must be a nested mercurial repository, as
1509 would be created by qinit -c.
1509 would be created by qinit -c.
1510 '''
1510 '''
1511 cmdutil.setremoteconfig(ui, opts)
1511 cmdutil.setremoteconfig(ui, opts)
1512 if dest is None:
1512 if dest is None:
1513 dest = hg.defaultdest(source)
1513 dest = hg.defaultdest(source)
1514 sr = hg.repository(ui, ui.expandpath(source))
1514 sr = hg.repository(ui, ui.expandpath(source))
1515 patchdir = opts['patches'] or (sr.url() + '/.hg/patches')
1515 patchdir = opts['patches'] or (sr.url() + '/.hg/patches')
1516 try:
1516 try:
1517 pr = hg.repository(ui, patchdir)
1517 pr = hg.repository(ui, patchdir)
1518 except hg.RepoError:
1518 except hg.RepoError:
1519 raise util.Abort(_('versioned patch repository not found'
1519 raise util.Abort(_('versioned patch repository not found'
1520 ' (see qinit -c)'))
1520 ' (see qinit -c)'))
1521 qbase, destrev = None, None
1521 qbase, destrev = None, None
1522 if sr.local():
1522 if sr.local():
1523 if sr.mq.applied:
1523 if sr.mq.applied:
1524 qbase = revlog.bin(sr.mq.applied[0].rev)
1524 qbase = revlog.bin(sr.mq.applied[0].rev)
1525 if not hg.islocal(dest):
1525 if not hg.islocal(dest):
1526 heads = dict.fromkeys(sr.heads())
1526 heads = dict.fromkeys(sr.heads())
1527 for h in sr.heads(qbase):
1527 for h in sr.heads(qbase):
1528 del heads[h]
1528 del heads[h]
1529 destrev = heads.keys()
1529 destrev = heads.keys()
1530 destrev.append(sr.changelog.parents(qbase)[0])
1530 destrev.append(sr.changelog.parents(qbase)[0])
1531 ui.note(_('cloning main repo\n'))
1531 ui.note(_('cloning main repo\n'))
1532 sr, dr = hg.clone(ui, sr.url(), dest,
1532 sr, dr = hg.clone(ui, sr.url(), dest,
1533 pull=opts['pull'],
1533 pull=opts['pull'],
1534 rev=destrev,
1534 rev=destrev,
1535 update=False,
1535 update=False,
1536 stream=opts['uncompressed'])
1536 stream=opts['uncompressed'])
1537 ui.note(_('cloning patch repo\n'))
1537 ui.note(_('cloning patch repo\n'))
1538 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1538 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1539 dr.url() + '/.hg/patches',
1539 dr.url() + '/.hg/patches',
1540 pull=opts['pull'],
1540 pull=opts['pull'],
1541 update=not opts['noupdate'],
1541 update=not opts['noupdate'],
1542 stream=opts['uncompressed'])
1542 stream=opts['uncompressed'])
1543 if dr.local():
1543 if dr.local():
1544 if qbase:
1544 if qbase:
1545 ui.note(_('stripping applied patches from destination repo\n'))
1545 ui.note(_('stripping applied patches from destination repo\n'))
1546 dr.mq.strip(dr, qbase, update=False, backup=None)
1546 dr.mq.strip(dr, qbase, update=False, backup=None)
1547 if not opts['noupdate']:
1547 if not opts['noupdate']:
1548 ui.note(_('updating destination repo\n'))
1548 ui.note(_('updating destination repo\n'))
1549 hg.update(dr, dr.changelog.tip())
1549 hg.update(dr, dr.changelog.tip())
1550
1550
1551 def commit(ui, repo, *pats, **opts):
1551 def commit(ui, repo, *pats, **opts):
1552 """commit changes in the queue repository"""
1552 """commit changes in the queue repository"""
1553 q = repo.mq
1553 q = repo.mq
1554 r = q.qrepo()
1554 r = q.qrepo()
1555 if not r: raise util.Abort('no queue repository')
1555 if not r: raise util.Abort('no queue repository')
1556 commands.commit(r.ui, r, *pats, **opts)
1556 commands.commit(r.ui, r, *pats, **opts)
1557
1557
1558 def series(ui, repo, **opts):
1558 def series(ui, repo, **opts):
1559 """print the entire series file"""
1559 """print the entire series file"""
1560 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1560 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1561 return 0
1561 return 0
1562
1562
1563 def top(ui, repo, **opts):
1563 def top(ui, repo, **opts):
1564 """print the name of the current patch"""
1564 """print the name of the current patch"""
1565 q = repo.mq
1565 q = repo.mq
1566 t = q.applied and q.series_end(True) or 0
1566 t = q.applied and q.series_end(True) or 0
1567 if t:
1567 if t:
1568 return q.qseries(repo, start=t-1, length=1, status='A',
1568 return q.qseries(repo, start=t-1, length=1, status='A',
1569 summary=opts.get('summary'))
1569 summary=opts.get('summary'))
1570 else:
1570 else:
1571 ui.write("No patches applied\n")
1571 ui.write("No patches applied\n")
1572 return 1
1572 return 1
1573
1573
1574 def next(ui, repo, **opts):
1574 def next(ui, repo, **opts):
1575 """print the name of the next patch"""
1575 """print the name of the next patch"""
1576 q = repo.mq
1576 q = repo.mq
1577 end = q.series_end()
1577 end = q.series_end()
1578 if end == len(q.series):
1578 if end == len(q.series):
1579 ui.write("All patches applied\n")
1579 ui.write("All patches applied\n")
1580 return 1
1580 return 1
1581 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1581 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1582
1582
1583 def prev(ui, repo, **opts):
1583 def prev(ui, repo, **opts):
1584 """print the name of the previous patch"""
1584 """print the name of the previous patch"""
1585 q = repo.mq
1585 q = repo.mq
1586 l = len(q.applied)
1586 l = len(q.applied)
1587 if l == 1:
1587 if l == 1:
1588 ui.write("Only one patch applied\n")
1588 ui.write("Only one patch applied\n")
1589 return 1
1589 return 1
1590 if not l:
1590 if not l:
1591 ui.write("No patches applied\n")
1591 ui.write("No patches applied\n")
1592 return 1
1592 return 1
1593 return q.qseries(repo, start=l-2, length=1, status='A',
1593 return q.qseries(repo, start=l-2, length=1, status='A',
1594 summary=opts.get('summary'))
1594 summary=opts.get('summary'))
1595
1595
1596 def new(ui, repo, patch, *args, **opts):
1596 def new(ui, repo, patch, *args, **opts):
1597 """create a new patch
1597 """create a new patch
1598
1598
1599 qnew creates a new patch on top of the currently-applied patch
1599 qnew creates a new patch on top of the currently-applied patch
1600 (if any). It will refuse to run if there are any outstanding
1600 (if any). It will refuse to run if there are any outstanding
1601 changes unless -f is specified, in which case the patch will
1601 changes unless -f is specified, in which case the patch will
1602 be initialised with them. You may also use -I, -X, and/or a list of
1602 be initialised with them. You may also use -I, -X, and/or a list of
1603 files after the patch name to add only changes to matching files
1603 files after the patch name to add only changes to matching files
1604 to the new patch, leaving the rest as uncommitted modifications.
1604 to the new patch, leaving the rest as uncommitted modifications.
1605
1605
1606 -e, -m or -l set the patch header as well as the commit message.
1606 -e, -m or -l set the patch header as well as the commit message.
1607 If none is specified, the patch header is empty and the
1607 If none is specified, the patch header is empty and the
1608 commit message is '[mq]: PATCH'"""
1608 commit message is '[mq]: PATCH'"""
1609 q = repo.mq
1609 q = repo.mq
1610 message = cmdutil.logmessage(opts)
1610 message = cmdutil.logmessage(opts)
1611 if opts['edit']:
1611 if opts['edit']:
1612 message = ui.edit(message, ui.username())
1612 message = ui.edit(message, ui.username())
1613 opts['msg'] = message
1613 opts['msg'] = message
1614 q.new(repo, patch, *args, **opts)
1614 q.new(repo, patch, *args, **opts)
1615 q.save_dirty()
1615 q.save_dirty()
1616 return 0
1616 return 0
1617
1617
1618 def refresh(ui, repo, *pats, **opts):
1618 def refresh(ui, repo, *pats, **opts):
1619 """update the current patch
1619 """update the current patch
1620
1620
1621 If any file patterns are provided, the refreshed patch will contain only
1621 If any file patterns are provided, the refreshed patch will contain only
1622 the modifications that match those patterns; the remaining modifications
1622 the modifications that match those patterns; the remaining modifications
1623 will remain in the working directory.
1623 will remain in the working directory.
1624
1624
1625 hg add/remove/copy/rename work as usual, though you might want to use
1625 hg add/remove/copy/rename work as usual, though you might want to use
1626 git-style patches (--git or [diff] git=1) to track copies and renames.
1626 git-style patches (--git or [diff] git=1) to track copies and renames.
1627 """
1627 """
1628 q = repo.mq
1628 q = repo.mq
1629 message = cmdutil.logmessage(opts)
1629 message = cmdutil.logmessage(opts)
1630 if opts['edit']:
1630 if opts['edit']:
1631 if message:
1631 if message:
1632 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1632 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1633 patch = q.applied[-1].name
1633 patch = q.applied[-1].name
1634 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1634 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1635 message = ui.edit('\n'.join(message), user or ui.username())
1635 message = ui.edit('\n'.join(message), user or ui.username())
1636 ret = q.refresh(repo, pats, msg=message, **opts)
1636 ret = q.refresh(repo, pats, msg=message, **opts)
1637 q.save_dirty()
1637 q.save_dirty()
1638 return ret
1638 return ret
1639
1639
1640 def diff(ui, repo, *pats, **opts):
1640 def diff(ui, repo, *pats, **opts):
1641 """diff of the current patch"""
1641 """diff of the current patch"""
1642 repo.mq.diff(repo, pats, opts)
1642 repo.mq.diff(repo, pats, opts)
1643 return 0
1643 return 0
1644
1644
1645 def fold(ui, repo, *files, **opts):
1645 def fold(ui, repo, *files, **opts):
1646 """fold the named patches into the current patch
1646 """fold the named patches into the current patch
1647
1647
1648 Patches must not yet be applied. Each patch will be successively
1648 Patches must not yet be applied. Each patch will be successively
1649 applied to the current patch in the order given. If all the
1649 applied to the current patch in the order given. If all the
1650 patches apply successfully, the current patch will be refreshed
1650 patches apply successfully, the current patch will be refreshed
1651 with the new cumulative patch, and the folded patches will
1651 with the new cumulative patch, and the folded patches will
1652 be deleted. With -k/--keep, the folded patch files will not
1652 be deleted. With -k/--keep, the folded patch files will not
1653 be removed afterwards.
1653 be removed afterwards.
1654
1654
1655 The header for each folded patch will be concatenated with
1655 The header for each folded patch will be concatenated with
1656 the current patch header, separated by a line of '* * *'."""
1656 the current patch header, separated by a line of '* * *'."""
1657
1657
1658 q = repo.mq
1658 q = repo.mq
1659
1659
1660 if not files:
1660 if not files:
1661 raise util.Abort(_('qfold requires at least one patch name'))
1661 raise util.Abort(_('qfold requires at least one patch name'))
1662 if not q.check_toppatch(repo):
1662 if not q.check_toppatch(repo):
1663 raise util.Abort(_('No patches applied'))
1663 raise util.Abort(_('No patches applied'))
1664
1664
1665 message = cmdutil.logmessage(opts)
1665 message = cmdutil.logmessage(opts)
1666 if opts['edit']:
1666 if opts['edit']:
1667 if message:
1667 if message:
1668 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1668 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1669
1669
1670 parent = q.lookup('qtip')
1670 parent = q.lookup('qtip')
1671 patches = []
1671 patches = []
1672 messages = []
1672 messages = []
1673 for f in files:
1673 for f in files:
1674 p = q.lookup(f)
1674 p = q.lookup(f)
1675 if p in patches or p == parent:
1675 if p in patches or p == parent:
1676 ui.warn(_('Skipping already folded patch %s') % p)
1676 ui.warn(_('Skipping already folded patch %s') % p)
1677 if q.isapplied(p):
1677 if q.isapplied(p):
1678 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1678 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1679 patches.append(p)
1679 patches.append(p)
1680
1680
1681 for p in patches:
1681 for p in patches:
1682 if not message:
1682 if not message:
1683 messages.append(q.readheaders(p)[0])
1683 messages.append(q.readheaders(p)[0])
1684 pf = q.join(p)
1684 pf = q.join(p)
1685 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1685 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1686 if not patchsuccess:
1686 if not patchsuccess:
1687 raise util.Abort(_('Error folding patch %s') % p)
1687 raise util.Abort(_('Error folding patch %s') % p)
1688 patch.updatedir(ui, repo, files)
1688 patch.updatedir(ui, repo, files)
1689
1689
1690 if not message:
1690 if not message:
1691 message, comments, user = q.readheaders(parent)[0:3]
1691 message, comments, user = q.readheaders(parent)[0:3]
1692 for msg in messages:
1692 for msg in messages:
1693 message.append('* * *')
1693 message.append('* * *')
1694 message.extend(msg)
1694 message.extend(msg)
1695 message = '\n'.join(message)
1695 message = '\n'.join(message)
1696
1696
1697 if opts['edit']:
1697 if opts['edit']:
1698 message = ui.edit(message, user or ui.username())
1698 message = ui.edit(message, user or ui.username())
1699
1699
1700 q.refresh(repo, msg=message)
1700 q.refresh(repo, msg=message)
1701 q.delete(repo, patches, opts)
1701 q.delete(repo, patches, opts)
1702 q.save_dirty()
1702 q.save_dirty()
1703
1703
1704 def goto(ui, repo, patch, **opts):
1704 def goto(ui, repo, patch, **opts):
1705 '''push or pop patches until named patch is at top of stack'''
1705 '''push or pop patches until named patch is at top of stack'''
1706 q = repo.mq
1706 q = repo.mq
1707 patch = q.lookup(patch)
1707 patch = q.lookup(patch)
1708 if q.isapplied(patch):
1708 if q.isapplied(patch):
1709 ret = q.pop(repo, patch, force=opts['force'])
1709 ret = q.pop(repo, patch, force=opts['force'])
1710 else:
1710 else:
1711 ret = q.push(repo, patch, force=opts['force'])
1711 ret = q.push(repo, patch, force=opts['force'])
1712 q.save_dirty()
1712 q.save_dirty()
1713 return ret
1713 return ret
1714
1714
1715 def guard(ui, repo, *args, **opts):
1715 def guard(ui, repo, *args, **opts):
1716 '''set or print guards for a patch
1716 '''set or print guards for a patch
1717
1717
1718 Guards control whether a patch can be pushed. A patch with no
1718 Guards control whether a patch can be pushed. A patch with no
1719 guards is always pushed. A patch with a positive guard ("+foo") is
1719 guards is always pushed. A patch with a positive guard ("+foo") is
1720 pushed only if the qselect command has activated it. A patch with
1720 pushed only if the qselect command has activated it. A patch with
1721 a negative guard ("-foo") is never pushed if the qselect command
1721 a negative guard ("-foo") is never pushed if the qselect command
1722 has activated it.
1722 has activated it.
1723
1723
1724 With no arguments, print the currently active guards.
1724 With no arguments, print the currently active guards.
1725 With arguments, set guards for the named patch.
1725 With arguments, set guards for the named patch.
1726
1726
1727 To set a negative guard "-foo" on topmost patch ("--" is needed so
1727 To set a negative guard "-foo" on topmost patch ("--" is needed so
1728 hg will not interpret "-foo" as an option):
1728 hg will not interpret "-foo" as an option):
1729 hg qguard -- -foo
1729 hg qguard -- -foo
1730
1730
1731 To set guards on another patch:
1731 To set guards on another patch:
1732 hg qguard other.patch +2.6.17 -stable
1732 hg qguard other.patch +2.6.17 -stable
1733 '''
1733 '''
1734 def status(idx):
1734 def status(idx):
1735 guards = q.series_guards[idx] or ['unguarded']
1735 guards = q.series_guards[idx] or ['unguarded']
1736 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1736 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1737 q = repo.mq
1737 q = repo.mq
1738 patch = None
1738 patch = None
1739 args = list(args)
1739 args = list(args)
1740 if opts['list']:
1740 if opts['list']:
1741 if args or opts['none']:
1741 if args or opts['none']:
1742 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1742 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1743 for i in xrange(len(q.series)):
1743 for i in xrange(len(q.series)):
1744 status(i)
1744 status(i)
1745 return
1745 return
1746 if not args or args[0][0:1] in '-+':
1746 if not args or args[0][0:1] in '-+':
1747 if not q.applied:
1747 if not q.applied:
1748 raise util.Abort(_('no patches applied'))
1748 raise util.Abort(_('no patches applied'))
1749 patch = q.applied[-1].name
1749 patch = q.applied[-1].name
1750 if patch is None and args[0][0:1] not in '-+':
1750 if patch is None and args[0][0:1] not in '-+':
1751 patch = args.pop(0)
1751 patch = args.pop(0)
1752 if patch is None:
1752 if patch is None:
1753 raise util.Abort(_('no patch to work with'))
1753 raise util.Abort(_('no patch to work with'))
1754 if args or opts['none']:
1754 if args or opts['none']:
1755 idx = q.find_series(patch)
1755 idx = q.find_series(patch)
1756 if idx is None:
1756 if idx is None:
1757 raise util.Abort(_('no patch named %s') % patch)
1757 raise util.Abort(_('no patch named %s') % patch)
1758 q.set_guards(idx, args)
1758 q.set_guards(idx, args)
1759 q.save_dirty()
1759 q.save_dirty()
1760 else:
1760 else:
1761 status(q.series.index(q.lookup(patch)))
1761 status(q.series.index(q.lookup(patch)))
1762
1762
1763 def header(ui, repo, patch=None):
1763 def header(ui, repo, patch=None):
1764 """Print the header of the topmost or specified patch"""
1764 """Print the header of the topmost or specified patch"""
1765 q = repo.mq
1765 q = repo.mq
1766
1766
1767 if patch:
1767 if patch:
1768 patch = q.lookup(patch)
1768 patch = q.lookup(patch)
1769 else:
1769 else:
1770 if not q.applied:
1770 if not q.applied:
1771 ui.write('No patches applied\n')
1771 ui.write('No patches applied\n')
1772 return 1
1772 return 1
1773 patch = q.lookup('qtip')
1773 patch = q.lookup('qtip')
1774 message = repo.mq.readheaders(patch)[0]
1774 message = repo.mq.readheaders(patch)[0]
1775
1775
1776 ui.write('\n'.join(message) + '\n')
1776 ui.write('\n'.join(message) + '\n')
1777
1777
1778 def lastsavename(path):
1778 def lastsavename(path):
1779 (directory, base) = os.path.split(path)
1779 (directory, base) = os.path.split(path)
1780 names = os.listdir(directory)
1780 names = os.listdir(directory)
1781 namere = re.compile("%s.([0-9]+)" % base)
1781 namere = re.compile("%s.([0-9]+)" % base)
1782 maxindex = None
1782 maxindex = None
1783 maxname = None
1783 maxname = None
1784 for f in names:
1784 for f in names:
1785 m = namere.match(f)
1785 m = namere.match(f)
1786 if m:
1786 if m:
1787 index = int(m.group(1))
1787 index = int(m.group(1))
1788 if maxindex == None or index > maxindex:
1788 if maxindex == None or index > maxindex:
1789 maxindex = index
1789 maxindex = index
1790 maxname = f
1790 maxname = f
1791 if maxname:
1791 if maxname:
1792 return (os.path.join(directory, maxname), maxindex)
1792 return (os.path.join(directory, maxname), maxindex)
1793 return (None, None)
1793 return (None, None)
1794
1794
1795 def savename(path):
1795 def savename(path):
1796 (last, index) = lastsavename(path)
1796 (last, index) = lastsavename(path)
1797 if last is None:
1797 if last is None:
1798 index = 0
1798 index = 0
1799 newpath = path + ".%d" % (index + 1)
1799 newpath = path + ".%d" % (index + 1)
1800 return newpath
1800 return newpath
1801
1801
1802 def push(ui, repo, patch=None, **opts):
1802 def push(ui, repo, patch=None, **opts):
1803 """push the next patch onto the stack"""
1803 """push the next patch onto the stack"""
1804 q = repo.mq
1804 q = repo.mq
1805 mergeq = None
1805 mergeq = None
1806
1806
1807 if opts['all']:
1807 if opts['all']:
1808 if not q.series:
1808 if not q.series:
1809 ui.warn(_('no patches in series\n'))
1809 ui.warn(_('no patches in series\n'))
1810 return 0
1810 return 0
1811 patch = q.series[-1]
1811 patch = q.series[-1]
1812 if opts['merge']:
1812 if opts['merge']:
1813 if opts['name']:
1813 if opts['name']:
1814 newpath = opts['name']
1814 newpath = opts['name']
1815 else:
1815 else:
1816 newpath, i = lastsavename(q.path)
1816 newpath, i = lastsavename(q.path)
1817 if not newpath:
1817 if not newpath:
1818 ui.warn("no saved queues found, please use -n\n")
1818 ui.warn("no saved queues found, please use -n\n")
1819 return 1
1819 return 1
1820 mergeq = queue(ui, repo.join(""), newpath)
1820 mergeq = queue(ui, repo.join(""), newpath)
1821 ui.warn("merging with queue at: %s\n" % mergeq.path)
1821 ui.warn("merging with queue at: %s\n" % mergeq.path)
1822 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1822 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1823 mergeq=mergeq)
1823 mergeq=mergeq)
1824 return ret
1824 return ret
1825
1825
1826 def pop(ui, repo, patch=None, **opts):
1826 def pop(ui, repo, patch=None, **opts):
1827 """pop the current patch off the stack"""
1827 """pop the current patch off the stack"""
1828 localupdate = True
1828 localupdate = True
1829 if opts['name']:
1829 if opts['name']:
1830 q = queue(ui, repo.join(""), repo.join(opts['name']))
1830 q = queue(ui, repo.join(""), repo.join(opts['name']))
1831 ui.warn('using patch queue: %s\n' % q.path)
1831 ui.warn('using patch queue: %s\n' % q.path)
1832 localupdate = False
1832 localupdate = False
1833 else:
1833 else:
1834 q = repo.mq
1834 q = repo.mq
1835 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1835 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1836 all=opts['all'])
1836 all=opts['all'])
1837 q.save_dirty()
1837 q.save_dirty()
1838 return ret
1838 return ret
1839
1839
1840 def rename(ui, repo, patch, name=None, **opts):
1840 def rename(ui, repo, patch, name=None, **opts):
1841 """rename a patch
1841 """rename a patch
1842
1842
1843 With one argument, renames the current patch to PATCH1.
1843 With one argument, renames the current patch to PATCH1.
1844 With two arguments, renames PATCH1 to PATCH2."""
1844 With two arguments, renames PATCH1 to PATCH2."""
1845
1845
1846 q = repo.mq
1846 q = repo.mq
1847
1847
1848 if not name:
1848 if not name:
1849 name = patch
1849 name = patch
1850 patch = None
1850 patch = None
1851
1851
1852 if patch:
1852 if patch:
1853 patch = q.lookup(patch)
1853 patch = q.lookup(patch)
1854 else:
1854 else:
1855 if not q.applied:
1855 if not q.applied:
1856 ui.write(_('No patches applied\n'))
1856 ui.write(_('No patches applied\n'))
1857 return
1857 return
1858 patch = q.lookup('qtip')
1858 patch = q.lookup('qtip')
1859 absdest = q.join(name)
1859 absdest = q.join(name)
1860 if os.path.isdir(absdest):
1860 if os.path.isdir(absdest):
1861 name = normname(os.path.join(name, os.path.basename(patch)))
1861 name = normname(os.path.join(name, os.path.basename(patch)))
1862 absdest = q.join(name)
1862 absdest = q.join(name)
1863 if os.path.exists(absdest):
1863 if os.path.exists(absdest):
1864 raise util.Abort(_('%s already exists') % absdest)
1864 raise util.Abort(_('%s already exists') % absdest)
1865
1865
1866 if name in q.series:
1866 if name in q.series:
1867 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1867 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1868
1868
1869 if ui.verbose:
1869 if ui.verbose:
1870 ui.write('Renaming %s to %s\n' % (patch, name))
1870 ui.write('Renaming %s to %s\n' % (patch, name))
1871 i = q.find_series(patch)
1871 i = q.find_series(patch)
1872 guards = q.guard_re.findall(q.full_series[i])
1872 guards = q.guard_re.findall(q.full_series[i])
1873 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1873 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1874 q.parse_series()
1874 q.parse_series()
1875 q.series_dirty = 1
1875 q.series_dirty = 1
1876
1876
1877 info = q.isapplied(patch)
1877 info = q.isapplied(patch)
1878 if info:
1878 if info:
1879 q.applied[info[0]] = statusentry(info[1], name)
1879 q.applied[info[0]] = statusentry(info[1], name)
1880 q.applied_dirty = 1
1880 q.applied_dirty = 1
1881
1881
1882 util.rename(q.join(patch), absdest)
1882 util.rename(q.join(patch), absdest)
1883 r = q.qrepo()
1883 r = q.qrepo()
1884 if r:
1884 if r:
1885 wlock = r.wlock()
1885 wlock = r.wlock()
1886 try:
1886 try:
1887 if r.dirstate[name] == 'r':
1887 if r.dirstate[name] == 'r':
1888 r.undelete([name])
1888 r.undelete([name])
1889 r.copy(patch, name)
1889 r.copy(patch, name)
1890 r.remove([patch], False)
1890 r.remove([patch], False)
1891 finally:
1891 finally:
1892 del wlock
1892 del wlock
1893
1893
1894 q.save_dirty()
1894 q.save_dirty()
1895
1895
1896 def restore(ui, repo, rev, **opts):
1896 def restore(ui, repo, rev, **opts):
1897 """restore the queue state saved by a rev"""
1897 """restore the queue state saved by a rev"""
1898 rev = repo.lookup(rev)
1898 rev = repo.lookup(rev)
1899 q = repo.mq
1899 q = repo.mq
1900 q.restore(repo, rev, delete=opts['delete'],
1900 q.restore(repo, rev, delete=opts['delete'],
1901 qupdate=opts['update'])
1901 qupdate=opts['update'])
1902 q.save_dirty()
1902 q.save_dirty()
1903 return 0
1903 return 0
1904
1904
1905 def save(ui, repo, **opts):
1905 def save(ui, repo, **opts):
1906 """save current queue state"""
1906 """save current queue state"""
1907 q = repo.mq
1907 q = repo.mq
1908 message = cmdutil.logmessage(opts)
1908 message = cmdutil.logmessage(opts)
1909 ret = q.save(repo, msg=message)
1909 ret = q.save(repo, msg=message)
1910 if ret:
1910 if ret:
1911 return ret
1911 return ret
1912 q.save_dirty()
1912 q.save_dirty()
1913 if opts['copy']:
1913 if opts['copy']:
1914 path = q.path
1914 path = q.path
1915 if opts['name']:
1915 if opts['name']:
1916 newpath = os.path.join(q.basepath, opts['name'])
1916 newpath = os.path.join(q.basepath, opts['name'])
1917 if os.path.exists(newpath):
1917 if os.path.exists(newpath):
1918 if not os.path.isdir(newpath):
1918 if not os.path.isdir(newpath):
1919 raise util.Abort(_('destination %s exists and is not '
1919 raise util.Abort(_('destination %s exists and is not '
1920 'a directory') % newpath)
1920 'a directory') % newpath)
1921 if not opts['force']:
1921 if not opts['force']:
1922 raise util.Abort(_('destination %s exists, '
1922 raise util.Abort(_('destination %s exists, '
1923 'use -f to force') % newpath)
1923 'use -f to force') % newpath)
1924 else:
1924 else:
1925 newpath = savename(path)
1925 newpath = savename(path)
1926 ui.warn("copy %s to %s\n" % (path, newpath))
1926 ui.warn("copy %s to %s\n" % (path, newpath))
1927 util.copyfiles(path, newpath)
1927 util.copyfiles(path, newpath)
1928 if opts['empty']:
1928 if opts['empty']:
1929 try:
1929 try:
1930 os.unlink(q.join(q.status_path))
1930 os.unlink(q.join(q.status_path))
1931 except:
1931 except:
1932 pass
1932 pass
1933 return 0
1933 return 0
1934
1934
1935 def strip(ui, repo, rev, **opts):
1935 def strip(ui, repo, rev, **opts):
1936 """strip a revision and all later revs on the same branch"""
1936 """strip a revision and all later revs on the same branch"""
1937 rev = repo.lookup(rev)
1937 rev = repo.lookup(rev)
1938 backup = 'all'
1938 backup = 'all'
1939 if opts['backup']:
1939 if opts['backup']:
1940 backup = 'strip'
1940 backup = 'strip'
1941 elif opts['nobackup']:
1941 elif opts['nobackup']:
1942 backup = 'none'
1942 backup = 'none'
1943 update = repo.dirstate.parents()[0] != revlog.nullid
1943 update = repo.dirstate.parents()[0] != revlog.nullid
1944 repo.mq.strip(repo, rev, backup=backup, update=update)
1944 repo.mq.strip(repo, rev, backup=backup, update=update)
1945 return 0
1945 return 0
1946
1946
1947 def select(ui, repo, *args, **opts):
1947 def select(ui, repo, *args, **opts):
1948 '''set or print guarded patches to push
1948 '''set or print guarded patches to push
1949
1949
1950 Use the qguard command to set or print guards on patch, then use
1950 Use the qguard command to set or print guards on patch, then use
1951 qselect to tell mq which guards to use. A patch will be pushed if it
1951 qselect to tell mq which guards to use. A patch will be pushed if it
1952 has no guards or any positive guards match the currently selected guard,
1952 has no guards or any positive guards match the currently selected guard,
1953 but will not be pushed if any negative guards match the current guard.
1953 but will not be pushed if any negative guards match the current guard.
1954 For example:
1954 For example:
1955
1955
1956 qguard foo.patch -stable (negative guard)
1956 qguard foo.patch -stable (negative guard)
1957 qguard bar.patch +stable (positive guard)
1957 qguard bar.patch +stable (positive guard)
1958 qselect stable
1958 qselect stable
1959
1959
1960 This activates the "stable" guard. mq will skip foo.patch (because
1960 This activates the "stable" guard. mq will skip foo.patch (because
1961 it has a negative match) but push bar.patch (because it
1961 it has a negative match) but push bar.patch (because it
1962 has a positive match).
1962 has a positive match).
1963
1963
1964 With no arguments, prints the currently active guards.
1964 With no arguments, prints the currently active guards.
1965 With one argument, sets the active guard.
1965 With one argument, sets the active guard.
1966
1966
1967 Use -n/--none to deactivate guards (no other arguments needed).
1967 Use -n/--none to deactivate guards (no other arguments needed).
1968 When no guards are active, patches with positive guards are skipped
1968 When no guards are active, patches with positive guards are skipped
1969 and patches with negative guards are pushed.
1969 and patches with negative guards are pushed.
1970
1970
1971 qselect can change the guards on applied patches. It does not pop
1971 qselect can change the guards on applied patches. It does not pop
1972 guarded patches by default. Use --pop to pop back to the last applied
1972 guarded patches by default. Use --pop to pop back to the last applied
1973 patch that is not guarded. Use --reapply (which implies --pop) to push
1973 patch that is not guarded. Use --reapply (which implies --pop) to push
1974 back to the current patch afterwards, but skip guarded patches.
1974 back to the current patch afterwards, but skip guarded patches.
1975
1975
1976 Use -s/--series to print a list of all guards in the series file (no
1976 Use -s/--series to print a list of all guards in the series file (no
1977 other arguments needed). Use -v for more information.'''
1977 other arguments needed). Use -v for more information.'''
1978
1978
1979 q = repo.mq
1979 q = repo.mq
1980 guards = q.active()
1980 guards = q.active()
1981 if args or opts['none']:
1981 if args or opts['none']:
1982 old_unapplied = q.unapplied(repo)
1982 old_unapplied = q.unapplied(repo)
1983 old_guarded = [i for i in xrange(len(q.applied)) if
1983 old_guarded = [i for i in xrange(len(q.applied)) if
1984 not q.pushable(i)[0]]
1984 not q.pushable(i)[0]]
1985 q.set_active(args)
1985 q.set_active(args)
1986 q.save_dirty()
1986 q.save_dirty()
1987 if not args:
1987 if not args:
1988 ui.status(_('guards deactivated\n'))
1988 ui.status(_('guards deactivated\n'))
1989 if not opts['pop'] and not opts['reapply']:
1989 if not opts['pop'] and not opts['reapply']:
1990 unapplied = q.unapplied(repo)
1990 unapplied = q.unapplied(repo)
1991 guarded = [i for i in xrange(len(q.applied))
1991 guarded = [i for i in xrange(len(q.applied))
1992 if not q.pushable(i)[0]]
1992 if not q.pushable(i)[0]]
1993 if len(unapplied) != len(old_unapplied):
1993 if len(unapplied) != len(old_unapplied):
1994 ui.status(_('number of unguarded, unapplied patches has '
1994 ui.status(_('number of unguarded, unapplied patches has '
1995 'changed from %d to %d\n') %
1995 'changed from %d to %d\n') %
1996 (len(old_unapplied), len(unapplied)))
1996 (len(old_unapplied), len(unapplied)))
1997 if len(guarded) != len(old_guarded):
1997 if len(guarded) != len(old_guarded):
1998 ui.status(_('number of guarded, applied patches has changed '
1998 ui.status(_('number of guarded, applied patches has changed '
1999 'from %d to %d\n') %
1999 'from %d to %d\n') %
2000 (len(old_guarded), len(guarded)))
2000 (len(old_guarded), len(guarded)))
2001 elif opts['series']:
2001 elif opts['series']:
2002 guards = {}
2002 guards = {}
2003 noguards = 0
2003 noguards = 0
2004 for gs in q.series_guards:
2004 for gs in q.series_guards:
2005 if not gs:
2005 if not gs:
2006 noguards += 1
2006 noguards += 1
2007 for g in gs:
2007 for g in gs:
2008 guards.setdefault(g, 0)
2008 guards.setdefault(g, 0)
2009 guards[g] += 1
2009 guards[g] += 1
2010 if ui.verbose:
2010 if ui.verbose:
2011 guards['NONE'] = noguards
2011 guards['NONE'] = noguards
2012 guards = guards.items()
2012 guards = guards.items()
2013 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2013 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2014 if guards:
2014 if guards:
2015 ui.note(_('guards in series file:\n'))
2015 ui.note(_('guards in series file:\n'))
2016 for guard, count in guards:
2016 for guard, count in guards:
2017 ui.note('%2d ' % count)
2017 ui.note('%2d ' % count)
2018 ui.write(guard, '\n')
2018 ui.write(guard, '\n')
2019 else:
2019 else:
2020 ui.note(_('no guards in series file\n'))
2020 ui.note(_('no guards in series file\n'))
2021 else:
2021 else:
2022 if guards:
2022 if guards:
2023 ui.note(_('active guards:\n'))
2023 ui.note(_('active guards:\n'))
2024 for g in guards:
2024 for g in guards:
2025 ui.write(g, '\n')
2025 ui.write(g, '\n')
2026 else:
2026 else:
2027 ui.write(_('no active guards\n'))
2027 ui.write(_('no active guards\n'))
2028 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2028 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2029 popped = False
2029 popped = False
2030 if opts['pop'] or opts['reapply']:
2030 if opts['pop'] or opts['reapply']:
2031 for i in xrange(len(q.applied)):
2031 for i in xrange(len(q.applied)):
2032 pushable, reason = q.pushable(i)
2032 pushable, reason = q.pushable(i)
2033 if not pushable:
2033 if not pushable:
2034 ui.status(_('popping guarded patches\n'))
2034 ui.status(_('popping guarded patches\n'))
2035 popped = True
2035 popped = True
2036 if i == 0:
2036 if i == 0:
2037 q.pop(repo, all=True)
2037 q.pop(repo, all=True)
2038 else:
2038 else:
2039 q.pop(repo, i-1)
2039 q.pop(repo, i-1)
2040 break
2040 break
2041 if popped:
2041 if popped:
2042 try:
2042 try:
2043 if reapply:
2043 if reapply:
2044 ui.status(_('reapplying unguarded patches\n'))
2044 ui.status(_('reapplying unguarded patches\n'))
2045 q.push(repo, reapply)
2045 q.push(repo, reapply)
2046 finally:
2046 finally:
2047 q.save_dirty()
2047 q.save_dirty()
2048
2048
2049 def reposetup(ui, repo):
2049 def reposetup(ui, repo):
2050 class mqrepo(repo.__class__):
2050 class mqrepo(repo.__class__):
2051 def abort_if_wdir_patched(self, errmsg, force=False):
2051 def abort_if_wdir_patched(self, errmsg, force=False):
2052 if self.mq.applied and not force:
2052 if self.mq.applied and not force:
2053 parent = revlog.hex(self.dirstate.parents()[0])
2053 parent = revlog.hex(self.dirstate.parents()[0])
2054 if parent in [s.rev for s in self.mq.applied]:
2054 if parent in [s.rev for s in self.mq.applied]:
2055 raise util.Abort(errmsg)
2055 raise util.Abort(errmsg)
2056
2056
2057 def commit(self, *args, **opts):
2057 def commit(self, *args, **opts):
2058 if len(args) >= 6:
2058 if len(args) >= 6:
2059 force = args[5]
2059 force = args[5]
2060 else:
2060 else:
2061 force = opts.get('force')
2061 force = opts.get('force')
2062 self.abort_if_wdir_patched(
2062 self.abort_if_wdir_patched(
2063 _('cannot commit over an applied mq patch'),
2063 _('cannot commit over an applied mq patch'),
2064 force)
2064 force)
2065
2065
2066 return super(mqrepo, self).commit(*args, **opts)
2066 return super(mqrepo, self).commit(*args, **opts)
2067
2067
2068 def push(self, remote, force=False, revs=None):
2068 def push(self, remote, force=False, revs=None):
2069 if self.mq.applied and not force and not revs:
2069 if self.mq.applied and not force and not revs:
2070 raise util.Abort(_('source has mq patches applied'))
2070 raise util.Abort(_('source has mq patches applied'))
2071 return super(mqrepo, self).push(remote, force, revs)
2071 return super(mqrepo, self).push(remote, force, revs)
2072
2072
2073 def tags(self):
2073 def tags(self):
2074 if self.tagscache:
2074 if self.tagscache:
2075 return self.tagscache
2075 return self.tagscache
2076
2076
2077 tagscache = super(mqrepo, self).tags()
2077 tagscache = super(mqrepo, self).tags()
2078
2078
2079 q = self.mq
2079 q = self.mq
2080 if not q.applied:
2080 if not q.applied:
2081 return tagscache
2081 return tagscache
2082
2082
2083 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2083 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2084 mqtags.append((mqtags[-1][0], 'qtip'))
2084 mqtags.append((mqtags[-1][0], 'qtip'))
2085 mqtags.append((mqtags[0][0], 'qbase'))
2085 mqtags.append((mqtags[0][0], 'qbase'))
2086 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2086 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2087 for patch in mqtags:
2087 for patch in mqtags:
2088 if patch[1] in tagscache:
2088 if patch[1] in tagscache:
2089 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2089 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2090 else:
2090 else:
2091 tagscache[patch[1]] = patch[0]
2091 tagscache[patch[1]] = patch[0]
2092
2092
2093 return tagscache
2093 return tagscache
2094
2094
2095 def _branchtags(self):
2095 def _branchtags(self):
2096 q = self.mq
2096 q = self.mq
2097 if not q.applied:
2097 if not q.applied:
2098 return super(mqrepo, self)._branchtags()
2098 return super(mqrepo, self)._branchtags()
2099
2099
2100 self.branchcache = {} # avoid recursion in changectx
2100 self.branchcache = {} # avoid recursion in changectx
2101 cl = self.changelog
2101 cl = self.changelog
2102 partial, last, lrev = self._readbranchcache()
2102 partial, last, lrev = self._readbranchcache()
2103
2103
2104 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2104 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2105 start = lrev + 1
2105 start = lrev + 1
2106 if start < qbase:
2106 if start < qbase:
2107 # update the cache (excluding the patches) and save it
2107 # update the cache (excluding the patches) and save it
2108 self._updatebranchcache(partial, lrev+1, qbase)
2108 self._updatebranchcache(partial, lrev+1, qbase)
2109 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2109 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2110 start = qbase
2110 start = qbase
2111 # if start = qbase, the cache is as updated as it should be.
2111 # if start = qbase, the cache is as updated as it should be.
2112 # if start > qbase, the cache includes (part of) the patches.
2112 # if start > qbase, the cache includes (part of) the patches.
2113 # we might as well use it, but we won't save it.
2113 # we might as well use it, but we won't save it.
2114
2114
2115 # update the cache up to the tip
2115 # update the cache up to the tip
2116 self._updatebranchcache(partial, start, cl.count())
2116 self._updatebranchcache(partial, start, cl.count())
2117
2117
2118 return partial
2118 return partial
2119
2119
2120 if repo.local():
2120 if repo.local():
2121 repo.__class__ = mqrepo
2121 repo.__class__ = mqrepo
2122 repo.mq = queue(ui, repo.join(""))
2122 repo.mq = queue(ui, repo.join(""))
2123
2123
2124 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2124 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2125
2125
2126 cmdtable = {
2126 cmdtable = {
2127 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2127 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2128 "qclone":
2128 "qclone":
2129 (clone,
2129 (clone,
2130 [('', 'pull', None, _('use pull protocol to copy metadata')),
2130 [('', 'pull', None, _('use pull protocol to copy metadata')),
2131 ('U', 'noupdate', None, _('do not update the new working directories')),
2131 ('U', 'noupdate', None, _('do not update the new working directories')),
2132 ('', 'uncompressed', None,
2132 ('', 'uncompressed', None,
2133 _('use uncompressed transfer (fast over LAN)')),
2133 _('use uncompressed transfer (fast over LAN)')),
2134 ('e', 'ssh', '', _('specify ssh command to use')),
2134 ('e', 'ssh', '', _('specify ssh command to use')),
2135 ('p', 'patches', '', _('location of source patch repo')),
2135 ('p', 'patches', '', _('location of source patch repo')),
2136 ('', 'remotecmd', '',
2136 ('', 'remotecmd', '',
2137 _('specify hg command to run on the remote side'))],
2137 _('specify hg command to run on the remote side'))],
2138 _('hg qclone [OPTION]... SOURCE [DEST]')),
2138 _('hg qclone [OPTION]... SOURCE [DEST]')),
2139 "qcommit|qci":
2139 "qcommit|qci":
2140 (commit,
2140 (commit,
2141 commands.table["^commit|ci"][1],
2141 commands.table["^commit|ci"][1],
2142 _('hg qcommit [OPTION]... [FILE]...')),
2142 _('hg qcommit [OPTION]... [FILE]...')),
2143 "^qdiff":
2143 "^qdiff":
2144 (diff,
2144 (diff,
2145 [('g', 'git', None, _('use git extended diff format')),
2145 [('g', 'git', None, _('use git extended diff format')),
2146 ('I', 'include', [], _('include names matching the given patterns')),
2146 ('I', 'include', [], _('include names matching the given patterns')),
2147 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2147 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2148 _('hg qdiff [-I] [-X] [-g] [FILE]...')),
2148 _('hg qdiff [-I] [-X] [-g] [FILE]...')),
2149 "qdelete|qremove|qrm":
2149 "qdelete|qremove|qrm":
2150 (delete,
2150 (delete,
2151 [('k', 'keep', None, _('keep patch file')),
2151 [('k', 'keep', None, _('keep patch file')),
2152 ('r', 'rev', [], _('stop managing a revision'))],
2152 ('r', 'rev', [], _('stop managing a revision'))],
2153 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2153 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2154 'qfold':
2154 'qfold':
2155 (fold,
2155 (fold,
2156 [('e', 'edit', None, _('edit patch header')),
2156 [('e', 'edit', None, _('edit patch header')),
2157 ('k', 'keep', None, _('keep folded patch files')),
2157 ('k', 'keep', None, _('keep folded patch files')),
2158 ] + commands.commitopts,
2158 ] + commands.commitopts,
2159 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2159 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2160 'qgoto':
2160 'qgoto':
2161 (goto,
2161 (goto,
2162 [('f', 'force', None, _('overwrite any local changes'))],
2162 [('f', 'force', None, _('overwrite any local changes'))],
2163 _('hg qgoto [OPTION]... PATCH')),
2163 _('hg qgoto [OPTION]... PATCH')),
2164 'qguard':
2164 'qguard':
2165 (guard,
2165 (guard,
2166 [('l', 'list', None, _('list all patches and guards')),
2166 [('l', 'list', None, _('list all patches and guards')),
2167 ('n', 'none', None, _('drop all guards'))],
2167 ('n', 'none', None, _('drop all guards'))],
2168 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2168 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2169 'qheader': (header, [], _('hg qheader [PATCH]')),
2169 'qheader': (header, [], _('hg qheader [PATCH]')),
2170 "^qimport":
2170 "^qimport":
2171 (qimport,
2171 (qimport,
2172 [('e', 'existing', None, 'import file in patch dir'),
2172 [('e', 'existing', None, 'import file in patch dir'),
2173 ('n', 'name', '', 'patch file name'),
2173 ('n', 'name', '', 'patch file name'),
2174 ('f', 'force', None, 'overwrite existing files'),
2174 ('f', 'force', None, 'overwrite existing files'),
2175 ('r', 'rev', [], 'place existing revisions under mq control'),
2175 ('r', 'rev', [], 'place existing revisions under mq control'),
2176 ('g', 'git', None, _('use git extended diff format'))],
2176 ('g', 'git', None, _('use git extended diff format'))],
2177 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2177 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2178 "^qinit":
2178 "^qinit":
2179 (init,
2179 (init,
2180 [('c', 'create-repo', None, 'create queue repository')],
2180 [('c', 'create-repo', None, 'create queue repository')],
2181 _('hg qinit [-c]')),
2181 _('hg qinit [-c]')),
2182 "qnew":
2182 "qnew":
2183 (new,
2183 (new,
2184 [('e', 'edit', None, _('edit commit message')),
2184 [('e', 'edit', None, _('edit commit message')),
2185 ('f', 'force', None, _('import uncommitted changes into patch')),
2185 ('f', 'force', None, _('import uncommitted changes into patch')),
2186 ('g', 'git', None, _('use git extended diff format')),
2186 ('I', 'include', [], _('include names matching the given patterns')),
2187 ('I', 'include', [], _('include names matching the given patterns')),
2187 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2188 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2188 ] + commands.commitopts,
2189 ] + commands.commitopts,
2189 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2190 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2190 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2191 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2191 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2192 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2192 "^qpop":
2193 "^qpop":
2193 (pop,
2194 (pop,
2194 [('a', 'all', None, _('pop all patches')),
2195 [('a', 'all', None, _('pop all patches')),
2195 ('n', 'name', '', _('queue name to pop')),
2196 ('n', 'name', '', _('queue name to pop')),
2196 ('f', 'force', None, _('forget any local changes'))],
2197 ('f', 'force', None, _('forget any local changes'))],
2197 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2198 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2198 "^qpush":
2199 "^qpush":
2199 (push,
2200 (push,
2200 [('f', 'force', None, _('apply if the patch has rejects')),
2201 [('f', 'force', None, _('apply if the patch has rejects')),
2201 ('l', 'list', None, _('list patch name in commit text')),
2202 ('l', 'list', None, _('list patch name in commit text')),
2202 ('a', 'all', None, _('apply all patches')),
2203 ('a', 'all', None, _('apply all patches')),
2203 ('m', 'merge', None, _('merge from another queue')),
2204 ('m', 'merge', None, _('merge from another queue')),
2204 ('n', 'name', '', _('merge queue name'))],
2205 ('n', 'name', '', _('merge queue name'))],
2205 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2206 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2206 "^qrefresh":
2207 "^qrefresh":
2207 (refresh,
2208 (refresh,
2208 [('e', 'edit', None, _('edit commit message')),
2209 [('e', 'edit', None, _('edit commit message')),
2209 ('g', 'git', None, _('use git extended diff format')),
2210 ('g', 'git', None, _('use git extended diff format')),
2210 ('s', 'short', None, _('refresh only files already in the patch')),
2211 ('s', 'short', None, _('refresh only files already in the patch')),
2211 ('I', 'include', [], _('include names matching the given patterns')),
2212 ('I', 'include', [], _('include names matching the given patterns')),
2212 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2213 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2213 ] + commands.commitopts,
2214 ] + commands.commitopts,
2214 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2215 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2215 'qrename|qmv':
2216 'qrename|qmv':
2216 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2217 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2217 "qrestore":
2218 "qrestore":
2218 (restore,
2219 (restore,
2219 [('d', 'delete', None, _('delete save entry')),
2220 [('d', 'delete', None, _('delete save entry')),
2220 ('u', 'update', None, _('update queue working dir'))],
2221 ('u', 'update', None, _('update queue working dir'))],
2221 _('hg qrestore [-d] [-u] REV')),
2222 _('hg qrestore [-d] [-u] REV')),
2222 "qsave":
2223 "qsave":
2223 (save,
2224 (save,
2224 [('c', 'copy', None, _('copy patch directory')),
2225 [('c', 'copy', None, _('copy patch directory')),
2225 ('n', 'name', '', _('copy directory name')),
2226 ('n', 'name', '', _('copy directory name')),
2226 ('e', 'empty', None, _('clear queue status file')),
2227 ('e', 'empty', None, _('clear queue status file')),
2227 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2228 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2228 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2229 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2229 "qselect":
2230 "qselect":
2230 (select,
2231 (select,
2231 [('n', 'none', None, _('disable all guards')),
2232 [('n', 'none', None, _('disable all guards')),
2232 ('s', 'series', None, _('list all guards in series file')),
2233 ('s', 'series', None, _('list all guards in series file')),
2233 ('', 'pop', None, _('pop to before first guarded applied patch')),
2234 ('', 'pop', None, _('pop to before first guarded applied patch')),
2234 ('', 'reapply', None, _('pop, then reapply patches'))],
2235 ('', 'reapply', None, _('pop, then reapply patches'))],
2235 _('hg qselect [OPTION]... [GUARD]...')),
2236 _('hg qselect [OPTION]... [GUARD]...')),
2236 "qseries":
2237 "qseries":
2237 (series,
2238 (series,
2238 [('m', 'missing', None, _('print patches not in series')),
2239 [('m', 'missing', None, _('print patches not in series')),
2239 ] + seriesopts,
2240 ] + seriesopts,
2240 _('hg qseries [-ms]')),
2241 _('hg qseries [-ms]')),
2241 "^strip":
2242 "^strip":
2242 (strip,
2243 (strip,
2243 [('f', 'force', None, _('force multi-head removal')),
2244 [('f', 'force', None, _('force multi-head removal')),
2244 ('b', 'backup', None, _('bundle unrelated changesets')),
2245 ('b', 'backup', None, _('bundle unrelated changesets')),
2245 ('n', 'nobackup', None, _('no backups'))],
2246 ('n', 'nobackup', None, _('no backups'))],
2246 _('hg strip [-f] [-b] [-n] REV')),
2247 _('hg strip [-f] [-b] [-n] REV')),
2247 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2248 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2248 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2249 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2249 }
2250 }
General Comments 0
You need to be logged in to leave comments. Login now