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