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