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