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