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