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