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