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