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