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