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