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