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