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