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