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