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