##// END OF EJS Templates
use our urlopener (proxy handling, etc) instead of urllib
Benoit Boissinot -
r7271:8046f0a0 default
parent child Browse files
Show More
@@ -1,2508 +1,2505 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 '''patch management and development
8 '''patch management and development
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use "hg help command" for more details):
17 Common tasks (use "hg help command" for more details):
18
18
19 prepare repository to work with patches qinit
19 prepare repository to work with patches qinit
20 create new patch qnew
20 create new patch qnew
21 import existing patch qimport
21 import existing patch qimport
22
22
23 print patch series qseries
23 print patch series qseries
24 print applied patches qapplied
24 print applied patches qapplied
25 print name of top applied patch qtop
25 print name of top applied patch qtop
26
26
27 add known patch to applied stack qpush
27 add known patch to applied stack qpush
28 remove patch from applied stack qpop
28 remove patch from applied stack qpop
29 refresh contents of top applied patch qrefresh
29 refresh contents of top applied patch qrefresh
30 '''
30 '''
31
31
32 from mercurial.i18n import _
32 from mercurial.i18n import _
33 from mercurial.node import bin, hex, short
33 from mercurial.node import bin, hex, short
34 from mercurial.repo import RepoError
34 from mercurial.repo import RepoError
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
36 from mercurial import repair, extensions
36 from mercurial import repair, extensions, url
37 import os, sys, re, errno, urllib
37 import os, sys, re, errno
38
38
39 commands.norepo += " qclone"
39 commands.norepo += " qclone"
40
40
41 # Patch names looks like unix-file names.
41 # Patch names looks like unix-file names.
42 # They must be joinable with queue directory and result in the patch path.
42 # They must be joinable with queue directory and result in the patch path.
43 normname = util.normpath
43 normname = util.normpath
44
44
45 class statusentry:
45 class statusentry:
46 def __init__(self, rev, name=None):
46 def __init__(self, rev, name=None):
47 if not name:
47 if not name:
48 fields = rev.split(':', 1)
48 fields = rev.split(':', 1)
49 if len(fields) == 2:
49 if len(fields) == 2:
50 self.rev, self.name = fields
50 self.rev, self.name = fields
51 else:
51 else:
52 self.rev, self.name = None, None
52 self.rev, self.name = None, None
53 else:
53 else:
54 self.rev, self.name = rev, name
54 self.rev, self.name = rev, name
55
55
56 def __str__(self):
56 def __str__(self):
57 return self.rev + ':' + self.name
57 return self.rev + ':' + self.name
58
58
59 class queue:
59 class queue:
60 def __init__(self, ui, path, patchdir=None):
60 def __init__(self, ui, path, patchdir=None):
61 self.basepath = path
61 self.basepath = path
62 self.path = patchdir or os.path.join(path, "patches")
62 self.path = patchdir or os.path.join(path, "patches")
63 self.opener = util.opener(self.path)
63 self.opener = util.opener(self.path)
64 self.ui = ui
64 self.ui = ui
65 self.applied = []
65 self.applied = []
66 self.full_series = []
66 self.full_series = []
67 self.applied_dirty = 0
67 self.applied_dirty = 0
68 self.series_dirty = 0
68 self.series_dirty = 0
69 self.series_path = "series"
69 self.series_path = "series"
70 self.status_path = "status"
70 self.status_path = "status"
71 self.guards_path = "guards"
71 self.guards_path = "guards"
72 self.active_guards = None
72 self.active_guards = None
73 self.guards_dirty = False
73 self.guards_dirty = False
74 self._diffopts = None
74 self._diffopts = None
75
75
76 if os.path.exists(self.join(self.series_path)):
76 if os.path.exists(self.join(self.series_path)):
77 self.full_series = self.opener(self.series_path).read().splitlines()
77 self.full_series = self.opener(self.series_path).read().splitlines()
78 self.parse_series()
78 self.parse_series()
79
79
80 if os.path.exists(self.join(self.status_path)):
80 if os.path.exists(self.join(self.status_path)):
81 lines = self.opener(self.status_path).read().splitlines()
81 lines = self.opener(self.status_path).read().splitlines()
82 self.applied = [statusentry(l) for l in lines]
82 self.applied = [statusentry(l) for l in lines]
83
83
84 def diffopts(self):
84 def diffopts(self):
85 if self._diffopts is None:
85 if self._diffopts is None:
86 self._diffopts = patch.diffopts(self.ui)
86 self._diffopts = patch.diffopts(self.ui)
87 return self._diffopts
87 return self._diffopts
88
88
89 def join(self, *p):
89 def join(self, *p):
90 return os.path.join(self.path, *p)
90 return os.path.join(self.path, *p)
91
91
92 def find_series(self, patch):
92 def find_series(self, patch):
93 pre = re.compile("(\s*)([^#]+)")
93 pre = re.compile("(\s*)([^#]+)")
94 index = 0
94 index = 0
95 for l in self.full_series:
95 for l in self.full_series:
96 m = pre.match(l)
96 m = pre.match(l)
97 if m:
97 if m:
98 s = m.group(2)
98 s = m.group(2)
99 s = s.rstrip()
99 s = s.rstrip()
100 if s == patch:
100 if s == patch:
101 return index
101 return index
102 index += 1
102 index += 1
103 return None
103 return None
104
104
105 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
105 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
106
106
107 def parse_series(self):
107 def parse_series(self):
108 self.series = []
108 self.series = []
109 self.series_guards = []
109 self.series_guards = []
110 for l in self.full_series:
110 for l in self.full_series:
111 h = l.find('#')
111 h = l.find('#')
112 if h == -1:
112 if h == -1:
113 patch = l
113 patch = l
114 comment = ''
114 comment = ''
115 elif h == 0:
115 elif h == 0:
116 continue
116 continue
117 else:
117 else:
118 patch = l[:h]
118 patch = l[:h]
119 comment = l[h:]
119 comment = l[h:]
120 patch = patch.strip()
120 patch = patch.strip()
121 if patch:
121 if patch:
122 if patch in self.series:
122 if patch in self.series:
123 raise util.Abort(_('%s appears more than once in %s') %
123 raise util.Abort(_('%s appears more than once in %s') %
124 (patch, self.join(self.series_path)))
124 (patch, self.join(self.series_path)))
125 self.series.append(patch)
125 self.series.append(patch)
126 self.series_guards.append(self.guard_re.findall(comment))
126 self.series_guards.append(self.guard_re.findall(comment))
127
127
128 def check_guard(self, guard):
128 def check_guard(self, guard):
129 if not guard:
129 if not guard:
130 return _('guard cannot be an empty string')
130 return _('guard cannot be an empty string')
131 bad_chars = '# \t\r\n\f'
131 bad_chars = '# \t\r\n\f'
132 first = guard[0]
132 first = guard[0]
133 for c in '-+':
133 for c in '-+':
134 if first == c:
134 if first == c:
135 return (_('guard %r starts with invalid character: %r') %
135 return (_('guard %r starts with invalid character: %r') %
136 (guard, c))
136 (guard, c))
137 for c in bad_chars:
137 for c in bad_chars:
138 if c in guard:
138 if c in guard:
139 return _('invalid character in guard %r: %r') % (guard, c)
139 return _('invalid character in guard %r: %r') % (guard, c)
140
140
141 def set_active(self, guards):
141 def set_active(self, guards):
142 for guard in guards:
142 for guard in guards:
143 bad = self.check_guard(guard)
143 bad = self.check_guard(guard)
144 if bad:
144 if bad:
145 raise util.Abort(bad)
145 raise util.Abort(bad)
146 guards = util.sort(util.unique(guards))
146 guards = util.sort(util.unique(guards))
147 self.ui.debug(_('active guards: %s\n') % ' '.join(guards))
147 self.ui.debug(_('active guards: %s\n') % ' '.join(guards))
148 self.active_guards = guards
148 self.active_guards = guards
149 self.guards_dirty = True
149 self.guards_dirty = True
150
150
151 def active(self):
151 def active(self):
152 if self.active_guards is None:
152 if self.active_guards is None:
153 self.active_guards = []
153 self.active_guards = []
154 try:
154 try:
155 guards = self.opener(self.guards_path).read().split()
155 guards = self.opener(self.guards_path).read().split()
156 except IOError, err:
156 except IOError, err:
157 if err.errno != errno.ENOENT: raise
157 if err.errno != errno.ENOENT: raise
158 guards = []
158 guards = []
159 for i, guard in enumerate(guards):
159 for i, guard in enumerate(guards):
160 bad = self.check_guard(guard)
160 bad = self.check_guard(guard)
161 if bad:
161 if bad:
162 self.ui.warn('%s:%d: %s\n' %
162 self.ui.warn('%s:%d: %s\n' %
163 (self.join(self.guards_path), i + 1, bad))
163 (self.join(self.guards_path), i + 1, bad))
164 else:
164 else:
165 self.active_guards.append(guard)
165 self.active_guards.append(guard)
166 return self.active_guards
166 return self.active_guards
167
167
168 def set_guards(self, idx, guards):
168 def set_guards(self, idx, guards):
169 for g in guards:
169 for g in guards:
170 if len(g) < 2:
170 if len(g) < 2:
171 raise util.Abort(_('guard %r too short') % g)
171 raise util.Abort(_('guard %r too short') % g)
172 if g[0] not in '-+':
172 if g[0] not in '-+':
173 raise util.Abort(_('guard %r starts with invalid char') % g)
173 raise util.Abort(_('guard %r starts with invalid char') % g)
174 bad = self.check_guard(g[1:])
174 bad = self.check_guard(g[1:])
175 if bad:
175 if bad:
176 raise util.Abort(bad)
176 raise util.Abort(bad)
177 drop = self.guard_re.sub('', self.full_series[idx])
177 drop = self.guard_re.sub('', self.full_series[idx])
178 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
178 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
179 self.parse_series()
179 self.parse_series()
180 self.series_dirty = True
180 self.series_dirty = True
181
181
182 def pushable(self, idx):
182 def pushable(self, idx):
183 if isinstance(idx, str):
183 if isinstance(idx, str):
184 idx = self.series.index(idx)
184 idx = self.series.index(idx)
185 patchguards = self.series_guards[idx]
185 patchguards = self.series_guards[idx]
186 if not patchguards:
186 if not patchguards:
187 return True, None
187 return True, None
188 default = False
188 default = False
189 guards = self.active()
189 guards = self.active()
190 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
190 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
191 if exactneg:
191 if exactneg:
192 return False, exactneg[0]
192 return False, exactneg[0]
193 pos = [g for g in patchguards if g[0] == '+']
193 pos = [g for g in patchguards if g[0] == '+']
194 exactpos = [g for g in pos if g[1:] in guards]
194 exactpos = [g for g in pos if g[1:] in guards]
195 if pos:
195 if pos:
196 if exactpos:
196 if exactpos:
197 return True, exactpos[0]
197 return True, exactpos[0]
198 return False, pos
198 return False, pos
199 return True, ''
199 return True, ''
200
200
201 def explain_pushable(self, idx, all_patches=False):
201 def explain_pushable(self, idx, all_patches=False):
202 write = all_patches and self.ui.write or self.ui.warn
202 write = all_patches and self.ui.write or self.ui.warn
203 if all_patches or self.ui.verbose:
203 if all_patches or self.ui.verbose:
204 if isinstance(idx, str):
204 if isinstance(idx, str):
205 idx = self.series.index(idx)
205 idx = self.series.index(idx)
206 pushable, why = self.pushable(idx)
206 pushable, why = self.pushable(idx)
207 if all_patches and pushable:
207 if all_patches and pushable:
208 if why is None:
208 if why is None:
209 write(_('allowing %s - no guards in effect\n') %
209 write(_('allowing %s - no guards in effect\n') %
210 self.series[idx])
210 self.series[idx])
211 else:
211 else:
212 if not why:
212 if not why:
213 write(_('allowing %s - no matching negative guards\n') %
213 write(_('allowing %s - no matching negative guards\n') %
214 self.series[idx])
214 self.series[idx])
215 else:
215 else:
216 write(_('allowing %s - guarded by %r\n') %
216 write(_('allowing %s - guarded by %r\n') %
217 (self.series[idx], why))
217 (self.series[idx], why))
218 if not pushable:
218 if not pushable:
219 if why:
219 if why:
220 write(_('skipping %s - guarded by %r\n') %
220 write(_('skipping %s - guarded by %r\n') %
221 (self.series[idx], why))
221 (self.series[idx], why))
222 else:
222 else:
223 write(_('skipping %s - no matching guards\n') %
223 write(_('skipping %s - no matching guards\n') %
224 self.series[idx])
224 self.series[idx])
225
225
226 def save_dirty(self):
226 def save_dirty(self):
227 def write_list(items, path):
227 def write_list(items, path):
228 fp = self.opener(path, 'w')
228 fp = self.opener(path, 'w')
229 for i in items:
229 for i in items:
230 fp.write("%s\n" % i)
230 fp.write("%s\n" % i)
231 fp.close()
231 fp.close()
232 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
232 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
233 if self.series_dirty: write_list(self.full_series, self.series_path)
233 if self.series_dirty: write_list(self.full_series, self.series_path)
234 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
234 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
235
235
236 def readheaders(self, patch):
236 def readheaders(self, patch):
237 def eatdiff(lines):
237 def eatdiff(lines):
238 while lines:
238 while lines:
239 l = lines[-1]
239 l = lines[-1]
240 if (l.startswith("diff -") or
240 if (l.startswith("diff -") or
241 l.startswith("Index:") or
241 l.startswith("Index:") or
242 l.startswith("===========")):
242 l.startswith("===========")):
243 del lines[-1]
243 del lines[-1]
244 else:
244 else:
245 break
245 break
246 def eatempty(lines):
246 def eatempty(lines):
247 while lines:
247 while lines:
248 l = lines[-1]
248 l = lines[-1]
249 if re.match('\s*$', l):
249 if re.match('\s*$', l):
250 del lines[-1]
250 del lines[-1]
251 else:
251 else:
252 break
252 break
253
253
254 pf = self.join(patch)
254 pf = self.join(patch)
255 message = []
255 message = []
256 comments = []
256 comments = []
257 user = None
257 user = None
258 date = None
258 date = None
259 format = None
259 format = None
260 subject = None
260 subject = None
261 diffstart = 0
261 diffstart = 0
262
262
263 for line in file(pf):
263 for line in file(pf):
264 line = line.rstrip()
264 line = line.rstrip()
265 if line.startswith('diff --git'):
265 if line.startswith('diff --git'):
266 diffstart = 2
266 diffstart = 2
267 break
267 break
268 if diffstart:
268 if diffstart:
269 if line.startswith('+++ '):
269 if line.startswith('+++ '):
270 diffstart = 2
270 diffstart = 2
271 break
271 break
272 if line.startswith("--- "):
272 if line.startswith("--- "):
273 diffstart = 1
273 diffstart = 1
274 continue
274 continue
275 elif format == "hgpatch":
275 elif format == "hgpatch":
276 # parse values when importing the result of an hg export
276 # parse values when importing the result of an hg export
277 if line.startswith("# User "):
277 if line.startswith("# User "):
278 user = line[7:]
278 user = line[7:]
279 elif line.startswith("# Date "):
279 elif line.startswith("# Date "):
280 date = line[7:]
280 date = line[7:]
281 elif not line.startswith("# ") and line:
281 elif not line.startswith("# ") and line:
282 message.append(line)
282 message.append(line)
283 format = None
283 format = None
284 elif line == '# HG changeset patch':
284 elif line == '# HG changeset patch':
285 format = "hgpatch"
285 format = "hgpatch"
286 elif (format != "tagdone" and (line.startswith("Subject: ") or
286 elif (format != "tagdone" and (line.startswith("Subject: ") or
287 line.startswith("subject: "))):
287 line.startswith("subject: "))):
288 subject = line[9:]
288 subject = line[9:]
289 format = "tag"
289 format = "tag"
290 elif (format != "tagdone" and (line.startswith("From: ") or
290 elif (format != "tagdone" and (line.startswith("From: ") or
291 line.startswith("from: "))):
291 line.startswith("from: "))):
292 user = line[6:]
292 user = line[6:]
293 format = "tag"
293 format = "tag"
294 elif format == "tag" and line == "":
294 elif format == "tag" and line == "":
295 # when looking for tags (subject: from: etc) they
295 # when looking for tags (subject: from: etc) they
296 # end once you find a blank line in the source
296 # end once you find a blank line in the source
297 format = "tagdone"
297 format = "tagdone"
298 elif message or line:
298 elif message or line:
299 message.append(line)
299 message.append(line)
300 comments.append(line)
300 comments.append(line)
301
301
302 eatdiff(message)
302 eatdiff(message)
303 eatdiff(comments)
303 eatdiff(comments)
304 eatempty(message)
304 eatempty(message)
305 eatempty(comments)
305 eatempty(comments)
306
306
307 # make sure message isn't empty
307 # make sure message isn't empty
308 if format and format.startswith("tag") and subject:
308 if format and format.startswith("tag") and subject:
309 message.insert(0, "")
309 message.insert(0, "")
310 message.insert(0, subject)
310 message.insert(0, subject)
311 return (message, comments, user, date, diffstart > 1)
311 return (message, comments, user, date, diffstart > 1)
312
312
313 def removeundo(self, repo):
313 def removeundo(self, repo):
314 undo = repo.sjoin('undo')
314 undo = repo.sjoin('undo')
315 if not os.path.exists(undo):
315 if not os.path.exists(undo):
316 return
316 return
317 try:
317 try:
318 os.unlink(undo)
318 os.unlink(undo)
319 except OSError, inst:
319 except OSError, inst:
320 self.ui.warn(_('error removing undo: %s\n') % str(inst))
320 self.ui.warn(_('error removing undo: %s\n') % str(inst))
321
321
322 def printdiff(self, repo, node1, node2=None, files=None,
322 def printdiff(self, repo, node1, node2=None, files=None,
323 fp=None, changes=None, opts={}):
323 fp=None, changes=None, opts={}):
324 m = cmdutil.match(repo, files, opts)
324 m = cmdutil.match(repo, files, opts)
325 patch.diff(repo, node1, node2, m, fp, changes, self.diffopts())
325 patch.diff(repo, node1, node2, m, fp, changes, self.diffopts())
326
326
327 def mergeone(self, repo, mergeq, head, patch, rev):
327 def mergeone(self, repo, mergeq, head, patch, rev):
328 # first try just applying the patch
328 # first try just applying the patch
329 (err, n) = self.apply(repo, [ patch ], update_status=False,
329 (err, n) = self.apply(repo, [ patch ], update_status=False,
330 strict=True, merge=rev)
330 strict=True, merge=rev)
331
331
332 if err == 0:
332 if err == 0:
333 return (err, n)
333 return (err, n)
334
334
335 if n is None:
335 if n is None:
336 raise util.Abort(_("apply failed for patch %s") % patch)
336 raise util.Abort(_("apply failed for patch %s") % patch)
337
337
338 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
338 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
339
339
340 # apply failed, strip away that rev and merge.
340 # apply failed, strip away that rev and merge.
341 hg.clean(repo, head)
341 hg.clean(repo, head)
342 self.strip(repo, n, update=False, backup='strip')
342 self.strip(repo, n, update=False, backup='strip')
343
343
344 ctx = repo[rev]
344 ctx = repo[rev]
345 ret = hg.merge(repo, rev)
345 ret = hg.merge(repo, rev)
346 if ret:
346 if ret:
347 raise util.Abort(_("update returned %d") % ret)
347 raise util.Abort(_("update returned %d") % ret)
348 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
348 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
349 if n == None:
349 if n == None:
350 raise util.Abort(_("repo commit failed"))
350 raise util.Abort(_("repo commit failed"))
351 try:
351 try:
352 message, comments, user, date, patchfound = mergeq.readheaders(patch)
352 message, comments, user, date, patchfound = mergeq.readheaders(patch)
353 except:
353 except:
354 raise util.Abort(_("unable to read %s") % patch)
354 raise util.Abort(_("unable to read %s") % patch)
355
355
356 patchf = self.opener(patch, "w")
356 patchf = self.opener(patch, "w")
357 if comments:
357 if comments:
358 comments = "\n".join(comments) + '\n\n'
358 comments = "\n".join(comments) + '\n\n'
359 patchf.write(comments)
359 patchf.write(comments)
360 self.printdiff(repo, head, n, fp=patchf)
360 self.printdiff(repo, head, n, fp=patchf)
361 patchf.close()
361 patchf.close()
362 self.removeundo(repo)
362 self.removeundo(repo)
363 return (0, n)
363 return (0, n)
364
364
365 def qparents(self, repo, rev=None):
365 def qparents(self, repo, rev=None):
366 if rev is None:
366 if rev is None:
367 (p1, p2) = repo.dirstate.parents()
367 (p1, p2) = repo.dirstate.parents()
368 if p2 == revlog.nullid:
368 if p2 == revlog.nullid:
369 return p1
369 return p1
370 if len(self.applied) == 0:
370 if len(self.applied) == 0:
371 return None
371 return None
372 return revlog.bin(self.applied[-1].rev)
372 return revlog.bin(self.applied[-1].rev)
373 pp = repo.changelog.parents(rev)
373 pp = repo.changelog.parents(rev)
374 if pp[1] != revlog.nullid:
374 if pp[1] != revlog.nullid:
375 arevs = [ x.rev for x in self.applied ]
375 arevs = [ x.rev for x in self.applied ]
376 p0 = revlog.hex(pp[0])
376 p0 = revlog.hex(pp[0])
377 p1 = revlog.hex(pp[1])
377 p1 = revlog.hex(pp[1])
378 if p0 in arevs:
378 if p0 in arevs:
379 return pp[0]
379 return pp[0]
380 if p1 in arevs:
380 if p1 in arevs:
381 return pp[1]
381 return pp[1]
382 return pp[0]
382 return pp[0]
383
383
384 def mergepatch(self, repo, mergeq, series):
384 def mergepatch(self, repo, mergeq, series):
385 if len(self.applied) == 0:
385 if len(self.applied) == 0:
386 # each of the patches merged in will have two parents. This
386 # each of the patches merged in will have two parents. This
387 # can confuse the qrefresh, qdiff, and strip code because it
387 # can confuse the qrefresh, qdiff, and strip code because it
388 # needs to know which parent is actually in the patch queue.
388 # needs to know which parent is actually in the patch queue.
389 # so, we insert a merge marker with only one parent. This way
389 # so, we insert a merge marker with only one parent. This way
390 # the first patch in the queue is never a merge patch
390 # the first patch in the queue is never a merge patch
391 #
391 #
392 pname = ".hg.patches.merge.marker"
392 pname = ".hg.patches.merge.marker"
393 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
393 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
394 self.removeundo(repo)
394 self.removeundo(repo)
395 self.applied.append(statusentry(revlog.hex(n), pname))
395 self.applied.append(statusentry(revlog.hex(n), pname))
396 self.applied_dirty = 1
396 self.applied_dirty = 1
397
397
398 head = self.qparents(repo)
398 head = self.qparents(repo)
399
399
400 for patch in series:
400 for patch in series:
401 patch = mergeq.lookup(patch, strict=True)
401 patch = mergeq.lookup(patch, strict=True)
402 if not patch:
402 if not patch:
403 self.ui.warn(_("patch %s does not exist\n") % patch)
403 self.ui.warn(_("patch %s does not exist\n") % patch)
404 return (1, None)
404 return (1, None)
405 pushable, reason = self.pushable(patch)
405 pushable, reason = self.pushable(patch)
406 if not pushable:
406 if not pushable:
407 self.explain_pushable(patch, all_patches=True)
407 self.explain_pushable(patch, all_patches=True)
408 continue
408 continue
409 info = mergeq.isapplied(patch)
409 info = mergeq.isapplied(patch)
410 if not info:
410 if not info:
411 self.ui.warn(_("patch %s is not applied\n") % patch)
411 self.ui.warn(_("patch %s is not applied\n") % patch)
412 return (1, None)
412 return (1, None)
413 rev = revlog.bin(info[1])
413 rev = revlog.bin(info[1])
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
415 if head:
415 if head:
416 self.applied.append(statusentry(revlog.hex(head), patch))
416 self.applied.append(statusentry(revlog.hex(head), patch))
417 self.applied_dirty = 1
417 self.applied_dirty = 1
418 if err:
418 if err:
419 return (err, head)
419 return (err, head)
420 self.save_dirty()
420 self.save_dirty()
421 return (0, head)
421 return (0, head)
422
422
423 def patch(self, repo, patchfile):
423 def patch(self, repo, patchfile):
424 '''Apply patchfile to the working directory.
424 '''Apply patchfile to the working directory.
425 patchfile: file name of patch'''
425 patchfile: file name of patch'''
426 files = {}
426 files = {}
427 try:
427 try:
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
429 files=files)
429 files=files)
430 except Exception, inst:
430 except Exception, inst:
431 self.ui.note(str(inst) + '\n')
431 self.ui.note(str(inst) + '\n')
432 if not self.ui.verbose:
432 if not self.ui.verbose:
433 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
433 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
434 return (False, files, False)
434 return (False, files, False)
435
435
436 return (True, files, fuzz)
436 return (True, files, fuzz)
437
437
438 def apply(self, repo, series, list=False, update_status=True,
438 def apply(self, repo, series, list=False, update_status=True,
439 strict=False, patchdir=None, merge=None, all_files={}):
439 strict=False, patchdir=None, merge=None, all_files={}):
440 wlock = lock = tr = None
440 wlock = lock = tr = None
441 try:
441 try:
442 wlock = repo.wlock()
442 wlock = repo.wlock()
443 lock = repo.lock()
443 lock = repo.lock()
444 tr = repo.transaction()
444 tr = repo.transaction()
445 try:
445 try:
446 ret = self._apply(repo, series, list, update_status,
446 ret = self._apply(repo, series, list, update_status,
447 strict, patchdir, merge, all_files=all_files)
447 strict, patchdir, merge, all_files=all_files)
448 tr.close()
448 tr.close()
449 self.save_dirty()
449 self.save_dirty()
450 return ret
450 return ret
451 except:
451 except:
452 try:
452 try:
453 tr.abort()
453 tr.abort()
454 finally:
454 finally:
455 repo.invalidate()
455 repo.invalidate()
456 repo.dirstate.invalidate()
456 repo.dirstate.invalidate()
457 raise
457 raise
458 finally:
458 finally:
459 del tr, lock, wlock
459 del tr, lock, wlock
460 self.removeundo(repo)
460 self.removeundo(repo)
461
461
462 def _apply(self, repo, series, list=False, update_status=True,
462 def _apply(self, repo, series, list=False, update_status=True,
463 strict=False, patchdir=None, merge=None, all_files={}):
463 strict=False, patchdir=None, merge=None, all_files={}):
464 # TODO unify with commands.py
464 # TODO unify with commands.py
465 if not patchdir:
465 if not patchdir:
466 patchdir = self.path
466 patchdir = self.path
467 err = 0
467 err = 0
468 n = None
468 n = None
469 for patchname in series:
469 for patchname in series:
470 pushable, reason = self.pushable(patchname)
470 pushable, reason = self.pushable(patchname)
471 if not pushable:
471 if not pushable:
472 self.explain_pushable(patchname, all_patches=True)
472 self.explain_pushable(patchname, all_patches=True)
473 continue
473 continue
474 self.ui.warn(_("applying %s\n") % patchname)
474 self.ui.warn(_("applying %s\n") % patchname)
475 pf = os.path.join(patchdir, patchname)
475 pf = os.path.join(patchdir, patchname)
476
476
477 try:
477 try:
478 message, comments, user, date, patchfound = self.readheaders(patchname)
478 message, comments, user, date, patchfound = self.readheaders(patchname)
479 except:
479 except:
480 self.ui.warn(_("Unable to read %s\n") % patchname)
480 self.ui.warn(_("Unable to read %s\n") % patchname)
481 err = 1
481 err = 1
482 break
482 break
483
483
484 if not message:
484 if not message:
485 message = _("imported patch %s\n") % patchname
485 message = _("imported patch %s\n") % patchname
486 else:
486 else:
487 if list:
487 if list:
488 message.append(_("\nimported patch %s") % patchname)
488 message.append(_("\nimported patch %s") % patchname)
489 message = '\n'.join(message)
489 message = '\n'.join(message)
490
490
491 (patcherr, files, fuzz) = self.patch(repo, pf)
491 (patcherr, files, fuzz) = self.patch(repo, pf)
492 all_files.update(files)
492 all_files.update(files)
493 patcherr = not patcherr
493 patcherr = not patcherr
494
494
495 if merge and files:
495 if merge and files:
496 # Mark as removed/merged and update dirstate parent info
496 # Mark as removed/merged and update dirstate parent info
497 removed = []
497 removed = []
498 merged = []
498 merged = []
499 for f in files:
499 for f in files:
500 if os.path.exists(repo.wjoin(f)):
500 if os.path.exists(repo.wjoin(f)):
501 merged.append(f)
501 merged.append(f)
502 else:
502 else:
503 removed.append(f)
503 removed.append(f)
504 for f in removed:
504 for f in removed:
505 repo.dirstate.remove(f)
505 repo.dirstate.remove(f)
506 for f in merged:
506 for f in merged:
507 repo.dirstate.merge(f)
507 repo.dirstate.merge(f)
508 p1, p2 = repo.dirstate.parents()
508 p1, p2 = repo.dirstate.parents()
509 repo.dirstate.setparents(p1, merge)
509 repo.dirstate.setparents(p1, merge)
510
510
511 files = patch.updatedir(self.ui, repo, files)
511 files = patch.updatedir(self.ui, repo, files)
512 match = cmdutil.matchfiles(repo, files or [])
512 match = cmdutil.matchfiles(repo, files or [])
513 n = repo.commit(files, message, user, date, match=match,
513 n = repo.commit(files, message, user, date, match=match,
514 force=True)
514 force=True)
515
515
516 if n == None:
516 if n == None:
517 raise util.Abort(_("repo commit failed"))
517 raise util.Abort(_("repo commit failed"))
518
518
519 if update_status:
519 if update_status:
520 self.applied.append(statusentry(revlog.hex(n), patchname))
520 self.applied.append(statusentry(revlog.hex(n), patchname))
521
521
522 if patcherr:
522 if patcherr:
523 if not patchfound:
523 if not patchfound:
524 self.ui.warn(_("patch %s is empty\n") % patchname)
524 self.ui.warn(_("patch %s is empty\n") % patchname)
525 err = 0
525 err = 0
526 else:
526 else:
527 self.ui.warn(_("patch failed, rejects left in working dir\n"))
527 self.ui.warn(_("patch failed, rejects left in working dir\n"))
528 err = 1
528 err = 1
529 break
529 break
530
530
531 if fuzz and strict:
531 if fuzz and strict:
532 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
532 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
533 err = 1
533 err = 1
534 break
534 break
535 return (err, n)
535 return (err, n)
536
536
537 def _clean_series(self, patches):
537 def _clean_series(self, patches):
538 indices = util.sort([self.find_series(p) for p in patches])
538 indices = util.sort([self.find_series(p) for p in patches])
539 for i in indices[-1::-1]:
539 for i in indices[-1::-1]:
540 del self.full_series[i]
540 del self.full_series[i]
541 self.parse_series()
541 self.parse_series()
542 self.series_dirty = 1
542 self.series_dirty = 1
543
543
544 def finish(self, repo, revs):
544 def finish(self, repo, revs):
545 revs.sort()
545 revs.sort()
546 firstrev = repo[self.applied[0].rev].rev()
546 firstrev = repo[self.applied[0].rev].rev()
547 appliedbase = 0
547 appliedbase = 0
548 patches = []
548 patches = []
549 for rev in util.sort(revs):
549 for rev in util.sort(revs):
550 if rev < firstrev:
550 if rev < firstrev:
551 raise util.Abort(_('revision %d is not managed') % rev)
551 raise util.Abort(_('revision %d is not managed') % rev)
552 base = revlog.bin(self.applied[appliedbase].rev)
552 base = revlog.bin(self.applied[appliedbase].rev)
553 node = repo.changelog.node(rev)
553 node = repo.changelog.node(rev)
554 if node != base:
554 if node != base:
555 raise util.Abort(_('cannot delete revision %d above '
555 raise util.Abort(_('cannot delete revision %d above '
556 'applied patches') % rev)
556 'applied patches') % rev)
557 patches.append(self.applied[appliedbase].name)
557 patches.append(self.applied[appliedbase].name)
558 appliedbase += 1
558 appliedbase += 1
559
559
560 r = self.qrepo()
560 r = self.qrepo()
561 if r:
561 if r:
562 r.remove(patches, True)
562 r.remove(patches, True)
563 else:
563 else:
564 for p in patches:
564 for p in patches:
565 os.unlink(self.join(p))
565 os.unlink(self.join(p))
566
566
567 del self.applied[:appliedbase]
567 del self.applied[:appliedbase]
568 self.applied_dirty = 1
568 self.applied_dirty = 1
569 self._clean_series(patches)
569 self._clean_series(patches)
570
570
571 def delete(self, repo, patches, opts):
571 def delete(self, repo, patches, opts):
572 if not patches and not opts.get('rev'):
572 if not patches and not opts.get('rev'):
573 raise util.Abort(_('qdelete requires at least one revision or '
573 raise util.Abort(_('qdelete requires at least one revision or '
574 'patch name'))
574 'patch name'))
575
575
576 realpatches = []
576 realpatches = []
577 for patch in patches:
577 for patch in patches:
578 patch = self.lookup(patch, strict=True)
578 patch = self.lookup(patch, strict=True)
579 info = self.isapplied(patch)
579 info = self.isapplied(patch)
580 if info:
580 if info:
581 raise util.Abort(_("cannot delete applied patch %s") % patch)
581 raise util.Abort(_("cannot delete applied patch %s") % patch)
582 if patch not in self.series:
582 if patch not in self.series:
583 raise util.Abort(_("patch %s not in series file") % patch)
583 raise util.Abort(_("patch %s not in series file") % patch)
584 realpatches.append(patch)
584 realpatches.append(patch)
585
585
586 appliedbase = 0
586 appliedbase = 0
587 if opts.get('rev'):
587 if opts.get('rev'):
588 if not self.applied:
588 if not self.applied:
589 raise util.Abort(_('no patches applied'))
589 raise util.Abort(_('no patches applied'))
590 revs = cmdutil.revrange(repo, opts['rev'])
590 revs = cmdutil.revrange(repo, opts['rev'])
591 if len(revs) > 1 and revs[0] > revs[1]:
591 if len(revs) > 1 and revs[0] > revs[1]:
592 revs.reverse()
592 revs.reverse()
593 for rev in revs:
593 for rev in revs:
594 if appliedbase >= len(self.applied):
594 if appliedbase >= len(self.applied):
595 raise util.Abort(_("revision %d is not managed") % rev)
595 raise util.Abort(_("revision %d is not managed") % rev)
596
596
597 base = revlog.bin(self.applied[appliedbase].rev)
597 base = revlog.bin(self.applied[appliedbase].rev)
598 node = repo.changelog.node(rev)
598 node = repo.changelog.node(rev)
599 if node != base:
599 if node != base:
600 raise util.Abort(_("cannot delete revision %d above "
600 raise util.Abort(_("cannot delete revision %d above "
601 "applied patches") % rev)
601 "applied patches") % rev)
602 realpatches.append(self.applied[appliedbase].name)
602 realpatches.append(self.applied[appliedbase].name)
603 appliedbase += 1
603 appliedbase += 1
604
604
605 if not opts.get('keep'):
605 if not opts.get('keep'):
606 r = self.qrepo()
606 r = self.qrepo()
607 if r:
607 if r:
608 r.remove(realpatches, True)
608 r.remove(realpatches, True)
609 else:
609 else:
610 for p in realpatches:
610 for p in realpatches:
611 os.unlink(self.join(p))
611 os.unlink(self.join(p))
612
612
613 if appliedbase:
613 if appliedbase:
614 del self.applied[:appliedbase]
614 del self.applied[:appliedbase]
615 self.applied_dirty = 1
615 self.applied_dirty = 1
616 self._clean_series(realpatches)
616 self._clean_series(realpatches)
617
617
618 def check_toppatch(self, repo):
618 def check_toppatch(self, repo):
619 if len(self.applied) > 0:
619 if len(self.applied) > 0:
620 top = revlog.bin(self.applied[-1].rev)
620 top = revlog.bin(self.applied[-1].rev)
621 pp = repo.dirstate.parents()
621 pp = repo.dirstate.parents()
622 if top not in pp:
622 if top not in pp:
623 raise util.Abort(_("working directory revision is not qtip"))
623 raise util.Abort(_("working directory revision is not qtip"))
624 return top
624 return top
625 return None
625 return None
626 def check_localchanges(self, repo, force=False, refresh=True):
626 def check_localchanges(self, repo, force=False, refresh=True):
627 m, a, r, d = repo.status()[:4]
627 m, a, r, d = repo.status()[:4]
628 if m or a or r or d:
628 if m or a or r or d:
629 if not force:
629 if not force:
630 if refresh:
630 if refresh:
631 raise util.Abort(_("local changes found, refresh first"))
631 raise util.Abort(_("local changes found, refresh first"))
632 else:
632 else:
633 raise util.Abort(_("local changes found"))
633 raise util.Abort(_("local changes found"))
634 return m, a, r, d
634 return m, a, r, d
635
635
636 _reserved = ('series', 'status', 'guards')
636 _reserved = ('series', 'status', 'guards')
637 def check_reserved_name(self, name):
637 def check_reserved_name(self, name):
638 if (name in self._reserved or name.startswith('.hg')
638 if (name in self._reserved or name.startswith('.hg')
639 or name.startswith('.mq')):
639 or name.startswith('.mq')):
640 raise util.Abort(_('"%s" cannot be used as the name of a patch')
640 raise util.Abort(_('"%s" cannot be used as the name of a patch')
641 % name)
641 % name)
642
642
643 def new(self, repo, patchfn, *pats, **opts):
643 def new(self, repo, patchfn, *pats, **opts):
644 """options:
644 """options:
645 msg: a string or a no-argument function returning a string
645 msg: a string or a no-argument function returning a string
646 """
646 """
647 msg = opts.get('msg')
647 msg = opts.get('msg')
648 force = opts.get('force')
648 force = opts.get('force')
649 user = opts.get('user')
649 user = opts.get('user')
650 date = opts.get('date')
650 date = opts.get('date')
651 if date:
651 if date:
652 date = util.parsedate(date)
652 date = util.parsedate(date)
653 self.check_reserved_name(patchfn)
653 self.check_reserved_name(patchfn)
654 if os.path.exists(self.join(patchfn)):
654 if os.path.exists(self.join(patchfn)):
655 raise util.Abort(_('patch "%s" already exists') % patchfn)
655 raise util.Abort(_('patch "%s" already exists') % patchfn)
656 if opts.get('include') or opts.get('exclude') or pats:
656 if opts.get('include') or opts.get('exclude') or pats:
657 match = cmdutil.match(repo, pats, opts)
657 match = cmdutil.match(repo, pats, opts)
658 # detect missing files in pats
658 # detect missing files in pats
659 def badfn(f, msg):
659 def badfn(f, msg):
660 raise util.Abort('%s: %s' % (f, msg))
660 raise util.Abort('%s: %s' % (f, msg))
661 match.bad = badfn
661 match.bad = badfn
662 m, a, r, d = repo.status(match=match)[:4]
662 m, a, r, d = repo.status(match=match)[:4]
663 else:
663 else:
664 m, a, r, d = self.check_localchanges(repo, force)
664 m, a, r, d = self.check_localchanges(repo, force)
665 match = cmdutil.match(repo, m + a + r)
665 match = cmdutil.match(repo, m + a + r)
666 commitfiles = m + a + r
666 commitfiles = m + a + r
667 self.check_toppatch(repo)
667 self.check_toppatch(repo)
668 insert = self.full_series_end()
668 insert = self.full_series_end()
669 wlock = repo.wlock()
669 wlock = repo.wlock()
670 try:
670 try:
671 # if patch file write fails, abort early
671 # if patch file write fails, abort early
672 p = self.opener(patchfn, "w")
672 p = self.opener(patchfn, "w")
673 try:
673 try:
674 if date:
674 if date:
675 p.write("# HG changeset patch\n")
675 p.write("# HG changeset patch\n")
676 if user:
676 if user:
677 p.write("# User " + user + "\n")
677 p.write("# User " + user + "\n")
678 p.write("# Date %d %d\n\n" % date)
678 p.write("# Date %d %d\n\n" % date)
679 elif user:
679 elif user:
680 p.write("From: " + user + "\n\n")
680 p.write("From: " + user + "\n\n")
681
681
682 if callable(msg):
682 if callable(msg):
683 msg = msg()
683 msg = msg()
684 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
684 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
685 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
685 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
686 if n == None:
686 if n == None:
687 raise util.Abort(_("repo commit failed"))
687 raise util.Abort(_("repo commit failed"))
688 try:
688 try:
689 self.full_series[insert:insert] = [patchfn]
689 self.full_series[insert:insert] = [patchfn]
690 self.applied.append(statusentry(revlog.hex(n), patchfn))
690 self.applied.append(statusentry(revlog.hex(n), patchfn))
691 self.parse_series()
691 self.parse_series()
692 self.series_dirty = 1
692 self.series_dirty = 1
693 self.applied_dirty = 1
693 self.applied_dirty = 1
694 if msg:
694 if msg:
695 msg = msg + "\n"
695 msg = msg + "\n"
696 p.write(msg)
696 p.write(msg)
697 if commitfiles:
697 if commitfiles:
698 diffopts = self.diffopts()
698 diffopts = self.diffopts()
699 if opts.get('git'): diffopts.git = True
699 if opts.get('git'): diffopts.git = True
700 parent = self.qparents(repo, n)
700 parent = self.qparents(repo, n)
701 patch.diff(repo, node1=parent, node2=n, fp=p,
701 patch.diff(repo, node1=parent, node2=n, fp=p,
702 match=match, opts=diffopts)
702 match=match, opts=diffopts)
703 p.close()
703 p.close()
704 wlock = None
704 wlock = None
705 r = self.qrepo()
705 r = self.qrepo()
706 if r: r.add([patchfn])
706 if r: r.add([patchfn])
707 except:
707 except:
708 repo.rollback()
708 repo.rollback()
709 raise
709 raise
710 except Exception, inst:
710 except Exception, inst:
711 patchpath = self.join(patchfn)
711 patchpath = self.join(patchfn)
712 try:
712 try:
713 os.unlink(patchpath)
713 os.unlink(patchpath)
714 except:
714 except:
715 self.ui.warn(_('error unlinking %s\n') % patchpath)
715 self.ui.warn(_('error unlinking %s\n') % patchpath)
716 raise
716 raise
717 self.removeundo(repo)
717 self.removeundo(repo)
718 finally:
718 finally:
719 del wlock
719 del wlock
720
720
721 def strip(self, repo, rev, update=True, backup="all", force=None):
721 def strip(self, repo, rev, update=True, backup="all", force=None):
722 wlock = lock = None
722 wlock = lock = None
723 try:
723 try:
724 wlock = repo.wlock()
724 wlock = repo.wlock()
725 lock = repo.lock()
725 lock = repo.lock()
726
726
727 if update:
727 if update:
728 self.check_localchanges(repo, force=force, refresh=False)
728 self.check_localchanges(repo, force=force, refresh=False)
729 urev = self.qparents(repo, rev)
729 urev = self.qparents(repo, rev)
730 hg.clean(repo, urev)
730 hg.clean(repo, urev)
731 repo.dirstate.write()
731 repo.dirstate.write()
732
732
733 self.removeundo(repo)
733 self.removeundo(repo)
734 repair.strip(self.ui, repo, rev, backup)
734 repair.strip(self.ui, repo, rev, backup)
735 # strip may have unbundled a set of backed up revisions after
735 # strip may have unbundled a set of backed up revisions after
736 # the actual strip
736 # the actual strip
737 self.removeundo(repo)
737 self.removeundo(repo)
738 finally:
738 finally:
739 del lock, wlock
739 del lock, wlock
740
740
741 def isapplied(self, patch):
741 def isapplied(self, patch):
742 """returns (index, rev, patch)"""
742 """returns (index, rev, patch)"""
743 for i in xrange(len(self.applied)):
743 for i in xrange(len(self.applied)):
744 a = self.applied[i]
744 a = self.applied[i]
745 if a.name == patch:
745 if a.name == patch:
746 return (i, a.rev, a.name)
746 return (i, a.rev, a.name)
747 return None
747 return None
748
748
749 # if the exact patch name does not exist, we try a few
749 # if the exact patch name does not exist, we try a few
750 # variations. If strict is passed, we try only #1
750 # variations. If strict is passed, we try only #1
751 #
751 #
752 # 1) a number to indicate an offset in the series file
752 # 1) a number to indicate an offset in the series file
753 # 2) a unique substring of the patch name was given
753 # 2) a unique substring of the patch name was given
754 # 3) patchname[-+]num to indicate an offset in the series file
754 # 3) patchname[-+]num to indicate an offset in the series file
755 def lookup(self, patch, strict=False):
755 def lookup(self, patch, strict=False):
756 patch = patch and str(patch)
756 patch = patch and str(patch)
757
757
758 def partial_name(s):
758 def partial_name(s):
759 if s in self.series:
759 if s in self.series:
760 return s
760 return s
761 matches = [x for x in self.series if s in x]
761 matches = [x for x in self.series if s in x]
762 if len(matches) > 1:
762 if len(matches) > 1:
763 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
763 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
764 for m in matches:
764 for m in matches:
765 self.ui.warn(' %s\n' % m)
765 self.ui.warn(' %s\n' % m)
766 return None
766 return None
767 if matches:
767 if matches:
768 return matches[0]
768 return matches[0]
769 if len(self.series) > 0 and len(self.applied) > 0:
769 if len(self.series) > 0 and len(self.applied) > 0:
770 if s == 'qtip':
770 if s == 'qtip':
771 return self.series[self.series_end(True)-1]
771 return self.series[self.series_end(True)-1]
772 if s == 'qbase':
772 if s == 'qbase':
773 return self.series[0]
773 return self.series[0]
774 return None
774 return None
775 if patch == None:
775 if patch == None:
776 return None
776 return None
777
777
778 # we don't want to return a partial match until we make
778 # we don't want to return a partial match until we make
779 # sure the file name passed in does not exist (checked below)
779 # sure the file name passed in does not exist (checked below)
780 res = partial_name(patch)
780 res = partial_name(patch)
781 if res and res == patch:
781 if res and res == patch:
782 return res
782 return res
783
783
784 if not os.path.isfile(self.join(patch)):
784 if not os.path.isfile(self.join(patch)):
785 try:
785 try:
786 sno = int(patch)
786 sno = int(patch)
787 except(ValueError, OverflowError):
787 except(ValueError, OverflowError):
788 pass
788 pass
789 else:
789 else:
790 if sno < len(self.series):
790 if sno < len(self.series):
791 return self.series[sno]
791 return self.series[sno]
792 if not strict:
792 if not strict:
793 # return any partial match made above
793 # return any partial match made above
794 if res:
794 if res:
795 return res
795 return res
796 minus = patch.rfind('-')
796 minus = patch.rfind('-')
797 if minus >= 0:
797 if minus >= 0:
798 res = partial_name(patch[:minus])
798 res = partial_name(patch[:minus])
799 if res:
799 if res:
800 i = self.series.index(res)
800 i = self.series.index(res)
801 try:
801 try:
802 off = int(patch[minus+1:] or 1)
802 off = int(patch[minus+1:] or 1)
803 except(ValueError, OverflowError):
803 except(ValueError, OverflowError):
804 pass
804 pass
805 else:
805 else:
806 if i - off >= 0:
806 if i - off >= 0:
807 return self.series[i - off]
807 return self.series[i - off]
808 plus = patch.rfind('+')
808 plus = patch.rfind('+')
809 if plus >= 0:
809 if plus >= 0:
810 res = partial_name(patch[:plus])
810 res = partial_name(patch[:plus])
811 if res:
811 if res:
812 i = self.series.index(res)
812 i = self.series.index(res)
813 try:
813 try:
814 off = int(patch[plus+1:] or 1)
814 off = int(patch[plus+1:] or 1)
815 except(ValueError, OverflowError):
815 except(ValueError, OverflowError):
816 pass
816 pass
817 else:
817 else:
818 if i + off < len(self.series):
818 if i + off < len(self.series):
819 return self.series[i + off]
819 return self.series[i + off]
820 raise util.Abort(_("patch %s not in series") % patch)
820 raise util.Abort(_("patch %s not in series") % patch)
821
821
822 def push(self, repo, patch=None, force=False, list=False,
822 def push(self, repo, patch=None, force=False, list=False,
823 mergeq=None):
823 mergeq=None):
824 wlock = repo.wlock()
824 wlock = repo.wlock()
825 if repo.dirstate.parents()[0] != repo.changelog.tip():
825 if repo.dirstate.parents()[0] != repo.changelog.tip():
826 self.ui.status(_("(working directory not at tip)\n"))
826 self.ui.status(_("(working directory not at tip)\n"))
827
827
828 try:
828 try:
829 patch = self.lookup(patch)
829 patch = self.lookup(patch)
830 # Suppose our series file is: A B C and the current 'top'
830 # Suppose our series file is: A B C and the current 'top'
831 # patch is B. qpush C should be performed (moving forward)
831 # patch is B. qpush C should be performed (moving forward)
832 # qpush B is a NOP (no change) qpush A is an error (can't
832 # qpush B is a NOP (no change) qpush A is an error (can't
833 # go backwards with qpush)
833 # go backwards with qpush)
834 if patch:
834 if patch:
835 info = self.isapplied(patch)
835 info = self.isapplied(patch)
836 if info:
836 if info:
837 if info[0] < len(self.applied) - 1:
837 if info[0] < len(self.applied) - 1:
838 raise util.Abort(
838 raise util.Abort(
839 _("cannot push to a previous patch: %s") % patch)
839 _("cannot push to a previous patch: %s") % patch)
840 if info[0] < len(self.series) - 1:
840 if info[0] < len(self.series) - 1:
841 self.ui.warn(
841 self.ui.warn(
842 _('qpush: %s is already at the top\n') % patch)
842 _('qpush: %s is already at the top\n') % patch)
843 else:
843 else:
844 self.ui.warn(_('all patches are currently applied\n'))
844 self.ui.warn(_('all patches are currently applied\n'))
845 return
845 return
846
846
847 # Following the above example, starting at 'top' of B:
847 # Following the above example, starting at 'top' of B:
848 # qpush should be performed (pushes C), but a subsequent
848 # qpush should be performed (pushes C), but a subsequent
849 # qpush without an argument is an error (nothing to
849 # qpush without an argument is an error (nothing to
850 # apply). This allows a loop of "...while hg qpush..." to
850 # apply). This allows a loop of "...while hg qpush..." to
851 # work as it detects an error when done
851 # work as it detects an error when done
852 if self.series_end() == len(self.series):
852 if self.series_end() == len(self.series):
853 self.ui.warn(_('patch series already fully applied\n'))
853 self.ui.warn(_('patch series already fully applied\n'))
854 return 1
854 return 1
855 if not force:
855 if not force:
856 self.check_localchanges(repo)
856 self.check_localchanges(repo)
857
857
858 self.applied_dirty = 1;
858 self.applied_dirty = 1;
859 start = self.series_end()
859 start = self.series_end()
860 if start > 0:
860 if start > 0:
861 self.check_toppatch(repo)
861 self.check_toppatch(repo)
862 if not patch:
862 if not patch:
863 patch = self.series[start]
863 patch = self.series[start]
864 end = start + 1
864 end = start + 1
865 else:
865 else:
866 end = self.series.index(patch, start) + 1
866 end = self.series.index(patch, start) + 1
867 s = self.series[start:end]
867 s = self.series[start:end]
868 all_files = {}
868 all_files = {}
869 try:
869 try:
870 if mergeq:
870 if mergeq:
871 ret = self.mergepatch(repo, mergeq, s)
871 ret = self.mergepatch(repo, mergeq, s)
872 else:
872 else:
873 ret = self.apply(repo, s, list, all_files=all_files)
873 ret = self.apply(repo, s, list, all_files=all_files)
874 except:
874 except:
875 self.ui.warn(_('cleaning up working directory...'))
875 self.ui.warn(_('cleaning up working directory...'))
876 node = repo.dirstate.parents()[0]
876 node = repo.dirstate.parents()[0]
877 hg.revert(repo, node, None)
877 hg.revert(repo, node, None)
878 unknown = repo.status(unknown=True)[4]
878 unknown = repo.status(unknown=True)[4]
879 # only remove unknown files that we know we touched or
879 # only remove unknown files that we know we touched or
880 # created while patching
880 # created while patching
881 for f in unknown:
881 for f in unknown:
882 if f in all_files:
882 if f in all_files:
883 util.unlink(repo.wjoin(f))
883 util.unlink(repo.wjoin(f))
884 self.ui.warn(_('done\n'))
884 self.ui.warn(_('done\n'))
885 raise
885 raise
886 top = self.applied[-1].name
886 top = self.applied[-1].name
887 if ret[0]:
887 if ret[0]:
888 self.ui.write(
888 self.ui.write(
889 "Errors during apply, please fix and refresh %s\n" % top)
889 "Errors during apply, please fix and refresh %s\n" % top)
890 else:
890 else:
891 self.ui.write("Now at: %s\n" % top)
891 self.ui.write("Now at: %s\n" % top)
892 return ret[0]
892 return ret[0]
893 finally:
893 finally:
894 del wlock
894 del wlock
895
895
896 def pop(self, repo, patch=None, force=False, update=True, all=False):
896 def pop(self, repo, patch=None, force=False, update=True, all=False):
897 def getfile(f, rev, flags):
897 def getfile(f, rev, flags):
898 t = repo.file(f).read(rev)
898 t = repo.file(f).read(rev)
899 repo.wwrite(f, t, flags)
899 repo.wwrite(f, t, flags)
900
900
901 wlock = repo.wlock()
901 wlock = repo.wlock()
902 try:
902 try:
903 if patch:
903 if patch:
904 # index, rev, patch
904 # index, rev, patch
905 info = self.isapplied(patch)
905 info = self.isapplied(patch)
906 if not info:
906 if not info:
907 patch = self.lookup(patch)
907 patch = self.lookup(patch)
908 info = self.isapplied(patch)
908 info = self.isapplied(patch)
909 if not info:
909 if not info:
910 raise util.Abort(_("patch %s is not applied") % patch)
910 raise util.Abort(_("patch %s is not applied") % patch)
911
911
912 if len(self.applied) == 0:
912 if len(self.applied) == 0:
913 # Allow qpop -a to work repeatedly,
913 # Allow qpop -a to work repeatedly,
914 # but not qpop without an argument
914 # but not qpop without an argument
915 self.ui.warn(_("no patches applied\n"))
915 self.ui.warn(_("no patches applied\n"))
916 return not all
916 return not all
917
917
918 if not update:
918 if not update:
919 parents = repo.dirstate.parents()
919 parents = repo.dirstate.parents()
920 rr = [ revlog.bin(x.rev) for x in self.applied ]
920 rr = [ revlog.bin(x.rev) for x in self.applied ]
921 for p in parents:
921 for p in parents:
922 if p in rr:
922 if p in rr:
923 self.ui.warn(_("qpop: forcing dirstate update\n"))
923 self.ui.warn(_("qpop: forcing dirstate update\n"))
924 update = True
924 update = True
925
925
926 if not force and update:
926 if not force and update:
927 self.check_localchanges(repo)
927 self.check_localchanges(repo)
928
928
929 self.applied_dirty = 1;
929 self.applied_dirty = 1;
930 end = len(self.applied)
930 end = len(self.applied)
931 if not patch:
931 if not patch:
932 if all:
932 if all:
933 popi = 0
933 popi = 0
934 else:
934 else:
935 popi = len(self.applied) - 1
935 popi = len(self.applied) - 1
936 else:
936 else:
937 popi = info[0] + 1
937 popi = info[0] + 1
938 if popi >= end:
938 if popi >= end:
939 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
939 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
940 return
940 return
941 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
941 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
942
942
943 start = info[0]
943 start = info[0]
944 rev = revlog.bin(info[1])
944 rev = revlog.bin(info[1])
945
945
946 if update:
946 if update:
947 top = self.check_toppatch(repo)
947 top = self.check_toppatch(repo)
948
948
949 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
949 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
950 raise util.Abort(_("popping would remove a revision not "
950 raise util.Abort(_("popping would remove a revision not "
951 "managed by this patch queue"))
951 "managed by this patch queue"))
952
952
953 # we know there are no local changes, so we can make a simplified
953 # we know there are no local changes, so we can make a simplified
954 # form of hg.update.
954 # form of hg.update.
955 if update:
955 if update:
956 qp = self.qparents(repo, rev)
956 qp = self.qparents(repo, rev)
957 changes = repo.changelog.read(qp)
957 changes = repo.changelog.read(qp)
958 mmap = repo.manifest.read(changes[0])
958 mmap = repo.manifest.read(changes[0])
959 m, a, r, d = repo.status(qp, top)[:4]
959 m, a, r, d = repo.status(qp, top)[:4]
960 if d:
960 if d:
961 raise util.Abort(_("deletions found between repo revs"))
961 raise util.Abort(_("deletions found between repo revs"))
962 for f in m:
962 for f in m:
963 getfile(f, mmap[f], mmap.flags(f))
963 getfile(f, mmap[f], mmap.flags(f))
964 for f in r:
964 for f in r:
965 getfile(f, mmap[f], mmap.flags(f))
965 getfile(f, mmap[f], mmap.flags(f))
966 for f in m + r:
966 for f in m + r:
967 repo.dirstate.normal(f)
967 repo.dirstate.normal(f)
968 for f in a:
968 for f in a:
969 try:
969 try:
970 os.unlink(repo.wjoin(f))
970 os.unlink(repo.wjoin(f))
971 except OSError, e:
971 except OSError, e:
972 if e.errno != errno.ENOENT:
972 if e.errno != errno.ENOENT:
973 raise
973 raise
974 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
974 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
975 except: pass
975 except: pass
976 repo.dirstate.forget(f)
976 repo.dirstate.forget(f)
977 repo.dirstate.setparents(qp, revlog.nullid)
977 repo.dirstate.setparents(qp, revlog.nullid)
978 del self.applied[start:end]
978 del self.applied[start:end]
979 self.strip(repo, rev, update=False, backup='strip')
979 self.strip(repo, rev, update=False, backup='strip')
980 if len(self.applied):
980 if len(self.applied):
981 self.ui.write(_("Now at: %s\n") % self.applied[-1].name)
981 self.ui.write(_("Now at: %s\n") % self.applied[-1].name)
982 else:
982 else:
983 self.ui.write(_("Patch queue now empty\n"))
983 self.ui.write(_("Patch queue now empty\n"))
984 finally:
984 finally:
985 del wlock
985 del wlock
986
986
987 def diff(self, repo, pats, opts):
987 def diff(self, repo, pats, opts):
988 top = self.check_toppatch(repo)
988 top = self.check_toppatch(repo)
989 if not top:
989 if not top:
990 self.ui.write(_("No patches applied\n"))
990 self.ui.write(_("No patches applied\n"))
991 return
991 return
992 qp = self.qparents(repo, top)
992 qp = self.qparents(repo, top)
993 self._diffopts = patch.diffopts(self.ui, opts)
993 self._diffopts = patch.diffopts(self.ui, opts)
994 self.printdiff(repo, qp, files=pats, opts=opts)
994 self.printdiff(repo, qp, files=pats, opts=opts)
995
995
996 def refresh(self, repo, pats=None, **opts):
996 def refresh(self, repo, pats=None, **opts):
997 if len(self.applied) == 0:
997 if len(self.applied) == 0:
998 self.ui.write(_("No patches applied\n"))
998 self.ui.write(_("No patches applied\n"))
999 return 1
999 return 1
1000 newdate = opts.get('date')
1000 newdate = opts.get('date')
1001 if newdate:
1001 if newdate:
1002 newdate = '%d %d' % util.parsedate(newdate)
1002 newdate = '%d %d' % util.parsedate(newdate)
1003 wlock = repo.wlock()
1003 wlock = repo.wlock()
1004 try:
1004 try:
1005 self.check_toppatch(repo)
1005 self.check_toppatch(repo)
1006 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1006 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1007 top = revlog.bin(top)
1007 top = revlog.bin(top)
1008 if repo.changelog.heads(top) != [top]:
1008 if repo.changelog.heads(top) != [top]:
1009 raise util.Abort(_("cannot refresh a revision with children"))
1009 raise util.Abort(_("cannot refresh a revision with children"))
1010 cparents = repo.changelog.parents(top)
1010 cparents = repo.changelog.parents(top)
1011 patchparent = self.qparents(repo, top)
1011 patchparent = self.qparents(repo, top)
1012 message, comments, user, date, patchfound = self.readheaders(patchfn)
1012 message, comments, user, date, patchfound = self.readheaders(patchfn)
1013
1013
1014 patchf = self.opener(patchfn, 'r+')
1014 patchf = self.opener(patchfn, 'r+')
1015
1015
1016 # if the patch was a git patch, refresh it as a git patch
1016 # if the patch was a git patch, refresh it as a git patch
1017 for line in patchf:
1017 for line in patchf:
1018 if line.startswith('diff --git'):
1018 if line.startswith('diff --git'):
1019 self.diffopts().git = True
1019 self.diffopts().git = True
1020 break
1020 break
1021
1021
1022 msg = opts.get('msg', '').rstrip()
1022 msg = opts.get('msg', '').rstrip()
1023 if msg and comments:
1023 if msg and comments:
1024 # Remove existing message, keeping the rest of the comments
1024 # Remove existing message, keeping the rest of the comments
1025 # fields.
1025 # fields.
1026 # If comments contains 'subject: ', message will prepend
1026 # If comments contains 'subject: ', message will prepend
1027 # the field and a blank line.
1027 # the field and a blank line.
1028 if message:
1028 if message:
1029 subj = 'subject: ' + message[0].lower()
1029 subj = 'subject: ' + message[0].lower()
1030 for i in xrange(len(comments)):
1030 for i in xrange(len(comments)):
1031 if subj == comments[i].lower():
1031 if subj == comments[i].lower():
1032 del comments[i]
1032 del comments[i]
1033 message = message[2:]
1033 message = message[2:]
1034 break
1034 break
1035 ci = 0
1035 ci = 0
1036 for mi in xrange(len(message)):
1036 for mi in xrange(len(message)):
1037 while message[mi] != comments[ci]:
1037 while message[mi] != comments[ci]:
1038 ci += 1
1038 ci += 1
1039 del comments[ci]
1039 del comments[ci]
1040
1040
1041 def setheaderfield(comments, prefixes, new):
1041 def setheaderfield(comments, prefixes, new):
1042 # Update all references to a field in the patch header.
1042 # Update all references to a field in the patch header.
1043 # If none found, add it email style.
1043 # If none found, add it email style.
1044 res = False
1044 res = False
1045 for prefix in prefixes:
1045 for prefix in prefixes:
1046 for i in xrange(len(comments)):
1046 for i in xrange(len(comments)):
1047 if comments[i].startswith(prefix):
1047 if comments[i].startswith(prefix):
1048 comments[i] = prefix + new
1048 comments[i] = prefix + new
1049 res = True
1049 res = True
1050 break
1050 break
1051 return res
1051 return res
1052
1052
1053 newuser = opts.get('user')
1053 newuser = opts.get('user')
1054 if newuser:
1054 if newuser:
1055 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1055 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1056 try:
1056 try:
1057 patchheaderat = comments.index('# HG changeset patch')
1057 patchheaderat = comments.index('# HG changeset patch')
1058 comments.insert(patchheaderat + 1,'# User ' + newuser)
1058 comments.insert(patchheaderat + 1,'# User ' + newuser)
1059 except ValueError:
1059 except ValueError:
1060 comments = ['From: ' + newuser, ''] + comments
1060 comments = ['From: ' + newuser, ''] + comments
1061 user = newuser
1061 user = newuser
1062
1062
1063 if newdate:
1063 if newdate:
1064 if setheaderfield(comments, ['# Date '], newdate):
1064 if setheaderfield(comments, ['# Date '], newdate):
1065 date = newdate
1065 date = newdate
1066
1066
1067 if msg:
1067 if msg:
1068 comments.append(msg)
1068 comments.append(msg)
1069
1069
1070 patchf.seek(0)
1070 patchf.seek(0)
1071 patchf.truncate()
1071 patchf.truncate()
1072
1072
1073 if comments:
1073 if comments:
1074 comments = "\n".join(comments) + '\n\n'
1074 comments = "\n".join(comments) + '\n\n'
1075 patchf.write(comments)
1075 patchf.write(comments)
1076
1076
1077 if opts.get('git'):
1077 if opts.get('git'):
1078 self.diffopts().git = True
1078 self.diffopts().git = True
1079 tip = repo.changelog.tip()
1079 tip = repo.changelog.tip()
1080 if top == tip:
1080 if top == tip:
1081 # if the top of our patch queue is also the tip, there is an
1081 # if the top of our patch queue is also the tip, there is an
1082 # optimization here. We update the dirstate in place and strip
1082 # optimization here. We update the dirstate in place and strip
1083 # off the tip commit. Then just commit the current directory
1083 # off the tip commit. Then just commit the current directory
1084 # tree. We can also send repo.commit the list of files
1084 # tree. We can also send repo.commit the list of files
1085 # changed to speed up the diff
1085 # changed to speed up the diff
1086 #
1086 #
1087 # in short mode, we only diff the files included in the
1087 # in short mode, we only diff the files included in the
1088 # patch already plus specified files
1088 # patch already plus specified files
1089 #
1089 #
1090 # this should really read:
1090 # this should really read:
1091 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1091 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1092 # but we do it backwards to take advantage of manifest/chlog
1092 # but we do it backwards to take advantage of manifest/chlog
1093 # caching against the next repo.status call
1093 # caching against the next repo.status call
1094 #
1094 #
1095 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1095 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1096 changes = repo.changelog.read(tip)
1096 changes = repo.changelog.read(tip)
1097 man = repo.manifest.read(changes[0])
1097 man = repo.manifest.read(changes[0])
1098 aaa = aa[:]
1098 aaa = aa[:]
1099 matchfn = cmdutil.match(repo, pats, opts)
1099 matchfn = cmdutil.match(repo, pats, opts)
1100 if opts.get('short'):
1100 if opts.get('short'):
1101 # if amending a patch, we start with existing
1101 # if amending a patch, we start with existing
1102 # files plus specified files - unfiltered
1102 # files plus specified files - unfiltered
1103 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1103 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1104 # filter with inc/exl options
1104 # filter with inc/exl options
1105 matchfn = cmdutil.match(repo, opts=opts)
1105 matchfn = cmdutil.match(repo, opts=opts)
1106 else:
1106 else:
1107 match = cmdutil.matchall(repo)
1107 match = cmdutil.matchall(repo)
1108 m, a, r, d = repo.status(match=match)[:4]
1108 m, a, r, d = repo.status(match=match)[:4]
1109
1109
1110 # we might end up with files that were added between
1110 # we might end up with files that were added between
1111 # tip and the dirstate parent, but then changed in the
1111 # tip and the dirstate parent, but then changed in the
1112 # local dirstate. in this case, we want them to only
1112 # local dirstate. in this case, we want them to only
1113 # show up in the added section
1113 # show up in the added section
1114 for x in m:
1114 for x in m:
1115 if x not in aa:
1115 if x not in aa:
1116 mm.append(x)
1116 mm.append(x)
1117 # we might end up with files added by the local dirstate that
1117 # we might end up with files added by the local dirstate that
1118 # were deleted by the patch. In this case, they should only
1118 # were deleted by the patch. In this case, they should only
1119 # show up in the changed section.
1119 # show up in the changed section.
1120 for x in a:
1120 for x in a:
1121 if x in dd:
1121 if x in dd:
1122 del dd[dd.index(x)]
1122 del dd[dd.index(x)]
1123 mm.append(x)
1123 mm.append(x)
1124 else:
1124 else:
1125 aa.append(x)
1125 aa.append(x)
1126 # make sure any files deleted in the local dirstate
1126 # make sure any files deleted in the local dirstate
1127 # are not in the add or change column of the patch
1127 # are not in the add or change column of the patch
1128 forget = []
1128 forget = []
1129 for x in d + r:
1129 for x in d + r:
1130 if x in aa:
1130 if x in aa:
1131 del aa[aa.index(x)]
1131 del aa[aa.index(x)]
1132 forget.append(x)
1132 forget.append(x)
1133 continue
1133 continue
1134 elif x in mm:
1134 elif x in mm:
1135 del mm[mm.index(x)]
1135 del mm[mm.index(x)]
1136 dd.append(x)
1136 dd.append(x)
1137
1137
1138 m = util.unique(mm)
1138 m = util.unique(mm)
1139 r = util.unique(dd)
1139 r = util.unique(dd)
1140 a = util.unique(aa)
1140 a = util.unique(aa)
1141 c = [filter(matchfn, l) for l in (m, a, r)]
1141 c = [filter(matchfn, l) for l in (m, a, r)]
1142 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1142 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1143 patch.diff(repo, patchparent, match=match,
1143 patch.diff(repo, patchparent, match=match,
1144 fp=patchf, changes=c, opts=self.diffopts())
1144 fp=patchf, changes=c, opts=self.diffopts())
1145 patchf.close()
1145 patchf.close()
1146
1146
1147 repo.dirstate.setparents(*cparents)
1147 repo.dirstate.setparents(*cparents)
1148 copies = {}
1148 copies = {}
1149 for dst in a:
1149 for dst in a:
1150 src = repo.dirstate.copied(dst)
1150 src = repo.dirstate.copied(dst)
1151 if src is not None:
1151 if src is not None:
1152 copies.setdefault(src, []).append(dst)
1152 copies.setdefault(src, []).append(dst)
1153 repo.dirstate.add(dst)
1153 repo.dirstate.add(dst)
1154 # remember the copies between patchparent and tip
1154 # remember the copies between patchparent and tip
1155 # this may be slow, so don't do it if we're not tracking copies
1155 # this may be slow, so don't do it if we're not tracking copies
1156 if self.diffopts().git:
1156 if self.diffopts().git:
1157 for dst in aaa:
1157 for dst in aaa:
1158 f = repo.file(dst)
1158 f = repo.file(dst)
1159 src = f.renamed(man[dst])
1159 src = f.renamed(man[dst])
1160 if src:
1160 if src:
1161 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1161 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1162 if dst in a:
1162 if dst in a:
1163 copies[src[0]].append(dst)
1163 copies[src[0]].append(dst)
1164 # we can't copy a file created by the patch itself
1164 # we can't copy a file created by the patch itself
1165 if dst in copies:
1165 if dst in copies:
1166 del copies[dst]
1166 del copies[dst]
1167 for src, dsts in copies.iteritems():
1167 for src, dsts in copies.iteritems():
1168 for dst in dsts:
1168 for dst in dsts:
1169 repo.dirstate.copy(src, dst)
1169 repo.dirstate.copy(src, dst)
1170 for f in r:
1170 for f in r:
1171 repo.dirstate.remove(f)
1171 repo.dirstate.remove(f)
1172 # if the patch excludes a modified file, mark that
1172 # if the patch excludes a modified file, mark that
1173 # file with mtime=0 so status can see it.
1173 # file with mtime=0 so status can see it.
1174 mm = []
1174 mm = []
1175 for i in xrange(len(m)-1, -1, -1):
1175 for i in xrange(len(m)-1, -1, -1):
1176 if not matchfn(m[i]):
1176 if not matchfn(m[i]):
1177 mm.append(m[i])
1177 mm.append(m[i])
1178 del m[i]
1178 del m[i]
1179 for f in m:
1179 for f in m:
1180 repo.dirstate.normal(f)
1180 repo.dirstate.normal(f)
1181 for f in mm:
1181 for f in mm:
1182 repo.dirstate.normallookup(f)
1182 repo.dirstate.normallookup(f)
1183 for f in forget:
1183 for f in forget:
1184 repo.dirstate.forget(f)
1184 repo.dirstate.forget(f)
1185
1185
1186 if not msg:
1186 if not msg:
1187 if not message:
1187 if not message:
1188 message = "[mq]: %s\n" % patchfn
1188 message = "[mq]: %s\n" % patchfn
1189 else:
1189 else:
1190 message = "\n".join(message)
1190 message = "\n".join(message)
1191 else:
1191 else:
1192 message = msg
1192 message = msg
1193
1193
1194 if not user:
1194 if not user:
1195 user = changes[1]
1195 user = changes[1]
1196
1196
1197 self.applied.pop()
1197 self.applied.pop()
1198 self.applied_dirty = 1
1198 self.applied_dirty = 1
1199 self.strip(repo, top, update=False,
1199 self.strip(repo, top, update=False,
1200 backup='strip')
1200 backup='strip')
1201 n = repo.commit(match.files(), message, user, date, match=match,
1201 n = repo.commit(match.files(), message, user, date, match=match,
1202 force=1)
1202 force=1)
1203 self.applied.append(statusentry(revlog.hex(n), patchfn))
1203 self.applied.append(statusentry(revlog.hex(n), patchfn))
1204 self.removeundo(repo)
1204 self.removeundo(repo)
1205 else:
1205 else:
1206 self.printdiff(repo, patchparent, fp=patchf)
1206 self.printdiff(repo, patchparent, fp=patchf)
1207 patchf.close()
1207 patchf.close()
1208 added = repo.status()[1]
1208 added = repo.status()[1]
1209 for a in added:
1209 for a in added:
1210 f = repo.wjoin(a)
1210 f = repo.wjoin(a)
1211 try:
1211 try:
1212 os.unlink(f)
1212 os.unlink(f)
1213 except OSError, e:
1213 except OSError, e:
1214 if e.errno != errno.ENOENT:
1214 if e.errno != errno.ENOENT:
1215 raise
1215 raise
1216 try: os.removedirs(os.path.dirname(f))
1216 try: os.removedirs(os.path.dirname(f))
1217 except: pass
1217 except: pass
1218 # forget the file copies in the dirstate
1218 # forget the file copies in the dirstate
1219 # push should readd the files later on
1219 # push should readd the files later on
1220 repo.dirstate.forget(a)
1220 repo.dirstate.forget(a)
1221 self.pop(repo, force=True)
1221 self.pop(repo, force=True)
1222 self.push(repo, force=True)
1222 self.push(repo, force=True)
1223 finally:
1223 finally:
1224 del wlock
1224 del wlock
1225
1225
1226 def init(self, repo, create=False):
1226 def init(self, repo, create=False):
1227 if not create and os.path.isdir(self.path):
1227 if not create and os.path.isdir(self.path):
1228 raise util.Abort(_("patch queue directory already exists"))
1228 raise util.Abort(_("patch queue directory already exists"))
1229 try:
1229 try:
1230 os.mkdir(self.path)
1230 os.mkdir(self.path)
1231 except OSError, inst:
1231 except OSError, inst:
1232 if inst.errno != errno.EEXIST or not create:
1232 if inst.errno != errno.EEXIST or not create:
1233 raise
1233 raise
1234 if create:
1234 if create:
1235 return self.qrepo(create=True)
1235 return self.qrepo(create=True)
1236
1236
1237 def unapplied(self, repo, patch=None):
1237 def unapplied(self, repo, patch=None):
1238 if patch and patch not in self.series:
1238 if patch and patch not in self.series:
1239 raise util.Abort(_("patch %s is not in series file") % patch)
1239 raise util.Abort(_("patch %s is not in series file") % patch)
1240 if not patch:
1240 if not patch:
1241 start = self.series_end()
1241 start = self.series_end()
1242 else:
1242 else:
1243 start = self.series.index(patch) + 1
1243 start = self.series.index(patch) + 1
1244 unapplied = []
1244 unapplied = []
1245 for i in xrange(start, len(self.series)):
1245 for i in xrange(start, len(self.series)):
1246 pushable, reason = self.pushable(i)
1246 pushable, reason = self.pushable(i)
1247 if pushable:
1247 if pushable:
1248 unapplied.append((i, self.series[i]))
1248 unapplied.append((i, self.series[i]))
1249 self.explain_pushable(i)
1249 self.explain_pushable(i)
1250 return unapplied
1250 return unapplied
1251
1251
1252 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1252 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1253 summary=False):
1253 summary=False):
1254 def displayname(patchname):
1254 def displayname(patchname):
1255 if summary:
1255 if summary:
1256 msg = self.readheaders(patchname)[0]
1256 msg = self.readheaders(patchname)[0]
1257 msg = msg and ': ' + msg[0] or ': '
1257 msg = msg and ': ' + msg[0] or ': '
1258 else:
1258 else:
1259 msg = ''
1259 msg = ''
1260 return '%s%s' % (patchname, msg)
1260 return '%s%s' % (patchname, msg)
1261
1261
1262 applied = dict.fromkeys([p.name for p in self.applied])
1262 applied = dict.fromkeys([p.name for p in self.applied])
1263 if length is None:
1263 if length is None:
1264 length = len(self.series) - start
1264 length = len(self.series) - start
1265 if not missing:
1265 if not missing:
1266 for i in xrange(start, start+length):
1266 for i in xrange(start, start+length):
1267 patch = self.series[i]
1267 patch = self.series[i]
1268 if patch in applied:
1268 if patch in applied:
1269 stat = 'A'
1269 stat = 'A'
1270 elif self.pushable(i)[0]:
1270 elif self.pushable(i)[0]:
1271 stat = 'U'
1271 stat = 'U'
1272 else:
1272 else:
1273 stat = 'G'
1273 stat = 'G'
1274 pfx = ''
1274 pfx = ''
1275 if self.ui.verbose:
1275 if self.ui.verbose:
1276 pfx = '%d %s ' % (i, stat)
1276 pfx = '%d %s ' % (i, stat)
1277 elif status and status != stat:
1277 elif status and status != stat:
1278 continue
1278 continue
1279 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1279 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1280 else:
1280 else:
1281 msng_list = []
1281 msng_list = []
1282 for root, dirs, files in os.walk(self.path):
1282 for root, dirs, files in os.walk(self.path):
1283 d = root[len(self.path) + 1:]
1283 d = root[len(self.path) + 1:]
1284 for f in files:
1284 for f in files:
1285 fl = os.path.join(d, f)
1285 fl = os.path.join(d, f)
1286 if (fl not in self.series and
1286 if (fl not in self.series and
1287 fl not in (self.status_path, self.series_path,
1287 fl not in (self.status_path, self.series_path,
1288 self.guards_path)
1288 self.guards_path)
1289 and not fl.startswith('.')):
1289 and not fl.startswith('.')):
1290 msng_list.append(fl)
1290 msng_list.append(fl)
1291 for x in util.sort(msng_list):
1291 for x in util.sort(msng_list):
1292 pfx = self.ui.verbose and ('D ') or ''
1292 pfx = self.ui.verbose and ('D ') or ''
1293 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1293 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1294
1294
1295 def issaveline(self, l):
1295 def issaveline(self, l):
1296 if l.name == '.hg.patches.save.line':
1296 if l.name == '.hg.patches.save.line':
1297 return True
1297 return True
1298
1298
1299 def qrepo(self, create=False):
1299 def qrepo(self, create=False):
1300 if create or os.path.isdir(self.join(".hg")):
1300 if create or os.path.isdir(self.join(".hg")):
1301 return hg.repository(self.ui, path=self.path, create=create)
1301 return hg.repository(self.ui, path=self.path, create=create)
1302
1302
1303 def restore(self, repo, rev, delete=None, qupdate=None):
1303 def restore(self, repo, rev, delete=None, qupdate=None):
1304 c = repo.changelog.read(rev)
1304 c = repo.changelog.read(rev)
1305 desc = c[4].strip()
1305 desc = c[4].strip()
1306 lines = desc.splitlines()
1306 lines = desc.splitlines()
1307 i = 0
1307 i = 0
1308 datastart = None
1308 datastart = None
1309 series = []
1309 series = []
1310 applied = []
1310 applied = []
1311 qpp = None
1311 qpp = None
1312 for i in xrange(0, len(lines)):
1312 for i in xrange(0, len(lines)):
1313 if lines[i] == 'Patch Data:':
1313 if lines[i] == 'Patch Data:':
1314 datastart = i + 1
1314 datastart = i + 1
1315 elif lines[i].startswith('Dirstate:'):
1315 elif lines[i].startswith('Dirstate:'):
1316 l = lines[i].rstrip()
1316 l = lines[i].rstrip()
1317 l = l[10:].split(' ')
1317 l = l[10:].split(' ')
1318 qpp = [ bin(x) for x in l ]
1318 qpp = [ bin(x) for x in l ]
1319 elif datastart != None:
1319 elif datastart != None:
1320 l = lines[i].rstrip()
1320 l = lines[i].rstrip()
1321 se = statusentry(l)
1321 se = statusentry(l)
1322 file_ = se.name
1322 file_ = se.name
1323 if se.rev:
1323 if se.rev:
1324 applied.append(se)
1324 applied.append(se)
1325 else:
1325 else:
1326 series.append(file_)
1326 series.append(file_)
1327 if datastart == None:
1327 if datastart == None:
1328 self.ui.warn(_("No saved patch data found\n"))
1328 self.ui.warn(_("No saved patch data found\n"))
1329 return 1
1329 return 1
1330 self.ui.warn(_("restoring status: %s\n") % lines[0])
1330 self.ui.warn(_("restoring status: %s\n") % lines[0])
1331 self.full_series = series
1331 self.full_series = series
1332 self.applied = applied
1332 self.applied = applied
1333 self.parse_series()
1333 self.parse_series()
1334 self.series_dirty = 1
1334 self.series_dirty = 1
1335 self.applied_dirty = 1
1335 self.applied_dirty = 1
1336 heads = repo.changelog.heads()
1336 heads = repo.changelog.heads()
1337 if delete:
1337 if delete:
1338 if rev not in heads:
1338 if rev not in heads:
1339 self.ui.warn(_("save entry has children, leaving it alone\n"))
1339 self.ui.warn(_("save entry has children, leaving it alone\n"))
1340 else:
1340 else:
1341 self.ui.warn(_("removing save entry %s\n") % short(rev))
1341 self.ui.warn(_("removing save entry %s\n") % short(rev))
1342 pp = repo.dirstate.parents()
1342 pp = repo.dirstate.parents()
1343 if rev in pp:
1343 if rev in pp:
1344 update = True
1344 update = True
1345 else:
1345 else:
1346 update = False
1346 update = False
1347 self.strip(repo, rev, update=update, backup='strip')
1347 self.strip(repo, rev, update=update, backup='strip')
1348 if qpp:
1348 if qpp:
1349 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1349 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1350 (short(qpp[0]), short(qpp[1])))
1350 (short(qpp[0]), short(qpp[1])))
1351 if qupdate:
1351 if qupdate:
1352 self.ui.status(_("queue directory updating\n"))
1352 self.ui.status(_("queue directory updating\n"))
1353 r = self.qrepo()
1353 r = self.qrepo()
1354 if not r:
1354 if not r:
1355 self.ui.warn(_("Unable to load queue repository\n"))
1355 self.ui.warn(_("Unable to load queue repository\n"))
1356 return 1
1356 return 1
1357 hg.clean(r, qpp[0])
1357 hg.clean(r, qpp[0])
1358
1358
1359 def save(self, repo, msg=None):
1359 def save(self, repo, msg=None):
1360 if len(self.applied) == 0:
1360 if len(self.applied) == 0:
1361 self.ui.warn(_("save: no patches applied, exiting\n"))
1361 self.ui.warn(_("save: no patches applied, exiting\n"))
1362 return 1
1362 return 1
1363 if self.issaveline(self.applied[-1]):
1363 if self.issaveline(self.applied[-1]):
1364 self.ui.warn(_("status is already saved\n"))
1364 self.ui.warn(_("status is already saved\n"))
1365 return 1
1365 return 1
1366
1366
1367 ar = [ ':' + x for x in self.full_series ]
1367 ar = [ ':' + x for x in self.full_series ]
1368 if not msg:
1368 if not msg:
1369 msg = _("hg patches saved state")
1369 msg = _("hg patches saved state")
1370 else:
1370 else:
1371 msg = "hg patches: " + msg.rstrip('\r\n')
1371 msg = "hg patches: " + msg.rstrip('\r\n')
1372 r = self.qrepo()
1372 r = self.qrepo()
1373 if r:
1373 if r:
1374 pp = r.dirstate.parents()
1374 pp = r.dirstate.parents()
1375 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1375 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1376 msg += "\n\nPatch Data:\n"
1376 msg += "\n\nPatch Data:\n"
1377 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1377 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1378 "\n".join(ar) + '\n' or "")
1378 "\n".join(ar) + '\n' or "")
1379 n = repo.commit(None, text, user=None, force=1)
1379 n = repo.commit(None, text, user=None, force=1)
1380 if not n:
1380 if not n:
1381 self.ui.warn(_("repo commit failed\n"))
1381 self.ui.warn(_("repo commit failed\n"))
1382 return 1
1382 return 1
1383 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1383 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1384 self.applied_dirty = 1
1384 self.applied_dirty = 1
1385 self.removeundo(repo)
1385 self.removeundo(repo)
1386
1386
1387 def full_series_end(self):
1387 def full_series_end(self):
1388 if len(self.applied) > 0:
1388 if len(self.applied) > 0:
1389 p = self.applied[-1].name
1389 p = self.applied[-1].name
1390 end = self.find_series(p)
1390 end = self.find_series(p)
1391 if end == None:
1391 if end == None:
1392 return len(self.full_series)
1392 return len(self.full_series)
1393 return end + 1
1393 return end + 1
1394 return 0
1394 return 0
1395
1395
1396 def series_end(self, all_patches=False):
1396 def series_end(self, all_patches=False):
1397 """If all_patches is False, return the index of the next pushable patch
1397 """If all_patches is False, return the index of the next pushable patch
1398 in the series, or the series length. If all_patches is True, return the
1398 in the series, or the series length. If all_patches is True, return the
1399 index of the first patch past the last applied one.
1399 index of the first patch past the last applied one.
1400 """
1400 """
1401 end = 0
1401 end = 0
1402 def next(start):
1402 def next(start):
1403 if all_patches:
1403 if all_patches:
1404 return start
1404 return start
1405 i = start
1405 i = start
1406 while i < len(self.series):
1406 while i < len(self.series):
1407 p, reason = self.pushable(i)
1407 p, reason = self.pushable(i)
1408 if p:
1408 if p:
1409 break
1409 break
1410 self.explain_pushable(i)
1410 self.explain_pushable(i)
1411 i += 1
1411 i += 1
1412 return i
1412 return i
1413 if len(self.applied) > 0:
1413 if len(self.applied) > 0:
1414 p = self.applied[-1].name
1414 p = self.applied[-1].name
1415 try:
1415 try:
1416 end = self.series.index(p)
1416 end = self.series.index(p)
1417 except ValueError:
1417 except ValueError:
1418 return 0
1418 return 0
1419 return next(end + 1)
1419 return next(end + 1)
1420 return next(end)
1420 return next(end)
1421
1421
1422 def appliedname(self, index):
1422 def appliedname(self, index):
1423 pname = self.applied[index].name
1423 pname = self.applied[index].name
1424 if not self.ui.verbose:
1424 if not self.ui.verbose:
1425 p = pname
1425 p = pname
1426 else:
1426 else:
1427 p = str(self.series.index(pname)) + " " + pname
1427 p = str(self.series.index(pname)) + " " + pname
1428 return p
1428 return p
1429
1429
1430 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1430 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1431 force=None, git=False):
1431 force=None, git=False):
1432 def checkseries(patchname):
1432 def checkseries(patchname):
1433 if patchname in self.series:
1433 if patchname in self.series:
1434 raise util.Abort(_('patch %s is already in the series file')
1434 raise util.Abort(_('patch %s is already in the series file')
1435 % patchname)
1435 % patchname)
1436 def checkfile(patchname):
1436 def checkfile(patchname):
1437 if not force and os.path.exists(self.join(patchname)):
1437 if not force and os.path.exists(self.join(patchname)):
1438 raise util.Abort(_('patch "%s" already exists')
1438 raise util.Abort(_('patch "%s" already exists')
1439 % patchname)
1439 % patchname)
1440
1440
1441 if rev:
1441 if rev:
1442 if files:
1442 if files:
1443 raise util.Abort(_('option "-r" not valid when importing '
1443 raise util.Abort(_('option "-r" not valid when importing '
1444 'files'))
1444 'files'))
1445 rev = cmdutil.revrange(repo, rev)
1445 rev = cmdutil.revrange(repo, rev)
1446 rev.sort(lambda x, y: cmp(y, x))
1446 rev.sort(lambda x, y: cmp(y, x))
1447 if (len(files) > 1 or len(rev) > 1) and patchname:
1447 if (len(files) > 1 or len(rev) > 1) and patchname:
1448 raise util.Abort(_('option "-n" not valid when importing multiple '
1448 raise util.Abort(_('option "-n" not valid when importing multiple '
1449 'patches'))
1449 'patches'))
1450 i = 0
1450 i = 0
1451 added = []
1451 added = []
1452 if rev:
1452 if rev:
1453 # If mq patches are applied, we can only import revisions
1453 # If mq patches are applied, we can only import revisions
1454 # that form a linear path to qbase.
1454 # that form a linear path to qbase.
1455 # Otherwise, they should form a linear path to a head.
1455 # Otherwise, they should form a linear path to a head.
1456 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1456 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1457 if len(heads) > 1:
1457 if len(heads) > 1:
1458 raise util.Abort(_('revision %d is the root of more than one '
1458 raise util.Abort(_('revision %d is the root of more than one '
1459 'branch') % rev[-1])
1459 'branch') % rev[-1])
1460 if self.applied:
1460 if self.applied:
1461 base = revlog.hex(repo.changelog.node(rev[0]))
1461 base = revlog.hex(repo.changelog.node(rev[0]))
1462 if base in [n.rev for n in self.applied]:
1462 if base in [n.rev for n in self.applied]:
1463 raise util.Abort(_('revision %d is already managed')
1463 raise util.Abort(_('revision %d is already managed')
1464 % rev[0])
1464 % rev[0])
1465 if heads != [revlog.bin(self.applied[-1].rev)]:
1465 if heads != [revlog.bin(self.applied[-1].rev)]:
1466 raise util.Abort(_('revision %d is not the parent of '
1466 raise util.Abort(_('revision %d is not the parent of '
1467 'the queue') % rev[0])
1467 'the queue') % rev[0])
1468 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1468 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1469 lastparent = repo.changelog.parentrevs(base)[0]
1469 lastparent = repo.changelog.parentrevs(base)[0]
1470 else:
1470 else:
1471 if heads != [repo.changelog.node(rev[0])]:
1471 if heads != [repo.changelog.node(rev[0])]:
1472 raise util.Abort(_('revision %d has unmanaged children')
1472 raise util.Abort(_('revision %d has unmanaged children')
1473 % rev[0])
1473 % rev[0])
1474 lastparent = None
1474 lastparent = None
1475
1475
1476 if git:
1476 if git:
1477 self.diffopts().git = True
1477 self.diffopts().git = True
1478
1478
1479 for r in rev:
1479 for r in rev:
1480 p1, p2 = repo.changelog.parentrevs(r)
1480 p1, p2 = repo.changelog.parentrevs(r)
1481 n = repo.changelog.node(r)
1481 n = repo.changelog.node(r)
1482 if p2 != revlog.nullrev:
1482 if p2 != revlog.nullrev:
1483 raise util.Abort(_('cannot import merge revision %d') % r)
1483 raise util.Abort(_('cannot import merge revision %d') % r)
1484 if lastparent and lastparent != r:
1484 if lastparent and lastparent != r:
1485 raise util.Abort(_('revision %d is not the parent of %d')
1485 raise util.Abort(_('revision %d is not the parent of %d')
1486 % (r, lastparent))
1486 % (r, lastparent))
1487 lastparent = p1
1487 lastparent = p1
1488
1488
1489 if not patchname:
1489 if not patchname:
1490 patchname = normname('%d.diff' % r)
1490 patchname = normname('%d.diff' % r)
1491 self.check_reserved_name(patchname)
1491 self.check_reserved_name(patchname)
1492 checkseries(patchname)
1492 checkseries(patchname)
1493 checkfile(patchname)
1493 checkfile(patchname)
1494 self.full_series.insert(0, patchname)
1494 self.full_series.insert(0, patchname)
1495
1495
1496 patchf = self.opener(patchname, "w")
1496 patchf = self.opener(patchname, "w")
1497 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1497 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1498 patchf.close()
1498 patchf.close()
1499
1499
1500 se = statusentry(revlog.hex(n), patchname)
1500 se = statusentry(revlog.hex(n), patchname)
1501 self.applied.insert(0, se)
1501 self.applied.insert(0, se)
1502
1502
1503 added.append(patchname)
1503 added.append(patchname)
1504 patchname = None
1504 patchname = None
1505 self.parse_series()
1505 self.parse_series()
1506 self.applied_dirty = 1
1506 self.applied_dirty = 1
1507
1507
1508 for filename in files:
1508 for filename in files:
1509 if existing:
1509 if existing:
1510 if filename == '-':
1510 if filename == '-':
1511 raise util.Abort(_('-e is incompatible with import from -'))
1511 raise util.Abort(_('-e is incompatible with import from -'))
1512 if not patchname:
1512 if not patchname:
1513 patchname = normname(filename)
1513 patchname = normname(filename)
1514 self.check_reserved_name(patchname)
1514 self.check_reserved_name(patchname)
1515 if not os.path.isfile(self.join(patchname)):
1515 if not os.path.isfile(self.join(patchname)):
1516 raise util.Abort(_("patch %s does not exist") % patchname)
1516 raise util.Abort(_("patch %s does not exist") % patchname)
1517 else:
1517 else:
1518 try:
1518 try:
1519 if filename == '-':
1519 if filename == '-':
1520 if not patchname:
1520 if not patchname:
1521 raise util.Abort(_('need --name to import a patch from -'))
1521 raise util.Abort(_('need --name to import a patch from -'))
1522 text = sys.stdin.read()
1522 text = sys.stdin.read()
1523 else:
1523 else:
1524 if os.path.exists(filename):
1524 text = url.open(self.ui, filename).read()
1525 text = file(filename, 'rb').read()
1526 else:
1527 text = urllib.urlopen(filename).read()
1528 except IOError:
1525 except IOError:
1529 raise util.Abort(_("unable to read %s") % filename)
1526 raise util.Abort(_("unable to read %s") % filename)
1530 if not patchname:
1527 if not patchname:
1531 patchname = normname(os.path.basename(filename))
1528 patchname = normname(os.path.basename(filename))
1532 self.check_reserved_name(patchname)
1529 self.check_reserved_name(patchname)
1533 checkfile(patchname)
1530 checkfile(patchname)
1534 patchf = self.opener(patchname, "w")
1531 patchf = self.opener(patchname, "w")
1535 patchf.write(text)
1532 patchf.write(text)
1536 if not force:
1533 if not force:
1537 checkseries(patchname)
1534 checkseries(patchname)
1538 if patchname not in self.series:
1535 if patchname not in self.series:
1539 index = self.full_series_end() + i
1536 index = self.full_series_end() + i
1540 self.full_series[index:index] = [patchname]
1537 self.full_series[index:index] = [patchname]
1541 self.parse_series()
1538 self.parse_series()
1542 self.ui.warn("adding %s to series file\n" % patchname)
1539 self.ui.warn("adding %s to series file\n" % patchname)
1543 i += 1
1540 i += 1
1544 added.append(patchname)
1541 added.append(patchname)
1545 patchname = None
1542 patchname = None
1546 self.series_dirty = 1
1543 self.series_dirty = 1
1547 qrepo = self.qrepo()
1544 qrepo = self.qrepo()
1548 if qrepo:
1545 if qrepo:
1549 qrepo.add(added)
1546 qrepo.add(added)
1550
1547
1551 def delete(ui, repo, *patches, **opts):
1548 def delete(ui, repo, *patches, **opts):
1552 """remove patches from queue
1549 """remove patches from queue
1553
1550
1554 The patches must not be applied, unless they are arguments to
1551 The patches must not be applied, unless they are arguments to
1555 the --rev parameter. At least one patch or revision is required.
1552 the --rev parameter. At least one patch or revision is required.
1556
1553
1557 With --rev, mq will stop managing the named revisions (converting
1554 With --rev, mq will stop managing the named revisions (converting
1558 them to regular mercurial changesets). The qfinish command should be
1555 them to regular mercurial changesets). The qfinish command should be
1559 used as an alternative for qdel -r, as the latter option is deprecated.
1556 used as an alternative for qdel -r, as the latter option is deprecated.
1560
1557
1561 With --keep, the patch files are preserved in the patch directory."""
1558 With --keep, the patch files are preserved in the patch directory."""
1562 q = repo.mq
1559 q = repo.mq
1563 q.delete(repo, patches, opts)
1560 q.delete(repo, patches, opts)
1564 q.save_dirty()
1561 q.save_dirty()
1565 return 0
1562 return 0
1566
1563
1567 def applied(ui, repo, patch=None, **opts):
1564 def applied(ui, repo, patch=None, **opts):
1568 """print the patches already applied"""
1565 """print the patches already applied"""
1569 q = repo.mq
1566 q = repo.mq
1570 if patch:
1567 if patch:
1571 if patch not in q.series:
1568 if patch not in q.series:
1572 raise util.Abort(_("patch %s is not in series file") % patch)
1569 raise util.Abort(_("patch %s is not in series file") % patch)
1573 end = q.series.index(patch) + 1
1570 end = q.series.index(patch) + 1
1574 else:
1571 else:
1575 end = q.series_end(True)
1572 end = q.series_end(True)
1576 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1573 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1577
1574
1578 def unapplied(ui, repo, patch=None, **opts):
1575 def unapplied(ui, repo, patch=None, **opts):
1579 """print the patches not yet applied"""
1576 """print the patches not yet applied"""
1580 q = repo.mq
1577 q = repo.mq
1581 if patch:
1578 if patch:
1582 if patch not in q.series:
1579 if patch not in q.series:
1583 raise util.Abort(_("patch %s is not in series file") % patch)
1580 raise util.Abort(_("patch %s is not in series file") % patch)
1584 start = q.series.index(patch) + 1
1581 start = q.series.index(patch) + 1
1585 else:
1582 else:
1586 start = q.series_end(True)
1583 start = q.series_end(True)
1587 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1584 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1588
1585
1589 def qimport(ui, repo, *filename, **opts):
1586 def qimport(ui, repo, *filename, **opts):
1590 """import a patch
1587 """import a patch
1591
1588
1592 The patch is inserted into the series after the last applied patch.
1589 The patch is inserted into the series after the last applied patch.
1593 If no patches have been applied, qimport prepends the patch
1590 If no patches have been applied, qimport prepends the patch
1594 to the series.
1591 to the series.
1595
1592
1596 The patch will have the same name as its source file unless you
1593 The patch will have the same name as its source file unless you
1597 give it a new one with --name.
1594 give it a new one with --name.
1598
1595
1599 You can register an existing patch inside the patch directory
1596 You can register an existing patch inside the patch directory
1600 with the --existing flag.
1597 with the --existing flag.
1601
1598
1602 With --force, an existing patch of the same name will be overwritten.
1599 With --force, an existing patch of the same name will be overwritten.
1603
1600
1604 An existing changeset may be placed under mq control with --rev
1601 An existing changeset may be placed under mq control with --rev
1605 (e.g. qimport --rev tip -n patch will place tip under mq control).
1602 (e.g. qimport --rev tip -n patch will place tip under mq control).
1606 With --git, patches imported with --rev will use the git diff
1603 With --git, patches imported with --rev will use the git diff
1607 format.
1604 format.
1608 """
1605 """
1609 q = repo.mq
1606 q = repo.mq
1610 q.qimport(repo, filename, patchname=opts['name'],
1607 q.qimport(repo, filename, patchname=opts['name'],
1611 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1608 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1612 git=opts['git'])
1609 git=opts['git'])
1613 q.save_dirty()
1610 q.save_dirty()
1614 return 0
1611 return 0
1615
1612
1616 def init(ui, repo, **opts):
1613 def init(ui, repo, **opts):
1617 """init a new queue repository
1614 """init a new queue repository
1618
1615
1619 The queue repository is unversioned by default. If -c is
1616 The queue repository is unversioned by default. If -c is
1620 specified, qinit will create a separate nested repository
1617 specified, qinit will create a separate nested repository
1621 for patches (qinit -c may also be run later to convert
1618 for patches (qinit -c may also be run later to convert
1622 an unversioned patch repository into a versioned one).
1619 an unversioned patch repository into a versioned one).
1623 You can use qcommit to commit changes to this queue repository."""
1620 You can use qcommit to commit changes to this queue repository."""
1624 q = repo.mq
1621 q = repo.mq
1625 r = q.init(repo, create=opts['create_repo'])
1622 r = q.init(repo, create=opts['create_repo'])
1626 q.save_dirty()
1623 q.save_dirty()
1627 if r:
1624 if r:
1628 if not os.path.exists(r.wjoin('.hgignore')):
1625 if not os.path.exists(r.wjoin('.hgignore')):
1629 fp = r.wopener('.hgignore', 'w')
1626 fp = r.wopener('.hgignore', 'w')
1630 fp.write('^\\.hg\n')
1627 fp.write('^\\.hg\n')
1631 fp.write('^\\.mq\n')
1628 fp.write('^\\.mq\n')
1632 fp.write('syntax: glob\n')
1629 fp.write('syntax: glob\n')
1633 fp.write('status\n')
1630 fp.write('status\n')
1634 fp.write('guards\n')
1631 fp.write('guards\n')
1635 fp.close()
1632 fp.close()
1636 if not os.path.exists(r.wjoin('series')):
1633 if not os.path.exists(r.wjoin('series')):
1637 r.wopener('series', 'w').close()
1634 r.wopener('series', 'w').close()
1638 r.add(['.hgignore', 'series'])
1635 r.add(['.hgignore', 'series'])
1639 commands.add(ui, r)
1636 commands.add(ui, r)
1640 return 0
1637 return 0
1641
1638
1642 def clone(ui, source, dest=None, **opts):
1639 def clone(ui, source, dest=None, **opts):
1643 '''clone main and patch repository at same time
1640 '''clone main and patch repository at same time
1644
1641
1645 If source is local, destination will have no patches applied. If
1642 If source is local, destination will have no patches applied. If
1646 source is remote, this command can not check if patches are
1643 source is remote, this command can not check if patches are
1647 applied in source, so cannot guarantee that patches are not
1644 applied in source, so cannot guarantee that patches are not
1648 applied in destination. If you clone remote repository, be sure
1645 applied in destination. If you clone remote repository, be sure
1649 before that it has no patches applied.
1646 before that it has no patches applied.
1650
1647
1651 Source patch repository is looked for in <src>/.hg/patches by
1648 Source patch repository is looked for in <src>/.hg/patches by
1652 default. Use -p <url> to change.
1649 default. Use -p <url> to change.
1653
1650
1654 The patch directory must be a nested mercurial repository, as
1651 The patch directory must be a nested mercurial repository, as
1655 would be created by qinit -c.
1652 would be created by qinit -c.
1656 '''
1653 '''
1657 def patchdir(repo):
1654 def patchdir(repo):
1658 url = repo.url()
1655 url = repo.url()
1659 if url.endswith('/'):
1656 if url.endswith('/'):
1660 url = url[:-1]
1657 url = url[:-1]
1661 return url + '/.hg/patches'
1658 return url + '/.hg/patches'
1662 cmdutil.setremoteconfig(ui, opts)
1659 cmdutil.setremoteconfig(ui, opts)
1663 if dest is None:
1660 if dest is None:
1664 dest = hg.defaultdest(source)
1661 dest = hg.defaultdest(source)
1665 sr = hg.repository(ui, ui.expandpath(source))
1662 sr = hg.repository(ui, ui.expandpath(source))
1666 patchespath = opts['patches'] or patchdir(sr)
1663 patchespath = opts['patches'] or patchdir(sr)
1667 try:
1664 try:
1668 pr = hg.repository(ui, patchespath)
1665 pr = hg.repository(ui, patchespath)
1669 except RepoError:
1666 except RepoError:
1670 raise util.Abort(_('versioned patch repository not found'
1667 raise util.Abort(_('versioned patch repository not found'
1671 ' (see qinit -c)'))
1668 ' (see qinit -c)'))
1672 qbase, destrev = None, None
1669 qbase, destrev = None, None
1673 if sr.local():
1670 if sr.local():
1674 if sr.mq.applied:
1671 if sr.mq.applied:
1675 qbase = revlog.bin(sr.mq.applied[0].rev)
1672 qbase = revlog.bin(sr.mq.applied[0].rev)
1676 if not hg.islocal(dest):
1673 if not hg.islocal(dest):
1677 heads = dict.fromkeys(sr.heads())
1674 heads = dict.fromkeys(sr.heads())
1678 for h in sr.heads(qbase):
1675 for h in sr.heads(qbase):
1679 del heads[h]
1676 del heads[h]
1680 destrev = heads.keys()
1677 destrev = heads.keys()
1681 destrev.append(sr.changelog.parents(qbase)[0])
1678 destrev.append(sr.changelog.parents(qbase)[0])
1682 elif sr.capable('lookup'):
1679 elif sr.capable('lookup'):
1683 try:
1680 try:
1684 qbase = sr.lookup('qbase')
1681 qbase = sr.lookup('qbase')
1685 except RepoError:
1682 except RepoError:
1686 pass
1683 pass
1687 ui.note(_('cloning main repo\n'))
1684 ui.note(_('cloning main repo\n'))
1688 sr, dr = hg.clone(ui, sr.url(), dest,
1685 sr, dr = hg.clone(ui, sr.url(), dest,
1689 pull=opts['pull'],
1686 pull=opts['pull'],
1690 rev=destrev,
1687 rev=destrev,
1691 update=False,
1688 update=False,
1692 stream=opts['uncompressed'])
1689 stream=opts['uncompressed'])
1693 ui.note(_('cloning patch repo\n'))
1690 ui.note(_('cloning patch repo\n'))
1694 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1691 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1695 pull=opts['pull'], update=not opts['noupdate'],
1692 pull=opts['pull'], update=not opts['noupdate'],
1696 stream=opts['uncompressed'])
1693 stream=opts['uncompressed'])
1697 if dr.local():
1694 if dr.local():
1698 if qbase:
1695 if qbase:
1699 ui.note(_('stripping applied patches from destination repo\n'))
1696 ui.note(_('stripping applied patches from destination repo\n'))
1700 dr.mq.strip(dr, qbase, update=False, backup=None)
1697 dr.mq.strip(dr, qbase, update=False, backup=None)
1701 if not opts['noupdate']:
1698 if not opts['noupdate']:
1702 ui.note(_('updating destination repo\n'))
1699 ui.note(_('updating destination repo\n'))
1703 hg.update(dr, dr.changelog.tip())
1700 hg.update(dr, dr.changelog.tip())
1704
1701
1705 def commit(ui, repo, *pats, **opts):
1702 def commit(ui, repo, *pats, **opts):
1706 """commit changes in the queue repository"""
1703 """commit changes in the queue repository"""
1707 q = repo.mq
1704 q = repo.mq
1708 r = q.qrepo()
1705 r = q.qrepo()
1709 if not r: raise util.Abort('no queue repository')
1706 if not r: raise util.Abort('no queue repository')
1710 commands.commit(r.ui, r, *pats, **opts)
1707 commands.commit(r.ui, r, *pats, **opts)
1711
1708
1712 def series(ui, repo, **opts):
1709 def series(ui, repo, **opts):
1713 """print the entire series file"""
1710 """print the entire series file"""
1714 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1711 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1715 return 0
1712 return 0
1716
1713
1717 def top(ui, repo, **opts):
1714 def top(ui, repo, **opts):
1718 """print the name of the current patch"""
1715 """print the name of the current patch"""
1719 q = repo.mq
1716 q = repo.mq
1720 t = q.applied and q.series_end(True) or 0
1717 t = q.applied and q.series_end(True) or 0
1721 if t:
1718 if t:
1722 return q.qseries(repo, start=t-1, length=1, status='A',
1719 return q.qseries(repo, start=t-1, length=1, status='A',
1723 summary=opts.get('summary'))
1720 summary=opts.get('summary'))
1724 else:
1721 else:
1725 ui.write("No patches applied\n")
1722 ui.write("No patches applied\n")
1726 return 1
1723 return 1
1727
1724
1728 def next(ui, repo, **opts):
1725 def next(ui, repo, **opts):
1729 """print the name of the next patch"""
1726 """print the name of the next patch"""
1730 q = repo.mq
1727 q = repo.mq
1731 end = q.series_end()
1728 end = q.series_end()
1732 if end == len(q.series):
1729 if end == len(q.series):
1733 ui.write("All patches applied\n")
1730 ui.write("All patches applied\n")
1734 return 1
1731 return 1
1735 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1732 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1736
1733
1737 def prev(ui, repo, **opts):
1734 def prev(ui, repo, **opts):
1738 """print the name of the previous patch"""
1735 """print the name of the previous patch"""
1739 q = repo.mq
1736 q = repo.mq
1740 l = len(q.applied)
1737 l = len(q.applied)
1741 if l == 1:
1738 if l == 1:
1742 ui.write("Only one patch applied\n")
1739 ui.write("Only one patch applied\n")
1743 return 1
1740 return 1
1744 if not l:
1741 if not l:
1745 ui.write("No patches applied\n")
1742 ui.write("No patches applied\n")
1746 return 1
1743 return 1
1747 return q.qseries(repo, start=l-2, length=1, status='A',
1744 return q.qseries(repo, start=l-2, length=1, status='A',
1748 summary=opts.get('summary'))
1745 summary=opts.get('summary'))
1749
1746
1750 def setupheaderopts(ui, opts):
1747 def setupheaderopts(ui, opts):
1751 def do(opt,val):
1748 def do(opt,val):
1752 if not opts[opt] and opts['current' + opt]:
1749 if not opts[opt] and opts['current' + opt]:
1753 opts[opt] = val
1750 opts[opt] = val
1754 do('user', ui.username())
1751 do('user', ui.username())
1755 do('date', "%d %d" % util.makedate())
1752 do('date', "%d %d" % util.makedate())
1756
1753
1757 def new(ui, repo, patch, *args, **opts):
1754 def new(ui, repo, patch, *args, **opts):
1758 """create a new patch
1755 """create a new patch
1759
1756
1760 qnew creates a new patch on top of the currently-applied patch
1757 qnew creates a new patch on top of the currently-applied patch
1761 (if any). It will refuse to run if there are any outstanding
1758 (if any). It will refuse to run if there are any outstanding
1762 changes unless -f is specified, in which case the patch will
1759 changes unless -f is specified, in which case the patch will
1763 be initialised with them. You may also use -I, -X, and/or a list of
1760 be initialised with them. You may also use -I, -X, and/or a list of
1764 files after the patch name to add only changes to matching files
1761 files after the patch name to add only changes to matching files
1765 to the new patch, leaving the rest as uncommitted modifications.
1762 to the new patch, leaving the rest as uncommitted modifications.
1766
1763
1767 -e, -m or -l set the patch header as well as the commit message.
1764 -e, -m or -l set the patch header as well as the commit message.
1768 If none is specified, the patch header is empty and the
1765 If none is specified, the patch header is empty and the
1769 commit message is '[mq]: PATCH'"""
1766 commit message is '[mq]: PATCH'"""
1770 msg = cmdutil.logmessage(opts)
1767 msg = cmdutil.logmessage(opts)
1771 def getmsg(): return ui.edit(msg, ui.username())
1768 def getmsg(): return ui.edit(msg, ui.username())
1772 q = repo.mq
1769 q = repo.mq
1773 opts['msg'] = msg
1770 opts['msg'] = msg
1774 if opts.get('edit'):
1771 if opts.get('edit'):
1775 opts['msg'] = getmsg
1772 opts['msg'] = getmsg
1776 else:
1773 else:
1777 opts['msg'] = msg
1774 opts['msg'] = msg
1778 setupheaderopts(ui, opts)
1775 setupheaderopts(ui, opts)
1779 q.new(repo, patch, *args, **opts)
1776 q.new(repo, patch, *args, **opts)
1780 q.save_dirty()
1777 q.save_dirty()
1781 return 0
1778 return 0
1782
1779
1783 def refresh(ui, repo, *pats, **opts):
1780 def refresh(ui, repo, *pats, **opts):
1784 """update the current patch
1781 """update the current patch
1785
1782
1786 If any file patterns are provided, the refreshed patch will contain only
1783 If any file patterns are provided, the refreshed patch will contain only
1787 the modifications that match those patterns; the remaining modifications
1784 the modifications that match those patterns; the remaining modifications
1788 will remain in the working directory.
1785 will remain in the working directory.
1789
1786
1790 If --short is specified, files currently included in the patch will
1787 If --short is specified, files currently included in the patch will
1791 be refreshed just like matched files and remain in the patch.
1788 be refreshed just like matched files and remain in the patch.
1792
1789
1793 hg add/remove/copy/rename work as usual, though you might want to use
1790 hg add/remove/copy/rename work as usual, though you might want to use
1794 git-style patches (--git or [diff] git=1) to track copies and renames.
1791 git-style patches (--git or [diff] git=1) to track copies and renames.
1795 """
1792 """
1796 q = repo.mq
1793 q = repo.mq
1797 message = cmdutil.logmessage(opts)
1794 message = cmdutil.logmessage(opts)
1798 if opts['edit']:
1795 if opts['edit']:
1799 if not q.applied:
1796 if not q.applied:
1800 ui.write(_("No patches applied\n"))
1797 ui.write(_("No patches applied\n"))
1801 return 1
1798 return 1
1802 if message:
1799 if message:
1803 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1800 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1804 patch = q.applied[-1].name
1801 patch = q.applied[-1].name
1805 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1802 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1806 message = ui.edit('\n'.join(message), user or ui.username())
1803 message = ui.edit('\n'.join(message), user or ui.username())
1807 setupheaderopts(ui, opts)
1804 setupheaderopts(ui, opts)
1808 ret = q.refresh(repo, pats, msg=message, **opts)
1805 ret = q.refresh(repo, pats, msg=message, **opts)
1809 q.save_dirty()
1806 q.save_dirty()
1810 return ret
1807 return ret
1811
1808
1812 def diff(ui, repo, *pats, **opts):
1809 def diff(ui, repo, *pats, **opts):
1813 """diff of the current patch and subsequent modifications
1810 """diff of the current patch and subsequent modifications
1814
1811
1815 Shows a diff which includes the current patch as well as any changes which
1812 Shows a diff which includes the current patch as well as any changes which
1816 have been made in the working directory since the last refresh (thus
1813 have been made in the working directory since the last refresh (thus
1817 showing what the current patch would become after a qrefresh).
1814 showing what the current patch would become after a qrefresh).
1818
1815
1819 Use 'hg diff' if you only want to see the changes made since the last
1816 Use 'hg diff' if you only want to see the changes made since the last
1820 qrefresh, or 'hg export qtip' if you want to see changes made by the
1817 qrefresh, or 'hg export qtip' if you want to see changes made by the
1821 current patch without including changes made since the qrefresh.
1818 current patch without including changes made since the qrefresh.
1822 """
1819 """
1823 repo.mq.diff(repo, pats, opts)
1820 repo.mq.diff(repo, pats, opts)
1824 return 0
1821 return 0
1825
1822
1826 def fold(ui, repo, *files, **opts):
1823 def fold(ui, repo, *files, **opts):
1827 """fold the named patches into the current patch
1824 """fold the named patches into the current patch
1828
1825
1829 Patches must not yet be applied. Each patch will be successively
1826 Patches must not yet be applied. Each patch will be successively
1830 applied to the current patch in the order given. If all the
1827 applied to the current patch in the order given. If all the
1831 patches apply successfully, the current patch will be refreshed
1828 patches apply successfully, the current patch will be refreshed
1832 with the new cumulative patch, and the folded patches will
1829 with the new cumulative patch, and the folded patches will
1833 be deleted. With -k/--keep, the folded patch files will not
1830 be deleted. With -k/--keep, the folded patch files will not
1834 be removed afterwards.
1831 be removed afterwards.
1835
1832
1836 The header for each folded patch will be concatenated with
1833 The header for each folded patch will be concatenated with
1837 the current patch header, separated by a line of '* * *'."""
1834 the current patch header, separated by a line of '* * *'."""
1838
1835
1839 q = repo.mq
1836 q = repo.mq
1840
1837
1841 if not files:
1838 if not files:
1842 raise util.Abort(_('qfold requires at least one patch name'))
1839 raise util.Abort(_('qfold requires at least one patch name'))
1843 if not q.check_toppatch(repo):
1840 if not q.check_toppatch(repo):
1844 raise util.Abort(_('No patches applied'))
1841 raise util.Abort(_('No patches applied'))
1845
1842
1846 message = cmdutil.logmessage(opts)
1843 message = cmdutil.logmessage(opts)
1847 if opts['edit']:
1844 if opts['edit']:
1848 if message:
1845 if message:
1849 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1846 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1850
1847
1851 parent = q.lookup('qtip')
1848 parent = q.lookup('qtip')
1852 patches = []
1849 patches = []
1853 messages = []
1850 messages = []
1854 for f in files:
1851 for f in files:
1855 p = q.lookup(f)
1852 p = q.lookup(f)
1856 if p in patches or p == parent:
1853 if p in patches or p == parent:
1857 ui.warn(_('Skipping already folded patch %s') % p)
1854 ui.warn(_('Skipping already folded patch %s') % p)
1858 if q.isapplied(p):
1855 if q.isapplied(p):
1859 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1856 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1860 patches.append(p)
1857 patches.append(p)
1861
1858
1862 for p in patches:
1859 for p in patches:
1863 if not message:
1860 if not message:
1864 messages.append(q.readheaders(p)[0])
1861 messages.append(q.readheaders(p)[0])
1865 pf = q.join(p)
1862 pf = q.join(p)
1866 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1863 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1867 if not patchsuccess:
1864 if not patchsuccess:
1868 raise util.Abort(_('Error folding patch %s') % p)
1865 raise util.Abort(_('Error folding patch %s') % p)
1869 patch.updatedir(ui, repo, files)
1866 patch.updatedir(ui, repo, files)
1870
1867
1871 if not message:
1868 if not message:
1872 message, comments, user = q.readheaders(parent)[0:3]
1869 message, comments, user = q.readheaders(parent)[0:3]
1873 for msg in messages:
1870 for msg in messages:
1874 message.append('* * *')
1871 message.append('* * *')
1875 message.extend(msg)
1872 message.extend(msg)
1876 message = '\n'.join(message)
1873 message = '\n'.join(message)
1877
1874
1878 if opts['edit']:
1875 if opts['edit']:
1879 message = ui.edit(message, user or ui.username())
1876 message = ui.edit(message, user or ui.username())
1880
1877
1881 q.refresh(repo, msg=message)
1878 q.refresh(repo, msg=message)
1882 q.delete(repo, patches, opts)
1879 q.delete(repo, patches, opts)
1883 q.save_dirty()
1880 q.save_dirty()
1884
1881
1885 def goto(ui, repo, patch, **opts):
1882 def goto(ui, repo, patch, **opts):
1886 '''push or pop patches until named patch is at top of stack'''
1883 '''push or pop patches until named patch is at top of stack'''
1887 q = repo.mq
1884 q = repo.mq
1888 patch = q.lookup(patch)
1885 patch = q.lookup(patch)
1889 if q.isapplied(patch):
1886 if q.isapplied(patch):
1890 ret = q.pop(repo, patch, force=opts['force'])
1887 ret = q.pop(repo, patch, force=opts['force'])
1891 else:
1888 else:
1892 ret = q.push(repo, patch, force=opts['force'])
1889 ret = q.push(repo, patch, force=opts['force'])
1893 q.save_dirty()
1890 q.save_dirty()
1894 return ret
1891 return ret
1895
1892
1896 def guard(ui, repo, *args, **opts):
1893 def guard(ui, repo, *args, **opts):
1897 '''set or print guards for a patch
1894 '''set or print guards for a patch
1898
1895
1899 Guards control whether a patch can be pushed. A patch with no
1896 Guards control whether a patch can be pushed. A patch with no
1900 guards is always pushed. A patch with a positive guard ("+foo") is
1897 guards is always pushed. A patch with a positive guard ("+foo") is
1901 pushed only if the qselect command has activated it. A patch with
1898 pushed only if the qselect command has activated it. A patch with
1902 a negative guard ("-foo") is never pushed if the qselect command
1899 a negative guard ("-foo") is never pushed if the qselect command
1903 has activated it.
1900 has activated it.
1904
1901
1905 With no arguments, print the currently active guards.
1902 With no arguments, print the currently active guards.
1906 With arguments, set guards for the named patch.
1903 With arguments, set guards for the named patch.
1907
1904
1908 To set a negative guard "-foo" on topmost patch ("--" is needed so
1905 To set a negative guard "-foo" on topmost patch ("--" is needed so
1909 hg will not interpret "-foo" as an option):
1906 hg will not interpret "-foo" as an option):
1910 hg qguard -- -foo
1907 hg qguard -- -foo
1911
1908
1912 To set guards on another patch:
1909 To set guards on another patch:
1913 hg qguard other.patch +2.6.17 -stable
1910 hg qguard other.patch +2.6.17 -stable
1914 '''
1911 '''
1915 def status(idx):
1912 def status(idx):
1916 guards = q.series_guards[idx] or ['unguarded']
1913 guards = q.series_guards[idx] or ['unguarded']
1917 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1914 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1918 q = repo.mq
1915 q = repo.mq
1919 patch = None
1916 patch = None
1920 args = list(args)
1917 args = list(args)
1921 if opts['list']:
1918 if opts['list']:
1922 if args or opts['none']:
1919 if args or opts['none']:
1923 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1920 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1924 for i in xrange(len(q.series)):
1921 for i in xrange(len(q.series)):
1925 status(i)
1922 status(i)
1926 return
1923 return
1927 if not args or args[0][0:1] in '-+':
1924 if not args or args[0][0:1] in '-+':
1928 if not q.applied:
1925 if not q.applied:
1929 raise util.Abort(_('no patches applied'))
1926 raise util.Abort(_('no patches applied'))
1930 patch = q.applied[-1].name
1927 patch = q.applied[-1].name
1931 if patch is None and args[0][0:1] not in '-+':
1928 if patch is None and args[0][0:1] not in '-+':
1932 patch = args.pop(0)
1929 patch = args.pop(0)
1933 if patch is None:
1930 if patch is None:
1934 raise util.Abort(_('no patch to work with'))
1931 raise util.Abort(_('no patch to work with'))
1935 if args or opts['none']:
1932 if args or opts['none']:
1936 idx = q.find_series(patch)
1933 idx = q.find_series(patch)
1937 if idx is None:
1934 if idx is None:
1938 raise util.Abort(_('no patch named %s') % patch)
1935 raise util.Abort(_('no patch named %s') % patch)
1939 q.set_guards(idx, args)
1936 q.set_guards(idx, args)
1940 q.save_dirty()
1937 q.save_dirty()
1941 else:
1938 else:
1942 status(q.series.index(q.lookup(patch)))
1939 status(q.series.index(q.lookup(patch)))
1943
1940
1944 def header(ui, repo, patch=None):
1941 def header(ui, repo, patch=None):
1945 """Print the header of the topmost or specified patch"""
1942 """Print the header of the topmost or specified patch"""
1946 q = repo.mq
1943 q = repo.mq
1947
1944
1948 if patch:
1945 if patch:
1949 patch = q.lookup(patch)
1946 patch = q.lookup(patch)
1950 else:
1947 else:
1951 if not q.applied:
1948 if not q.applied:
1952 ui.write('No patches applied\n')
1949 ui.write('No patches applied\n')
1953 return 1
1950 return 1
1954 patch = q.lookup('qtip')
1951 patch = q.lookup('qtip')
1955 message = repo.mq.readheaders(patch)[0]
1952 message = repo.mq.readheaders(patch)[0]
1956
1953
1957 ui.write('\n'.join(message) + '\n')
1954 ui.write('\n'.join(message) + '\n')
1958
1955
1959 def lastsavename(path):
1956 def lastsavename(path):
1960 (directory, base) = os.path.split(path)
1957 (directory, base) = os.path.split(path)
1961 names = os.listdir(directory)
1958 names = os.listdir(directory)
1962 namere = re.compile("%s.([0-9]+)" % base)
1959 namere = re.compile("%s.([0-9]+)" % base)
1963 maxindex = None
1960 maxindex = None
1964 maxname = None
1961 maxname = None
1965 for f in names:
1962 for f in names:
1966 m = namere.match(f)
1963 m = namere.match(f)
1967 if m:
1964 if m:
1968 index = int(m.group(1))
1965 index = int(m.group(1))
1969 if maxindex == None or index > maxindex:
1966 if maxindex == None or index > maxindex:
1970 maxindex = index
1967 maxindex = index
1971 maxname = f
1968 maxname = f
1972 if maxname:
1969 if maxname:
1973 return (os.path.join(directory, maxname), maxindex)
1970 return (os.path.join(directory, maxname), maxindex)
1974 return (None, None)
1971 return (None, None)
1975
1972
1976 def savename(path):
1973 def savename(path):
1977 (last, index) = lastsavename(path)
1974 (last, index) = lastsavename(path)
1978 if last is None:
1975 if last is None:
1979 index = 0
1976 index = 0
1980 newpath = path + ".%d" % (index + 1)
1977 newpath = path + ".%d" % (index + 1)
1981 return newpath
1978 return newpath
1982
1979
1983 def push(ui, repo, patch=None, **opts):
1980 def push(ui, repo, patch=None, **opts):
1984 """push the next patch onto the stack
1981 """push the next patch onto the stack
1985
1982
1986 When --force is applied, all local changes in patched files will be lost.
1983 When --force is applied, all local changes in patched files will be lost.
1987 """
1984 """
1988 q = repo.mq
1985 q = repo.mq
1989 mergeq = None
1986 mergeq = None
1990
1987
1991 if opts['all']:
1988 if opts['all']:
1992 if not q.series:
1989 if not q.series:
1993 ui.warn(_('no patches in series\n'))
1990 ui.warn(_('no patches in series\n'))
1994 return 0
1991 return 0
1995 patch = q.series[-1]
1992 patch = q.series[-1]
1996 if opts['merge']:
1993 if opts['merge']:
1997 if opts['name']:
1994 if opts['name']:
1998 newpath = repo.join(opts['name'])
1995 newpath = repo.join(opts['name'])
1999 else:
1996 else:
2000 newpath, i = lastsavename(q.path)
1997 newpath, i = lastsavename(q.path)
2001 if not newpath:
1998 if not newpath:
2002 ui.warn(_("no saved queues found, please use -n\n"))
1999 ui.warn(_("no saved queues found, please use -n\n"))
2003 return 1
2000 return 1
2004 mergeq = queue(ui, repo.join(""), newpath)
2001 mergeq = queue(ui, repo.join(""), newpath)
2005 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2002 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2006 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2003 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2007 mergeq=mergeq)
2004 mergeq=mergeq)
2008 return ret
2005 return ret
2009
2006
2010 def pop(ui, repo, patch=None, **opts):
2007 def pop(ui, repo, patch=None, **opts):
2011 """pop the current patch off the stack
2008 """pop the current patch off the stack
2012
2009
2013 By default, pops off the top of the patch stack. If given a patch name,
2010 By default, pops off the top of the patch stack. If given a patch name,
2014 keeps popping off patches until the named patch is at the top of the stack.
2011 keeps popping off patches until the named patch is at the top of the stack.
2015 """
2012 """
2016 localupdate = True
2013 localupdate = True
2017 if opts['name']:
2014 if opts['name']:
2018 q = queue(ui, repo.join(""), repo.join(opts['name']))
2015 q = queue(ui, repo.join(""), repo.join(opts['name']))
2019 ui.warn(_('using patch queue: %s\n') % q.path)
2016 ui.warn(_('using patch queue: %s\n') % q.path)
2020 localupdate = False
2017 localupdate = False
2021 else:
2018 else:
2022 q = repo.mq
2019 q = repo.mq
2023 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2020 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2024 all=opts['all'])
2021 all=opts['all'])
2025 q.save_dirty()
2022 q.save_dirty()
2026 return ret
2023 return ret
2027
2024
2028 def rename(ui, repo, patch, name=None, **opts):
2025 def rename(ui, repo, patch, name=None, **opts):
2029 """rename a patch
2026 """rename a patch
2030
2027
2031 With one argument, renames the current patch to PATCH1.
2028 With one argument, renames the current patch to PATCH1.
2032 With two arguments, renames PATCH1 to PATCH2."""
2029 With two arguments, renames PATCH1 to PATCH2."""
2033
2030
2034 q = repo.mq
2031 q = repo.mq
2035
2032
2036 if not name:
2033 if not name:
2037 name = patch
2034 name = patch
2038 patch = None
2035 patch = None
2039
2036
2040 if patch:
2037 if patch:
2041 patch = q.lookup(patch)
2038 patch = q.lookup(patch)
2042 else:
2039 else:
2043 if not q.applied:
2040 if not q.applied:
2044 ui.write(_('No patches applied\n'))
2041 ui.write(_('No patches applied\n'))
2045 return
2042 return
2046 patch = q.lookup('qtip')
2043 patch = q.lookup('qtip')
2047 absdest = q.join(name)
2044 absdest = q.join(name)
2048 if os.path.isdir(absdest):
2045 if os.path.isdir(absdest):
2049 name = normname(os.path.join(name, os.path.basename(patch)))
2046 name = normname(os.path.join(name, os.path.basename(patch)))
2050 absdest = q.join(name)
2047 absdest = q.join(name)
2051 if os.path.exists(absdest):
2048 if os.path.exists(absdest):
2052 raise util.Abort(_('%s already exists') % absdest)
2049 raise util.Abort(_('%s already exists') % absdest)
2053
2050
2054 if name in q.series:
2051 if name in q.series:
2055 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2052 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2056
2053
2057 if ui.verbose:
2054 if ui.verbose:
2058 ui.write('Renaming %s to %s\n' % (patch, name))
2055 ui.write('Renaming %s to %s\n' % (patch, name))
2059 i = q.find_series(patch)
2056 i = q.find_series(patch)
2060 guards = q.guard_re.findall(q.full_series[i])
2057 guards = q.guard_re.findall(q.full_series[i])
2061 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2058 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2062 q.parse_series()
2059 q.parse_series()
2063 q.series_dirty = 1
2060 q.series_dirty = 1
2064
2061
2065 info = q.isapplied(patch)
2062 info = q.isapplied(patch)
2066 if info:
2063 if info:
2067 q.applied[info[0]] = statusentry(info[1], name)
2064 q.applied[info[0]] = statusentry(info[1], name)
2068 q.applied_dirty = 1
2065 q.applied_dirty = 1
2069
2066
2070 util.rename(q.join(patch), absdest)
2067 util.rename(q.join(patch), absdest)
2071 r = q.qrepo()
2068 r = q.qrepo()
2072 if r:
2069 if r:
2073 wlock = r.wlock()
2070 wlock = r.wlock()
2074 try:
2071 try:
2075 if r.dirstate[patch] == 'a':
2072 if r.dirstate[patch] == 'a':
2076 r.dirstate.forget(patch)
2073 r.dirstate.forget(patch)
2077 r.dirstate.add(name)
2074 r.dirstate.add(name)
2078 else:
2075 else:
2079 if r.dirstate[name] == 'r':
2076 if r.dirstate[name] == 'r':
2080 r.undelete([name])
2077 r.undelete([name])
2081 r.copy(patch, name)
2078 r.copy(patch, name)
2082 r.remove([patch], False)
2079 r.remove([patch], False)
2083 finally:
2080 finally:
2084 del wlock
2081 del wlock
2085
2082
2086 q.save_dirty()
2083 q.save_dirty()
2087
2084
2088 def restore(ui, repo, rev, **opts):
2085 def restore(ui, repo, rev, **opts):
2089 """restore the queue state saved by a rev"""
2086 """restore the queue state saved by a rev"""
2090 rev = repo.lookup(rev)
2087 rev = repo.lookup(rev)
2091 q = repo.mq
2088 q = repo.mq
2092 q.restore(repo, rev, delete=opts['delete'],
2089 q.restore(repo, rev, delete=opts['delete'],
2093 qupdate=opts['update'])
2090 qupdate=opts['update'])
2094 q.save_dirty()
2091 q.save_dirty()
2095 return 0
2092 return 0
2096
2093
2097 def save(ui, repo, **opts):
2094 def save(ui, repo, **opts):
2098 """save current queue state"""
2095 """save current queue state"""
2099 q = repo.mq
2096 q = repo.mq
2100 message = cmdutil.logmessage(opts)
2097 message = cmdutil.logmessage(opts)
2101 ret = q.save(repo, msg=message)
2098 ret = q.save(repo, msg=message)
2102 if ret:
2099 if ret:
2103 return ret
2100 return ret
2104 q.save_dirty()
2101 q.save_dirty()
2105 if opts['copy']:
2102 if opts['copy']:
2106 path = q.path
2103 path = q.path
2107 if opts['name']:
2104 if opts['name']:
2108 newpath = os.path.join(q.basepath, opts['name'])
2105 newpath = os.path.join(q.basepath, opts['name'])
2109 if os.path.exists(newpath):
2106 if os.path.exists(newpath):
2110 if not os.path.isdir(newpath):
2107 if not os.path.isdir(newpath):
2111 raise util.Abort(_('destination %s exists and is not '
2108 raise util.Abort(_('destination %s exists and is not '
2112 'a directory') % newpath)
2109 'a directory') % newpath)
2113 if not opts['force']:
2110 if not opts['force']:
2114 raise util.Abort(_('destination %s exists, '
2111 raise util.Abort(_('destination %s exists, '
2115 'use -f to force') % newpath)
2112 'use -f to force') % newpath)
2116 else:
2113 else:
2117 newpath = savename(path)
2114 newpath = savename(path)
2118 ui.warn(_("copy %s to %s\n") % (path, newpath))
2115 ui.warn(_("copy %s to %s\n") % (path, newpath))
2119 util.copyfiles(path, newpath)
2116 util.copyfiles(path, newpath)
2120 if opts['empty']:
2117 if opts['empty']:
2121 try:
2118 try:
2122 os.unlink(q.join(q.status_path))
2119 os.unlink(q.join(q.status_path))
2123 except:
2120 except:
2124 pass
2121 pass
2125 return 0
2122 return 0
2126
2123
2127 def strip(ui, repo, rev, **opts):
2124 def strip(ui, repo, rev, **opts):
2128 """strip a revision and all its descendants from the repository
2125 """strip a revision and all its descendants from the repository
2129
2126
2130 If one of the working dir's parent revisions is stripped, the working
2127 If one of the working dir's parent revisions is stripped, the working
2131 directory will be updated to the parent of the stripped revision.
2128 directory will be updated to the parent of the stripped revision.
2132 """
2129 """
2133 backup = 'all'
2130 backup = 'all'
2134 if opts['backup']:
2131 if opts['backup']:
2135 backup = 'strip'
2132 backup = 'strip'
2136 elif opts['nobackup']:
2133 elif opts['nobackup']:
2137 backup = 'none'
2134 backup = 'none'
2138
2135
2139 rev = repo.lookup(rev)
2136 rev = repo.lookup(rev)
2140 p = repo.dirstate.parents()
2137 p = repo.dirstate.parents()
2141 cl = repo.changelog
2138 cl = repo.changelog
2142 update = True
2139 update = True
2143 if p[0] == revlog.nullid:
2140 if p[0] == revlog.nullid:
2144 update = False
2141 update = False
2145 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2142 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2146 update = False
2143 update = False
2147 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2144 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2148 update = False
2145 update = False
2149
2146
2150 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2147 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2151 return 0
2148 return 0
2152
2149
2153 def select(ui, repo, *args, **opts):
2150 def select(ui, repo, *args, **opts):
2154 '''set or print guarded patches to push
2151 '''set or print guarded patches to push
2155
2152
2156 Use the qguard command to set or print guards on patch, then use
2153 Use the qguard command to set or print guards on patch, then use
2157 qselect to tell mq which guards to use. A patch will be pushed if it
2154 qselect to tell mq which guards to use. A patch will be pushed if it
2158 has no guards or any positive guards match the currently selected guard,
2155 has no guards or any positive guards match the currently selected guard,
2159 but will not be pushed if any negative guards match the current guard.
2156 but will not be pushed if any negative guards match the current guard.
2160 For example:
2157 For example:
2161
2158
2162 qguard foo.patch -stable (negative guard)
2159 qguard foo.patch -stable (negative guard)
2163 qguard bar.patch +stable (positive guard)
2160 qguard bar.patch +stable (positive guard)
2164 qselect stable
2161 qselect stable
2165
2162
2166 This activates the "stable" guard. mq will skip foo.patch (because
2163 This activates the "stable" guard. mq will skip foo.patch (because
2167 it has a negative match) but push bar.patch (because it
2164 it has a negative match) but push bar.patch (because it
2168 has a positive match).
2165 has a positive match).
2169
2166
2170 With no arguments, prints the currently active guards.
2167 With no arguments, prints the currently active guards.
2171 With one argument, sets the active guard.
2168 With one argument, sets the active guard.
2172
2169
2173 Use -n/--none to deactivate guards (no other arguments needed).
2170 Use -n/--none to deactivate guards (no other arguments needed).
2174 When no guards are active, patches with positive guards are skipped
2171 When no guards are active, patches with positive guards are skipped
2175 and patches with negative guards are pushed.
2172 and patches with negative guards are pushed.
2176
2173
2177 qselect can change the guards on applied patches. It does not pop
2174 qselect can change the guards on applied patches. It does not pop
2178 guarded patches by default. Use --pop to pop back to the last applied
2175 guarded patches by default. Use --pop to pop back to the last applied
2179 patch that is not guarded. Use --reapply (which implies --pop) to push
2176 patch that is not guarded. Use --reapply (which implies --pop) to push
2180 back to the current patch afterwards, but skip guarded patches.
2177 back to the current patch afterwards, but skip guarded patches.
2181
2178
2182 Use -s/--series to print a list of all guards in the series file (no
2179 Use -s/--series to print a list of all guards in the series file (no
2183 other arguments needed). Use -v for more information.'''
2180 other arguments needed). Use -v for more information.'''
2184
2181
2185 q = repo.mq
2182 q = repo.mq
2186 guards = q.active()
2183 guards = q.active()
2187 if args or opts['none']:
2184 if args or opts['none']:
2188 old_unapplied = q.unapplied(repo)
2185 old_unapplied = q.unapplied(repo)
2189 old_guarded = [i for i in xrange(len(q.applied)) if
2186 old_guarded = [i for i in xrange(len(q.applied)) if
2190 not q.pushable(i)[0]]
2187 not q.pushable(i)[0]]
2191 q.set_active(args)
2188 q.set_active(args)
2192 q.save_dirty()
2189 q.save_dirty()
2193 if not args:
2190 if not args:
2194 ui.status(_('guards deactivated\n'))
2191 ui.status(_('guards deactivated\n'))
2195 if not opts['pop'] and not opts['reapply']:
2192 if not opts['pop'] and not opts['reapply']:
2196 unapplied = q.unapplied(repo)
2193 unapplied = q.unapplied(repo)
2197 guarded = [i for i in xrange(len(q.applied))
2194 guarded = [i for i in xrange(len(q.applied))
2198 if not q.pushable(i)[0]]
2195 if not q.pushable(i)[0]]
2199 if len(unapplied) != len(old_unapplied):
2196 if len(unapplied) != len(old_unapplied):
2200 ui.status(_('number of unguarded, unapplied patches has '
2197 ui.status(_('number of unguarded, unapplied patches has '
2201 'changed from %d to %d\n') %
2198 'changed from %d to %d\n') %
2202 (len(old_unapplied), len(unapplied)))
2199 (len(old_unapplied), len(unapplied)))
2203 if len(guarded) != len(old_guarded):
2200 if len(guarded) != len(old_guarded):
2204 ui.status(_('number of guarded, applied patches has changed '
2201 ui.status(_('number of guarded, applied patches has changed '
2205 'from %d to %d\n') %
2202 'from %d to %d\n') %
2206 (len(old_guarded), len(guarded)))
2203 (len(old_guarded), len(guarded)))
2207 elif opts['series']:
2204 elif opts['series']:
2208 guards = {}
2205 guards = {}
2209 noguards = 0
2206 noguards = 0
2210 for gs in q.series_guards:
2207 for gs in q.series_guards:
2211 if not gs:
2208 if not gs:
2212 noguards += 1
2209 noguards += 1
2213 for g in gs:
2210 for g in gs:
2214 guards.setdefault(g, 0)
2211 guards.setdefault(g, 0)
2215 guards[g] += 1
2212 guards[g] += 1
2216 if ui.verbose:
2213 if ui.verbose:
2217 guards['NONE'] = noguards
2214 guards['NONE'] = noguards
2218 guards = guards.items()
2215 guards = guards.items()
2219 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2216 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2220 if guards:
2217 if guards:
2221 ui.note(_('guards in series file:\n'))
2218 ui.note(_('guards in series file:\n'))
2222 for guard, count in guards:
2219 for guard, count in guards:
2223 ui.note('%2d ' % count)
2220 ui.note('%2d ' % count)
2224 ui.write(guard, '\n')
2221 ui.write(guard, '\n')
2225 else:
2222 else:
2226 ui.note(_('no guards in series file\n'))
2223 ui.note(_('no guards in series file\n'))
2227 else:
2224 else:
2228 if guards:
2225 if guards:
2229 ui.note(_('active guards:\n'))
2226 ui.note(_('active guards:\n'))
2230 for g in guards:
2227 for g in guards:
2231 ui.write(g, '\n')
2228 ui.write(g, '\n')
2232 else:
2229 else:
2233 ui.write(_('no active guards\n'))
2230 ui.write(_('no active guards\n'))
2234 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2231 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2235 popped = False
2232 popped = False
2236 if opts['pop'] or opts['reapply']:
2233 if opts['pop'] or opts['reapply']:
2237 for i in xrange(len(q.applied)):
2234 for i in xrange(len(q.applied)):
2238 pushable, reason = q.pushable(i)
2235 pushable, reason = q.pushable(i)
2239 if not pushable:
2236 if not pushable:
2240 ui.status(_('popping guarded patches\n'))
2237 ui.status(_('popping guarded patches\n'))
2241 popped = True
2238 popped = True
2242 if i == 0:
2239 if i == 0:
2243 q.pop(repo, all=True)
2240 q.pop(repo, all=True)
2244 else:
2241 else:
2245 q.pop(repo, i-1)
2242 q.pop(repo, i-1)
2246 break
2243 break
2247 if popped:
2244 if popped:
2248 try:
2245 try:
2249 if reapply:
2246 if reapply:
2250 ui.status(_('reapplying unguarded patches\n'))
2247 ui.status(_('reapplying unguarded patches\n'))
2251 q.push(repo, reapply)
2248 q.push(repo, reapply)
2252 finally:
2249 finally:
2253 q.save_dirty()
2250 q.save_dirty()
2254
2251
2255 def finish(ui, repo, *revrange, **opts):
2252 def finish(ui, repo, *revrange, **opts):
2256 """move applied patches into repository history
2253 """move applied patches into repository history
2257
2254
2258 Finishes the specified revisions (corresponding to applied patches) by
2255 Finishes the specified revisions (corresponding to applied patches) by
2259 moving them out of mq control into regular repository history.
2256 moving them out of mq control into regular repository history.
2260
2257
2261 Accepts a revision range or the --applied option. If --applied is
2258 Accepts a revision range or the --applied option. If --applied is
2262 specified, all applied mq revisions are removed from mq control.
2259 specified, all applied mq revisions are removed from mq control.
2263 Otherwise, the given revisions must be at the base of the stack of
2260 Otherwise, the given revisions must be at the base of the stack of
2264 applied patches.
2261 applied patches.
2265
2262
2266 This can be especially useful if your changes have been applied to an
2263 This can be especially useful if your changes have been applied to an
2267 upstream repository, or if you are about to push your changes to upstream.
2264 upstream repository, or if you are about to push your changes to upstream.
2268 """
2265 """
2269 if not opts['applied'] and not revrange:
2266 if not opts['applied'] and not revrange:
2270 raise util.Abort(_('no revisions specified'))
2267 raise util.Abort(_('no revisions specified'))
2271 elif opts['applied']:
2268 elif opts['applied']:
2272 revrange = ('qbase:qtip',) + revrange
2269 revrange = ('qbase:qtip',) + revrange
2273
2270
2274 q = repo.mq
2271 q = repo.mq
2275 if not q.applied:
2272 if not q.applied:
2276 ui.status(_('no patches applied\n'))
2273 ui.status(_('no patches applied\n'))
2277 return 0
2274 return 0
2278
2275
2279 revs = cmdutil.revrange(repo, revrange)
2276 revs = cmdutil.revrange(repo, revrange)
2280 q.finish(repo, revs)
2277 q.finish(repo, revs)
2281 q.save_dirty()
2278 q.save_dirty()
2282 return 0
2279 return 0
2283
2280
2284 def reposetup(ui, repo):
2281 def reposetup(ui, repo):
2285 class mqrepo(repo.__class__):
2282 class mqrepo(repo.__class__):
2286 def abort_if_wdir_patched(self, errmsg, force=False):
2283 def abort_if_wdir_patched(self, errmsg, force=False):
2287 if self.mq.applied and not force:
2284 if self.mq.applied and not force:
2288 parent = revlog.hex(self.dirstate.parents()[0])
2285 parent = revlog.hex(self.dirstate.parents()[0])
2289 if parent in [s.rev for s in self.mq.applied]:
2286 if parent in [s.rev for s in self.mq.applied]:
2290 raise util.Abort(errmsg)
2287 raise util.Abort(errmsg)
2291
2288
2292 def commit(self, *args, **opts):
2289 def commit(self, *args, **opts):
2293 if len(args) >= 6:
2290 if len(args) >= 6:
2294 force = args[5]
2291 force = args[5]
2295 else:
2292 else:
2296 force = opts.get('force')
2293 force = opts.get('force')
2297 self.abort_if_wdir_patched(
2294 self.abort_if_wdir_patched(
2298 _('cannot commit over an applied mq patch'),
2295 _('cannot commit over an applied mq patch'),
2299 force)
2296 force)
2300
2297
2301 return super(mqrepo, self).commit(*args, **opts)
2298 return super(mqrepo, self).commit(*args, **opts)
2302
2299
2303 def push(self, remote, force=False, revs=None):
2300 def push(self, remote, force=False, revs=None):
2304 if self.mq.applied and not force and not revs:
2301 if self.mq.applied and not force and not revs:
2305 raise util.Abort(_('source has mq patches applied'))
2302 raise util.Abort(_('source has mq patches applied'))
2306 return super(mqrepo, self).push(remote, force, revs)
2303 return super(mqrepo, self).push(remote, force, revs)
2307
2304
2308 def tags(self):
2305 def tags(self):
2309 if self.tagscache:
2306 if self.tagscache:
2310 return self.tagscache
2307 return self.tagscache
2311
2308
2312 tagscache = super(mqrepo, self).tags()
2309 tagscache = super(mqrepo, self).tags()
2313
2310
2314 q = self.mq
2311 q = self.mq
2315 if not q.applied:
2312 if not q.applied:
2316 return tagscache
2313 return tagscache
2317
2314
2318 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2315 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2319
2316
2320 if mqtags[-1][0] not in self.changelog.nodemap:
2317 if mqtags[-1][0] not in self.changelog.nodemap:
2321 self.ui.warn(_('mq status file refers to unknown node %s\n')
2318 self.ui.warn(_('mq status file refers to unknown node %s\n')
2322 % revlog.short(mqtags[-1][0]))
2319 % revlog.short(mqtags[-1][0]))
2323 return tagscache
2320 return tagscache
2324
2321
2325 mqtags.append((mqtags[-1][0], 'qtip'))
2322 mqtags.append((mqtags[-1][0], 'qtip'))
2326 mqtags.append((mqtags[0][0], 'qbase'))
2323 mqtags.append((mqtags[0][0], 'qbase'))
2327 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2324 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2328 for patch in mqtags:
2325 for patch in mqtags:
2329 if patch[1] in tagscache:
2326 if patch[1] in tagscache:
2330 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2327 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2331 % patch[1])
2328 % patch[1])
2332 else:
2329 else:
2333 tagscache[patch[1]] = patch[0]
2330 tagscache[patch[1]] = patch[0]
2334
2331
2335 return tagscache
2332 return tagscache
2336
2333
2337 def _branchtags(self, partial, lrev):
2334 def _branchtags(self, partial, lrev):
2338 q = self.mq
2335 q = self.mq
2339 if not q.applied:
2336 if not q.applied:
2340 return super(mqrepo, self)._branchtags(partial, lrev)
2337 return super(mqrepo, self)._branchtags(partial, lrev)
2341
2338
2342 cl = self.changelog
2339 cl = self.changelog
2343 qbasenode = revlog.bin(q.applied[0].rev)
2340 qbasenode = revlog.bin(q.applied[0].rev)
2344 if qbasenode not in cl.nodemap:
2341 if qbasenode not in cl.nodemap:
2345 self.ui.warn(_('mq status file refers to unknown node %s\n')
2342 self.ui.warn(_('mq status file refers to unknown node %s\n')
2346 % revlog.short(qbasenode))
2343 % revlog.short(qbasenode))
2347 return super(mqrepo, self)._branchtags(partial, lrev)
2344 return super(mqrepo, self)._branchtags(partial, lrev)
2348
2345
2349 qbase = cl.rev(qbasenode)
2346 qbase = cl.rev(qbasenode)
2350 start = lrev + 1
2347 start = lrev + 1
2351 if start < qbase:
2348 if start < qbase:
2352 # update the cache (excluding the patches) and save it
2349 # update the cache (excluding the patches) and save it
2353 self._updatebranchcache(partial, lrev+1, qbase)
2350 self._updatebranchcache(partial, lrev+1, qbase)
2354 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2351 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2355 start = qbase
2352 start = qbase
2356 # if start = qbase, the cache is as updated as it should be.
2353 # if start = qbase, the cache is as updated as it should be.
2357 # if start > qbase, the cache includes (part of) the patches.
2354 # if start > qbase, the cache includes (part of) the patches.
2358 # we might as well use it, but we won't save it.
2355 # we might as well use it, but we won't save it.
2359
2356
2360 # update the cache up to the tip
2357 # update the cache up to the tip
2361 self._updatebranchcache(partial, start, len(cl))
2358 self._updatebranchcache(partial, start, len(cl))
2362
2359
2363 return partial
2360 return partial
2364
2361
2365 if repo.local():
2362 if repo.local():
2366 repo.__class__ = mqrepo
2363 repo.__class__ = mqrepo
2367 repo.mq = queue(ui, repo.join(""))
2364 repo.mq = queue(ui, repo.join(""))
2368
2365
2369 def mqimport(orig, ui, repo, *args, **kwargs):
2366 def mqimport(orig, ui, repo, *args, **kwargs):
2370 if hasattr(repo, 'abort_if_wdir_patched'):
2367 if hasattr(repo, 'abort_if_wdir_patched'):
2371 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2368 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2372 kwargs.get('force'))
2369 kwargs.get('force'))
2373 return orig(ui, repo, *args, **kwargs)
2370 return orig(ui, repo, *args, **kwargs)
2374
2371
2375 def uisetup(ui):
2372 def uisetup(ui):
2376 extensions.wrapcommand(commands.table, 'import', mqimport)
2373 extensions.wrapcommand(commands.table, 'import', mqimport)
2377
2374
2378 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2375 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2379
2376
2380 cmdtable = {
2377 cmdtable = {
2381 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2378 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2382 "qclone":
2379 "qclone":
2383 (clone,
2380 (clone,
2384 [('', 'pull', None, _('use pull protocol to copy metadata')),
2381 [('', 'pull', None, _('use pull protocol to copy metadata')),
2385 ('U', 'noupdate', None, _('do not update the new working directories')),
2382 ('U', 'noupdate', None, _('do not update the new working directories')),
2386 ('', 'uncompressed', None,
2383 ('', 'uncompressed', None,
2387 _('use uncompressed transfer (fast over LAN)')),
2384 _('use uncompressed transfer (fast over LAN)')),
2388 ('p', 'patches', '', _('location of source patch repo')),
2385 ('p', 'patches', '', _('location of source patch repo')),
2389 ] + commands.remoteopts,
2386 ] + commands.remoteopts,
2390 _('hg qclone [OPTION]... SOURCE [DEST]')),
2387 _('hg qclone [OPTION]... SOURCE [DEST]')),
2391 "qcommit|qci":
2388 "qcommit|qci":
2392 (commit,
2389 (commit,
2393 commands.table["^commit|ci"][1],
2390 commands.table["^commit|ci"][1],
2394 _('hg qcommit [OPTION]... [FILE]...')),
2391 _('hg qcommit [OPTION]... [FILE]...')),
2395 "^qdiff":
2392 "^qdiff":
2396 (diff,
2393 (diff,
2397 commands.diffopts + commands.diffopts2 + commands.walkopts,
2394 commands.diffopts + commands.diffopts2 + commands.walkopts,
2398 _('hg qdiff [OPTION]... [FILE]...')),
2395 _('hg qdiff [OPTION]... [FILE]...')),
2399 "qdelete|qremove|qrm":
2396 "qdelete|qremove|qrm":
2400 (delete,
2397 (delete,
2401 [('k', 'keep', None, _('keep patch file')),
2398 [('k', 'keep', None, _('keep patch file')),
2402 ('r', 'rev', [], _('stop managing a revision'))],
2399 ('r', 'rev', [], _('stop managing a revision'))],
2403 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2400 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2404 'qfold':
2401 'qfold':
2405 (fold,
2402 (fold,
2406 [('e', 'edit', None, _('edit patch header')),
2403 [('e', 'edit', None, _('edit patch header')),
2407 ('k', 'keep', None, _('keep folded patch files')),
2404 ('k', 'keep', None, _('keep folded patch files')),
2408 ] + commands.commitopts,
2405 ] + commands.commitopts,
2409 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2406 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2410 'qgoto':
2407 'qgoto':
2411 (goto,
2408 (goto,
2412 [('f', 'force', None, _('overwrite any local changes'))],
2409 [('f', 'force', None, _('overwrite any local changes'))],
2413 _('hg qgoto [OPTION]... PATCH')),
2410 _('hg qgoto [OPTION]... PATCH')),
2414 'qguard':
2411 'qguard':
2415 (guard,
2412 (guard,
2416 [('l', 'list', None, _('list all patches and guards')),
2413 [('l', 'list', None, _('list all patches and guards')),
2417 ('n', 'none', None, _('drop all guards'))],
2414 ('n', 'none', None, _('drop all guards'))],
2418 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2415 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2419 'qheader': (header, [], _('hg qheader [PATCH]')),
2416 'qheader': (header, [], _('hg qheader [PATCH]')),
2420 "^qimport":
2417 "^qimport":
2421 (qimport,
2418 (qimport,
2422 [('e', 'existing', None, _('import file in patch dir')),
2419 [('e', 'existing', None, _('import file in patch dir')),
2423 ('n', 'name', '', _('patch file name')),
2420 ('n', 'name', '', _('patch file name')),
2424 ('f', 'force', None, _('overwrite existing files')),
2421 ('f', 'force', None, _('overwrite existing files')),
2425 ('r', 'rev', [], _('place existing revisions under mq control')),
2422 ('r', 'rev', [], _('place existing revisions under mq control')),
2426 ('g', 'git', None, _('use git extended diff format'))],
2423 ('g', 'git', None, _('use git extended diff format'))],
2427 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2424 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2428 "^qinit":
2425 "^qinit":
2429 (init,
2426 (init,
2430 [('c', 'create-repo', None, _('create queue repository'))],
2427 [('c', 'create-repo', None, _('create queue repository'))],
2431 _('hg qinit [-c]')),
2428 _('hg qinit [-c]')),
2432 "qnew":
2429 "qnew":
2433 (new,
2430 (new,
2434 [('e', 'edit', None, _('edit commit message')),
2431 [('e', 'edit', None, _('edit commit message')),
2435 ('f', 'force', None, _('import uncommitted changes into patch')),
2432 ('f', 'force', None, _('import uncommitted changes into patch')),
2436 ('g', 'git', None, _('use git extended diff format')),
2433 ('g', 'git', None, _('use git extended diff format')),
2437 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2434 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2438 ('u', 'user', '', _('add "From: <given user>" to patch')),
2435 ('u', 'user', '', _('add "From: <given user>" to patch')),
2439 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2436 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2440 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2437 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2441 ] + commands.walkopts + commands.commitopts,
2438 ] + commands.walkopts + commands.commitopts,
2442 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2439 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2443 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2440 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2444 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2441 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2445 "^qpop":
2442 "^qpop":
2446 (pop,
2443 (pop,
2447 [('a', 'all', None, _('pop all patches')),
2444 [('a', 'all', None, _('pop all patches')),
2448 ('n', 'name', '', _('queue name to pop')),
2445 ('n', 'name', '', _('queue name to pop')),
2449 ('f', 'force', None, _('forget any local changes'))],
2446 ('f', 'force', None, _('forget any local changes'))],
2450 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2447 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2451 "^qpush":
2448 "^qpush":
2452 (push,
2449 (push,
2453 [('f', 'force', None, _('apply if the patch has rejects')),
2450 [('f', 'force', None, _('apply if the patch has rejects')),
2454 ('l', 'list', None, _('list patch name in commit text')),
2451 ('l', 'list', None, _('list patch name in commit text')),
2455 ('a', 'all', None, _('apply all patches')),
2452 ('a', 'all', None, _('apply all patches')),
2456 ('m', 'merge', None, _('merge from another queue')),
2453 ('m', 'merge', None, _('merge from another queue')),
2457 ('n', 'name', '', _('merge queue name'))],
2454 ('n', 'name', '', _('merge queue name'))],
2458 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2455 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2459 "^qrefresh":
2456 "^qrefresh":
2460 (refresh,
2457 (refresh,
2461 [('e', 'edit', None, _('edit commit message')),
2458 [('e', 'edit', None, _('edit commit message')),
2462 ('g', 'git', None, _('use git extended diff format')),
2459 ('g', 'git', None, _('use git extended diff format')),
2463 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2460 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2464 ('U', 'currentuser', None, _('add/update "From: <current user>" in patch')),
2461 ('U', 'currentuser', None, _('add/update "From: <current user>" in patch')),
2465 ('u', 'user', '', _('add/update "From: <given user>" in patch')),
2462 ('u', 'user', '', _('add/update "From: <given user>" in patch')),
2466 ('D', 'currentdate', None, _('update "Date: <current date>" in patch (if present)')),
2463 ('D', 'currentdate', None, _('update "Date: <current date>" in patch (if present)')),
2467 ('d', 'date', '', _('update "Date: <given date>" in patch (if present)'))
2464 ('d', 'date', '', _('update "Date: <given date>" in patch (if present)'))
2468 ] + commands.walkopts + commands.commitopts,
2465 ] + commands.walkopts + commands.commitopts,
2469 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2466 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2470 'qrename|qmv':
2467 'qrename|qmv':
2471 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2468 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2472 "qrestore":
2469 "qrestore":
2473 (restore,
2470 (restore,
2474 [('d', 'delete', None, _('delete save entry')),
2471 [('d', 'delete', None, _('delete save entry')),
2475 ('u', 'update', None, _('update queue working dir'))],
2472 ('u', 'update', None, _('update queue working dir'))],
2476 _('hg qrestore [-d] [-u] REV')),
2473 _('hg qrestore [-d] [-u] REV')),
2477 "qsave":
2474 "qsave":
2478 (save,
2475 (save,
2479 [('c', 'copy', None, _('copy patch directory')),
2476 [('c', 'copy', None, _('copy patch directory')),
2480 ('n', 'name', '', _('copy directory name')),
2477 ('n', 'name', '', _('copy directory name')),
2481 ('e', 'empty', None, _('clear queue status file')),
2478 ('e', 'empty', None, _('clear queue status file')),
2482 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2479 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2483 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2480 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2484 "qselect":
2481 "qselect":
2485 (select,
2482 (select,
2486 [('n', 'none', None, _('disable all guards')),
2483 [('n', 'none', None, _('disable all guards')),
2487 ('s', 'series', None, _('list all guards in series file')),
2484 ('s', 'series', None, _('list all guards in series file')),
2488 ('', 'pop', None, _('pop to before first guarded applied patch')),
2485 ('', 'pop', None, _('pop to before first guarded applied patch')),
2489 ('', 'reapply', None, _('pop, then reapply patches'))],
2486 ('', 'reapply', None, _('pop, then reapply patches'))],
2490 _('hg qselect [OPTION]... [GUARD]...')),
2487 _('hg qselect [OPTION]... [GUARD]...')),
2491 "qseries":
2488 "qseries":
2492 (series,
2489 (series,
2493 [('m', 'missing', None, _('print patches not in series')),
2490 [('m', 'missing', None, _('print patches not in series')),
2494 ] + seriesopts,
2491 ] + seriesopts,
2495 _('hg qseries [-ms]')),
2492 _('hg qseries [-ms]')),
2496 "^strip":
2493 "^strip":
2497 (strip,
2494 (strip,
2498 [('f', 'force', None, _('force removal with local changes')),
2495 [('f', 'force', None, _('force removal with local changes')),
2499 ('b', 'backup', None, _('bundle unrelated changesets')),
2496 ('b', 'backup', None, _('bundle unrelated changesets')),
2500 ('n', 'nobackup', None, _('no backups'))],
2497 ('n', 'nobackup', None, _('no backups'))],
2501 _('hg strip [-f] [-b] [-n] REV')),
2498 _('hg strip [-f] [-b] [-n] REV')),
2502 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2499 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2503 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2500 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2504 "qfinish":
2501 "qfinish":
2505 (finish,
2502 (finish,
2506 [('a', 'applied', None, _('finish all applied changesets'))],
2503 [('a', 'applied', None, _('finish all applied changesets'))],
2507 _('hg qfinish [-a] [REV...]')),
2504 _('hg qfinish [-a] [REV...]')),
2508 }
2505 }
@@ -1,3374 +1,3369 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.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 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from repo import RepoError, NoCapability
9 from repo import RepoError, NoCapability
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, urllib
11 import os, re, sys
12 import hg, util, revlog, bundlerepo, extensions, copies
12 import hg, util, revlog, bundlerepo, extensions, copies
13 import difflib, patch, time, help, mdiff, tempfile, url
13 import difflib, patch, time, help, mdiff, tempfile, url
14 import version, socket
14 import version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 import merge as merge_
16 import merge as merge_
17
17
18 # Commands start here, listed alphabetically
18 # Commands start here, listed alphabetically
19
19
20 def add(ui, repo, *pats, **opts):
20 def add(ui, repo, *pats, **opts):
21 """add the specified files on the next commit
21 """add the specified files on the next commit
22
22
23 Schedule files to be version controlled and added to the repository.
23 Schedule files to be version controlled and added to the repository.
24
24
25 The files will be added to the repository at the next commit. To
25 The files will be added to the repository at the next commit. To
26 undo an add before that, see hg revert.
26 undo an add before that, see hg revert.
27
27
28 If no names are given, add all files in the repository.
28 If no names are given, add all files in the repository.
29 """
29 """
30
30
31 rejected = None
31 rejected = None
32 exacts = {}
32 exacts = {}
33 names = []
33 names = []
34 m = cmdutil.match(repo, pats, opts)
34 m = cmdutil.match(repo, pats, opts)
35 m.bad = lambda x,y: True
35 m.bad = lambda x,y: True
36 for abs in repo.walk(m):
36 for abs in repo.walk(m):
37 if m.exact(abs):
37 if m.exact(abs):
38 if ui.verbose:
38 if ui.verbose:
39 ui.status(_('adding %s\n') % m.rel(abs))
39 ui.status(_('adding %s\n') % m.rel(abs))
40 names.append(abs)
40 names.append(abs)
41 exacts[abs] = 1
41 exacts[abs] = 1
42 elif abs not in repo.dirstate:
42 elif abs not in repo.dirstate:
43 ui.status(_('adding %s\n') % m.rel(abs))
43 ui.status(_('adding %s\n') % m.rel(abs))
44 names.append(abs)
44 names.append(abs)
45 if not opts.get('dry_run'):
45 if not opts.get('dry_run'):
46 rejected = repo.add(names)
46 rejected = repo.add(names)
47 rejected = [p for p in rejected if p in exacts]
47 rejected = [p for p in rejected if p in exacts]
48 return rejected and 1 or 0
48 return rejected and 1 or 0
49
49
50 def addremove(ui, repo, *pats, **opts):
50 def addremove(ui, repo, *pats, **opts):
51 """add all new files, delete all missing files
51 """add all new files, delete all missing files
52
52
53 Add all new files and remove all missing files from the repository.
53 Add all new files and remove all missing files from the repository.
54
54
55 New files are ignored if they match any of the patterns in .hgignore. As
55 New files are ignored if they match any of the patterns in .hgignore. As
56 with add, these changes take effect at the next commit.
56 with add, these changes take effect at the next commit.
57
57
58 Use the -s option to detect renamed files. With a parameter > 0,
58 Use the -s option to detect renamed files. With a parameter > 0,
59 this compares every removed file with every added file and records
59 this compares every removed file with every added file and records
60 those similar enough as renames. This option takes a percentage
60 those similar enough as renames. This option takes a percentage
61 between 0 (disabled) and 100 (files must be identical) as its
61 between 0 (disabled) and 100 (files must be identical) as its
62 parameter. Detecting renamed files this way can be expensive.
62 parameter. Detecting renamed files this way can be expensive.
63 """
63 """
64 try:
64 try:
65 sim = float(opts.get('similarity') or 0)
65 sim = float(opts.get('similarity') or 0)
66 except ValueError:
66 except ValueError:
67 raise util.Abort(_('similarity must be a number'))
67 raise util.Abort(_('similarity must be a number'))
68 if sim < 0 or sim > 100:
68 if sim < 0 or sim > 100:
69 raise util.Abort(_('similarity must be between 0 and 100'))
69 raise util.Abort(_('similarity must be between 0 and 100'))
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
71
71
72 def annotate(ui, repo, *pats, **opts):
72 def annotate(ui, repo, *pats, **opts):
73 """show changeset information per file line
73 """show changeset information per file line
74
74
75 List changes in files, showing the revision id responsible for each line
75 List changes in files, showing the revision id responsible for each line
76
76
77 This command is useful to discover who did a change or when a change took
77 This command is useful to discover who did a change or when a change took
78 place.
78 place.
79
79
80 Without the -a option, annotate will avoid processing files it
80 Without the -a option, annotate will avoid processing files it
81 detects as binary. With -a, annotate will generate an annotation
81 detects as binary. With -a, annotate will generate an annotation
82 anyway, probably with undesirable results.
82 anyway, probably with undesirable results.
83 """
83 """
84 datefunc = ui.quiet and util.shortdate or util.datestr
84 datefunc = ui.quiet and util.shortdate or util.datestr
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
86
86
87 if not pats:
87 if not pats:
88 raise util.Abort(_('at least one file name or pattern required'))
88 raise util.Abort(_('at least one file name or pattern required'))
89
89
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
91 ('number', lambda x: str(x[0].rev())),
91 ('number', lambda x: str(x[0].rev())),
92 ('changeset', lambda x: short(x[0].node())),
92 ('changeset', lambda x: short(x[0].node())),
93 ('date', getdate),
93 ('date', getdate),
94 ('follow', lambda x: x[0].path()),
94 ('follow', lambda x: x[0].path()),
95 ]
95 ]
96
96
97 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
97 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
98 and not opts.get('follow')):
98 and not opts.get('follow')):
99 opts['number'] = 1
99 opts['number'] = 1
100
100
101 linenumber = opts.get('line_number') is not None
101 linenumber = opts.get('line_number') is not None
102 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
102 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
104
104
105 funcmap = [func for op, func in opmap if opts.get(op)]
105 funcmap = [func for op, func in opmap if opts.get(op)]
106 if linenumber:
106 if linenumber:
107 lastfunc = funcmap[-1]
107 lastfunc = funcmap[-1]
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
109
109
110 ctx = repo[opts.get('rev')]
110 ctx = repo[opts.get('rev')]
111
111
112 m = cmdutil.match(repo, pats, opts)
112 m = cmdutil.match(repo, pats, opts)
113 for abs in ctx.walk(m):
113 for abs in ctx.walk(m):
114 fctx = ctx[abs]
114 fctx = ctx[abs]
115 if not opts.get('text') and util.binary(fctx.data()):
115 if not opts.get('text') and util.binary(fctx.data()):
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
117 continue
117 continue
118
118
119 lines = fctx.annotate(follow=opts.get('follow'),
119 lines = fctx.annotate(follow=opts.get('follow'),
120 linenumber=linenumber)
120 linenumber=linenumber)
121 pieces = []
121 pieces = []
122
122
123 for f in funcmap:
123 for f in funcmap:
124 l = [f(n) for n, dummy in lines]
124 l = [f(n) for n, dummy in lines]
125 if l:
125 if l:
126 ml = max(map(len, l))
126 ml = max(map(len, l))
127 pieces.append(["%*s" % (ml, x) for x in l])
127 pieces.append(["%*s" % (ml, x) for x in l])
128
128
129 if pieces:
129 if pieces:
130 for p, l in zip(zip(*pieces), lines):
130 for p, l in zip(zip(*pieces), lines):
131 ui.write("%s: %s" % (" ".join(p), l[1]))
131 ui.write("%s: %s" % (" ".join(p), l[1]))
132
132
133 def archive(ui, repo, dest, **opts):
133 def archive(ui, repo, dest, **opts):
134 '''create unversioned archive of a repository revision
134 '''create unversioned archive of a repository revision
135
135
136 By default, the revision used is the parent of the working
136 By default, the revision used is the parent of the working
137 directory; use "-r" to specify a different revision.
137 directory; use "-r" to specify a different revision.
138
138
139 To specify the type of archive to create, use "-t". Valid
139 To specify the type of archive to create, use "-t". Valid
140 types are:
140 types are:
141
141
142 "files" (default): a directory full of files
142 "files" (default): a directory full of files
143 "tar": tar archive, uncompressed
143 "tar": tar archive, uncompressed
144 "tbz2": tar archive, compressed using bzip2
144 "tbz2": tar archive, compressed using bzip2
145 "tgz": tar archive, compressed using gzip
145 "tgz": tar archive, compressed using gzip
146 "uzip": zip archive, uncompressed
146 "uzip": zip archive, uncompressed
147 "zip": zip archive, compressed using deflate
147 "zip": zip archive, compressed using deflate
148
148
149 The exact name of the destination archive or directory is given
149 The exact name of the destination archive or directory is given
150 using a format string; see "hg help export" for details.
150 using a format string; see "hg help export" for details.
151
151
152 Each member added to an archive file has a directory prefix
152 Each member added to an archive file has a directory prefix
153 prepended. Use "-p" to specify a format string for the prefix.
153 prepended. Use "-p" to specify a format string for the prefix.
154 The default is the basename of the archive, with suffixes removed.
154 The default is the basename of the archive, with suffixes removed.
155 '''
155 '''
156
156
157 ctx = repo[opts.get('rev')]
157 ctx = repo[opts.get('rev')]
158 if not ctx:
158 if not ctx:
159 raise util.Abort(_('repository has no revisions'))
159 raise util.Abort(_('repository has no revisions'))
160 node = ctx.node()
160 node = ctx.node()
161 dest = cmdutil.make_filename(repo, dest, node)
161 dest = cmdutil.make_filename(repo, dest, node)
162 if os.path.realpath(dest) == repo.root:
162 if os.path.realpath(dest) == repo.root:
163 raise util.Abort(_('repository root cannot be destination'))
163 raise util.Abort(_('repository root cannot be destination'))
164 matchfn = cmdutil.match(repo, [], opts)
164 matchfn = cmdutil.match(repo, [], opts)
165 kind = opts.get('type') or 'files'
165 kind = opts.get('type') or 'files'
166 prefix = opts.get('prefix')
166 prefix = opts.get('prefix')
167 if dest == '-':
167 if dest == '-':
168 if kind == 'files':
168 if kind == 'files':
169 raise util.Abort(_('cannot archive plain files to stdout'))
169 raise util.Abort(_('cannot archive plain files to stdout'))
170 dest = sys.stdout
170 dest = sys.stdout
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
172 prefix = cmdutil.make_filename(repo, prefix, node)
172 prefix = cmdutil.make_filename(repo, prefix, node)
173 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
173 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
174 matchfn, prefix)
174 matchfn, prefix)
175
175
176 def backout(ui, repo, node=None, rev=None, **opts):
176 def backout(ui, repo, node=None, rev=None, **opts):
177 '''reverse effect of earlier changeset
177 '''reverse effect of earlier changeset
178
178
179 Commit the backed out changes as a new changeset. The new
179 Commit the backed out changes as a new changeset. The new
180 changeset is a child of the backed out changeset.
180 changeset is a child of the backed out changeset.
181
181
182 If you back out a changeset other than the tip, a new head is
182 If you back out a changeset other than the tip, a new head is
183 created. This head will be the new tip and you should merge this
183 created. This head will be the new tip and you should merge this
184 backout changeset with another head (current one by default).
184 backout changeset with another head (current one by default).
185
185
186 The --merge option remembers the parent of the working directory
186 The --merge option remembers the parent of the working directory
187 before starting the backout, then merges the new head with that
187 before starting the backout, then merges the new head with that
188 changeset afterwards. This saves you from doing the merge by
188 changeset afterwards. This saves you from doing the merge by
189 hand. The result of this merge is not committed, as for a normal
189 hand. The result of this merge is not committed, as for a normal
190 merge.
190 merge.
191
191
192 See \'hg help dates\' for a list of formats valid for -d/--date.
192 See \'hg help dates\' for a list of formats valid for -d/--date.
193 '''
193 '''
194 if rev and node:
194 if rev and node:
195 raise util.Abort(_("please specify just one revision"))
195 raise util.Abort(_("please specify just one revision"))
196
196
197 if not rev:
197 if not rev:
198 rev = node
198 rev = node
199
199
200 if not rev:
200 if not rev:
201 raise util.Abort(_("please specify a revision to backout"))
201 raise util.Abort(_("please specify a revision to backout"))
202
202
203 date = opts.get('date')
203 date = opts.get('date')
204 if date:
204 if date:
205 opts['date'] = util.parsedate(date)
205 opts['date'] = util.parsedate(date)
206
206
207 cmdutil.bail_if_changed(repo)
207 cmdutil.bail_if_changed(repo)
208 node = repo.lookup(rev)
208 node = repo.lookup(rev)
209
209
210 op1, op2 = repo.dirstate.parents()
210 op1, op2 = repo.dirstate.parents()
211 a = repo.changelog.ancestor(op1, node)
211 a = repo.changelog.ancestor(op1, node)
212 if a != node:
212 if a != node:
213 raise util.Abort(_('cannot back out change on a different branch'))
213 raise util.Abort(_('cannot back out change on a different branch'))
214
214
215 p1, p2 = repo.changelog.parents(node)
215 p1, p2 = repo.changelog.parents(node)
216 if p1 == nullid:
216 if p1 == nullid:
217 raise util.Abort(_('cannot back out a change with no parents'))
217 raise util.Abort(_('cannot back out a change with no parents'))
218 if p2 != nullid:
218 if p2 != nullid:
219 if not opts.get('parent'):
219 if not opts.get('parent'):
220 raise util.Abort(_('cannot back out a merge changeset without '
220 raise util.Abort(_('cannot back out a merge changeset without '
221 '--parent'))
221 '--parent'))
222 p = repo.lookup(opts['parent'])
222 p = repo.lookup(opts['parent'])
223 if p not in (p1, p2):
223 if p not in (p1, p2):
224 raise util.Abort(_('%s is not a parent of %s') %
224 raise util.Abort(_('%s is not a parent of %s') %
225 (short(p), short(node)))
225 (short(p), short(node)))
226 parent = p
226 parent = p
227 else:
227 else:
228 if opts.get('parent'):
228 if opts.get('parent'):
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
230 parent = p1
230 parent = p1
231
231
232 # the backout should appear on the same branch
232 # the backout should appear on the same branch
233 branch = repo.dirstate.branch()
233 branch = repo.dirstate.branch()
234 hg.clean(repo, node, show_stats=False)
234 hg.clean(repo, node, show_stats=False)
235 repo.dirstate.setbranch(branch)
235 repo.dirstate.setbranch(branch)
236 revert_opts = opts.copy()
236 revert_opts = opts.copy()
237 revert_opts['date'] = None
237 revert_opts['date'] = None
238 revert_opts['all'] = True
238 revert_opts['all'] = True
239 revert_opts['rev'] = hex(parent)
239 revert_opts['rev'] = hex(parent)
240 revert_opts['no_backup'] = None
240 revert_opts['no_backup'] = None
241 revert(ui, repo, **revert_opts)
241 revert(ui, repo, **revert_opts)
242 commit_opts = opts.copy()
242 commit_opts = opts.copy()
243 commit_opts['addremove'] = False
243 commit_opts['addremove'] = False
244 if not commit_opts['message'] and not commit_opts['logfile']:
244 if not commit_opts['message'] and not commit_opts['logfile']:
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
246 commit_opts['force_editor'] = True
246 commit_opts['force_editor'] = True
247 commit(ui, repo, **commit_opts)
247 commit(ui, repo, **commit_opts)
248 def nice(node):
248 def nice(node):
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
250 ui.status(_('changeset %s backs out changeset %s\n') %
250 ui.status(_('changeset %s backs out changeset %s\n') %
251 (nice(repo.changelog.tip()), nice(node)))
251 (nice(repo.changelog.tip()), nice(node)))
252 if op1 != node:
252 if op1 != node:
253 hg.clean(repo, op1, show_stats=False)
253 hg.clean(repo, op1, show_stats=False)
254 if opts.get('merge'):
254 if opts.get('merge'):
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
257 else:
257 else:
258 ui.status(_('the backout changeset is a new head - '
258 ui.status(_('the backout changeset is a new head - '
259 'do not forget to merge\n'))
259 'do not forget to merge\n'))
260 ui.status(_('(use "backout --merge" '
260 ui.status(_('(use "backout --merge" '
261 'if you want to auto-merge)\n'))
261 'if you want to auto-merge)\n'))
262
262
263 def bisect(ui, repo, rev=None, extra=None, command=None,
263 def bisect(ui, repo, rev=None, extra=None, command=None,
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
265 """subdivision search of changesets
265 """subdivision search of changesets
266
266
267 This command helps to find changesets which introduce problems.
267 This command helps to find changesets which introduce problems.
268 To use, mark the earliest changeset you know exhibits the problem
268 To use, mark the earliest changeset you know exhibits the problem
269 as bad, then mark the latest changeset which is free from the
269 as bad, then mark the latest changeset which is free from the
270 problem as good. Bisect will update your working directory to a
270 problem as good. Bisect will update your working directory to a
271 revision for testing (unless the --noupdate option is specified).
271 revision for testing (unless the --noupdate option is specified).
272 Once you have performed tests, mark the working directory as bad
272 Once you have performed tests, mark the working directory as bad
273 or good and bisect will either update to another candidate changeset
273 or good and bisect will either update to another candidate changeset
274 or announce that it has found the bad revision.
274 or announce that it has found the bad revision.
275
275
276 As a shortcut, you can also use the revision argument to mark a
276 As a shortcut, you can also use the revision argument to mark a
277 revision as good or bad without checking it out first.
277 revision as good or bad without checking it out first.
278
278
279 If you supply a command it will be used for automatic bisection. Its exit
279 If you supply a command it will be used for automatic bisection. Its exit
280 status will be used as flag to mark revision as bad or good. In case exit
280 status will be used as flag to mark revision as bad or good. In case exit
281 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
281 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
282 found) - bisection will be aborted and any other status bigger than 0 will
282 found) - bisection will be aborted and any other status bigger than 0 will
283 mark revision as bad.
283 mark revision as bad.
284 """
284 """
285 def print_result(nodes, good):
285 def print_result(nodes, good):
286 displayer = cmdutil.show_changeset(ui, repo, {})
286 displayer = cmdutil.show_changeset(ui, repo, {})
287 transition = (good and "good" or "bad")
287 transition = (good and "good" or "bad")
288 if len(nodes) == 1:
288 if len(nodes) == 1:
289 # narrowed it down to a single revision
289 # narrowed it down to a single revision
290 ui.write(_("The first %s revision is:\n") % transition)
290 ui.write(_("The first %s revision is:\n") % transition)
291 displayer.show(changenode=nodes[0])
291 displayer.show(changenode=nodes[0])
292 else:
292 else:
293 # multiple possible revisions
293 # multiple possible revisions
294 ui.write(_("Due to skipped revisions, the first "
294 ui.write(_("Due to skipped revisions, the first "
295 "%s revision could be any of:\n") % transition)
295 "%s revision could be any of:\n") % transition)
296 for n in nodes:
296 for n in nodes:
297 displayer.show(changenode=n)
297 displayer.show(changenode=n)
298
298
299 def check_state(state, interactive=True):
299 def check_state(state, interactive=True):
300 if not state['good'] or not state['bad']:
300 if not state['good'] or not state['bad']:
301 if (good or bad or skip or reset) and interactive:
301 if (good or bad or skip or reset) and interactive:
302 return
302 return
303 if not state['good']:
303 if not state['good']:
304 raise util.Abort(_('cannot bisect (no known good revisions)'))
304 raise util.Abort(_('cannot bisect (no known good revisions)'))
305 else:
305 else:
306 raise util.Abort(_('cannot bisect (no known bad revisions)'))
306 raise util.Abort(_('cannot bisect (no known bad revisions)'))
307 return True
307 return True
308
308
309 # backward compatibility
309 # backward compatibility
310 if rev in "good bad reset init".split():
310 if rev in "good bad reset init".split():
311 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
311 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
312 cmd, rev, extra = rev, extra, None
312 cmd, rev, extra = rev, extra, None
313 if cmd == "good":
313 if cmd == "good":
314 good = True
314 good = True
315 elif cmd == "bad":
315 elif cmd == "bad":
316 bad = True
316 bad = True
317 else:
317 else:
318 reset = True
318 reset = True
319 elif extra or good + bad + skip + reset + bool(command) > 1:
319 elif extra or good + bad + skip + reset + bool(command) > 1:
320 raise util.Abort(_('incompatible arguments'))
320 raise util.Abort(_('incompatible arguments'))
321
321
322 if reset:
322 if reset:
323 p = repo.join("bisect.state")
323 p = repo.join("bisect.state")
324 if os.path.exists(p):
324 if os.path.exists(p):
325 os.unlink(p)
325 os.unlink(p)
326 return
326 return
327
327
328 state = hbisect.load_state(repo)
328 state = hbisect.load_state(repo)
329
329
330 if command:
330 if command:
331 changesets = 1
331 changesets = 1
332 while changesets:
332 while changesets:
333 # update state
333 # update state
334 status = os.spawnlp(os.P_WAIT, command)
334 status = os.spawnlp(os.P_WAIT, command)
335 node = repo.lookup(rev or '.')
335 node = repo.lookup(rev or '.')
336 if status == 125:
336 if status == 125:
337 transition = "skip"
337 transition = "skip"
338 elif status == 0:
338 elif status == 0:
339 transition = "good"
339 transition = "good"
340 # status < 0 means process was killed
340 # status < 0 means process was killed
341 elif status == 127 or status < 0:
341 elif status == 127 or status < 0:
342 break
342 break
343 else:
343 else:
344 transition = "bad"
344 transition = "bad"
345 state[transition].append(node)
345 state[transition].append(node)
346 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
346 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
347 check_state(state, interactive=False)
347 check_state(state, interactive=False)
348 # bisect
348 # bisect
349 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
349 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
350 # update to next check
350 # update to next check
351 cmdutil.bail_if_changed(repo)
351 cmdutil.bail_if_changed(repo)
352 hg.clean(repo, nodes[0], show_stats=False)
352 hg.clean(repo, nodes[0], show_stats=False)
353 hbisect.save_state(repo, state)
353 hbisect.save_state(repo, state)
354 return print_result(nodes, not status)
354 return print_result(nodes, not status)
355
355
356 # update state
356 # update state
357 node = repo.lookup(rev or '.')
357 node = repo.lookup(rev or '.')
358 if good:
358 if good:
359 state['good'].append(node)
359 state['good'].append(node)
360 elif bad:
360 elif bad:
361 state['bad'].append(node)
361 state['bad'].append(node)
362 elif skip:
362 elif skip:
363 state['skip'].append(node)
363 state['skip'].append(node)
364
364
365 hbisect.save_state(repo, state)
365 hbisect.save_state(repo, state)
366
366
367 if not check_state(state):
367 if not check_state(state):
368 return
368 return
369
369
370 # actually bisect
370 # actually bisect
371 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
371 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
372 if changesets == 0:
372 if changesets == 0:
373 print_result(nodes, good)
373 print_result(nodes, good)
374 else:
374 else:
375 assert len(nodes) == 1 # only a single node can be tested next
375 assert len(nodes) == 1 # only a single node can be tested next
376 node = nodes[0]
376 node = nodes[0]
377 # compute the approximate number of remaining tests
377 # compute the approximate number of remaining tests
378 tests, size = 0, 2
378 tests, size = 0, 2
379 while size <= changesets:
379 while size <= changesets:
380 tests, size = tests + 1, size * 2
380 tests, size = tests + 1, size * 2
381 rev = repo.changelog.rev(node)
381 rev = repo.changelog.rev(node)
382 ui.write(_("Testing changeset %s:%s "
382 ui.write(_("Testing changeset %s:%s "
383 "(%s changesets remaining, ~%s tests)\n")
383 "(%s changesets remaining, ~%s tests)\n")
384 % (rev, short(node), changesets, tests))
384 % (rev, short(node), changesets, tests))
385 if not noupdate:
385 if not noupdate:
386 cmdutil.bail_if_changed(repo)
386 cmdutil.bail_if_changed(repo)
387 return hg.clean(repo, node)
387 return hg.clean(repo, node)
388
388
389 def branch(ui, repo, label=None, **opts):
389 def branch(ui, repo, label=None, **opts):
390 """set or show the current branch name
390 """set or show the current branch name
391
391
392 With no argument, show the current branch name. With one argument,
392 With no argument, show the current branch name. With one argument,
393 set the working directory branch name (the branch does not exist in
393 set the working directory branch name (the branch does not exist in
394 the repository until the next commit).
394 the repository until the next commit).
395
395
396 Unless --force is specified, branch will not let you set a
396 Unless --force is specified, branch will not let you set a
397 branch name that shadows an existing branch.
397 branch name that shadows an existing branch.
398
398
399 Use --clean to reset the working directory branch to that of the
399 Use --clean to reset the working directory branch to that of the
400 parent of the working directory, negating a previous branch change.
400 parent of the working directory, negating a previous branch change.
401
401
402 Use the command 'hg update' to switch to an existing branch.
402 Use the command 'hg update' to switch to an existing branch.
403 """
403 """
404
404
405 if opts.get('clean'):
405 if opts.get('clean'):
406 label = repo[None].parents()[0].branch()
406 label = repo[None].parents()[0].branch()
407 repo.dirstate.setbranch(label)
407 repo.dirstate.setbranch(label)
408 ui.status(_('reset working directory to branch %s\n') % label)
408 ui.status(_('reset working directory to branch %s\n') % label)
409 elif label:
409 elif label:
410 if not opts.get('force') and label in repo.branchtags():
410 if not opts.get('force') and label in repo.branchtags():
411 if label not in [p.branch() for p in repo.parents()]:
411 if label not in [p.branch() for p in repo.parents()]:
412 raise util.Abort(_('a branch of the same name already exists'
412 raise util.Abort(_('a branch of the same name already exists'
413 ' (use --force to override)'))
413 ' (use --force to override)'))
414 repo.dirstate.setbranch(util.fromlocal(label))
414 repo.dirstate.setbranch(util.fromlocal(label))
415 ui.status(_('marked working directory as branch %s\n') % label)
415 ui.status(_('marked working directory as branch %s\n') % label)
416 else:
416 else:
417 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
417 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
418
418
419 def branches(ui, repo, active=False):
419 def branches(ui, repo, active=False):
420 """list repository named branches
420 """list repository named branches
421
421
422 List the repository's named branches, indicating which ones are
422 List the repository's named branches, indicating which ones are
423 inactive. If active is specified, only show active branches.
423 inactive. If active is specified, only show active branches.
424
424
425 A branch is considered active if it contains repository heads.
425 A branch is considered active if it contains repository heads.
426
426
427 Use the command 'hg update' to switch to an existing branch.
427 Use the command 'hg update' to switch to an existing branch.
428 """
428 """
429 hexfunc = ui.debugflag and hex or short
429 hexfunc = ui.debugflag and hex or short
430 activebranches = [util.tolocal(repo[n].branch())
430 activebranches = [util.tolocal(repo[n].branch())
431 for n in repo.heads()]
431 for n in repo.heads()]
432 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
432 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
433 for tag, node in repo.branchtags().items()])
433 for tag, node in repo.branchtags().items()])
434 branches.reverse()
434 branches.reverse()
435
435
436 for isactive, node, tag in branches:
436 for isactive, node, tag in branches:
437 if (not active) or isactive:
437 if (not active) or isactive:
438 if ui.quiet:
438 if ui.quiet:
439 ui.write("%s\n" % tag)
439 ui.write("%s\n" % tag)
440 else:
440 else:
441 rev = str(node).rjust(31 - util.locallen(tag))
441 rev = str(node).rjust(31 - util.locallen(tag))
442 isinactive = ((not isactive) and " (inactive)") or ''
442 isinactive = ((not isactive) and " (inactive)") or ''
443 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
443 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
444 ui.write("%s %s:%s%s\n" % data)
444 ui.write("%s %s:%s%s\n" % data)
445
445
446 def bundle(ui, repo, fname, dest=None, **opts):
446 def bundle(ui, repo, fname, dest=None, **opts):
447 """create a changegroup file
447 """create a changegroup file
448
448
449 Generate a compressed changegroup file collecting changesets not
449 Generate a compressed changegroup file collecting changesets not
450 found in the other repository.
450 found in the other repository.
451
451
452 If no destination repository is specified the destination is
452 If no destination repository is specified the destination is
453 assumed to have all the nodes specified by one or more --base
453 assumed to have all the nodes specified by one or more --base
454 parameters. To create a bundle containing all changesets, use
454 parameters. To create a bundle containing all changesets, use
455 --all (or --base null). To change the compression method applied,
455 --all (or --base null). To change the compression method applied,
456 use the -t option (by default, bundles are compressed using bz2).
456 use the -t option (by default, bundles are compressed using bz2).
457
457
458 The bundle file can then be transferred using conventional means and
458 The bundle file can then be transferred using conventional means and
459 applied to another repository with the unbundle or pull command.
459 applied to another repository with the unbundle or pull command.
460 This is useful when direct push and pull are not available or when
460 This is useful when direct push and pull are not available or when
461 exporting an entire repository is undesirable.
461 exporting an entire repository is undesirable.
462
462
463 Applying bundles preserves all changeset contents including
463 Applying bundles preserves all changeset contents including
464 permissions, copy/rename information, and revision history.
464 permissions, copy/rename information, and revision history.
465 """
465 """
466 revs = opts.get('rev') or None
466 revs = opts.get('rev') or None
467 if revs:
467 if revs:
468 revs = [repo.lookup(rev) for rev in revs]
468 revs = [repo.lookup(rev) for rev in revs]
469 if opts.get('all'):
469 if opts.get('all'):
470 base = ['null']
470 base = ['null']
471 else:
471 else:
472 base = opts.get('base')
472 base = opts.get('base')
473 if base:
473 if base:
474 if dest:
474 if dest:
475 raise util.Abort(_("--base is incompatible with specifiying "
475 raise util.Abort(_("--base is incompatible with specifiying "
476 "a destination"))
476 "a destination"))
477 base = [repo.lookup(rev) for rev in base]
477 base = [repo.lookup(rev) for rev in base]
478 # create the right base
478 # create the right base
479 # XXX: nodesbetween / changegroup* should be "fixed" instead
479 # XXX: nodesbetween / changegroup* should be "fixed" instead
480 o = []
480 o = []
481 has = {nullid: None}
481 has = {nullid: None}
482 for n in base:
482 for n in base:
483 has.update(repo.changelog.reachable(n))
483 has.update(repo.changelog.reachable(n))
484 if revs:
484 if revs:
485 visit = list(revs)
485 visit = list(revs)
486 else:
486 else:
487 visit = repo.changelog.heads()
487 visit = repo.changelog.heads()
488 seen = {}
488 seen = {}
489 while visit:
489 while visit:
490 n = visit.pop(0)
490 n = visit.pop(0)
491 parents = [p for p in repo.changelog.parents(n) if p not in has]
491 parents = [p for p in repo.changelog.parents(n) if p not in has]
492 if len(parents) == 0:
492 if len(parents) == 0:
493 o.insert(0, n)
493 o.insert(0, n)
494 else:
494 else:
495 for p in parents:
495 for p in parents:
496 if p not in seen:
496 if p not in seen:
497 seen[p] = 1
497 seen[p] = 1
498 visit.append(p)
498 visit.append(p)
499 else:
499 else:
500 cmdutil.setremoteconfig(ui, opts)
500 cmdutil.setremoteconfig(ui, opts)
501 dest, revs, checkout = hg.parseurl(
501 dest, revs, checkout = hg.parseurl(
502 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
502 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
503 other = hg.repository(ui, dest)
503 other = hg.repository(ui, dest)
504 o = repo.findoutgoing(other, force=opts.get('force'))
504 o = repo.findoutgoing(other, force=opts.get('force'))
505
505
506 if revs:
506 if revs:
507 cg = repo.changegroupsubset(o, revs, 'bundle')
507 cg = repo.changegroupsubset(o, revs, 'bundle')
508 else:
508 else:
509 cg = repo.changegroup(o, 'bundle')
509 cg = repo.changegroup(o, 'bundle')
510
510
511 bundletype = opts.get('type', 'bzip2').lower()
511 bundletype = opts.get('type', 'bzip2').lower()
512 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
512 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
513 bundletype = btypes.get(bundletype)
513 bundletype = btypes.get(bundletype)
514 if bundletype not in changegroup.bundletypes:
514 if bundletype not in changegroup.bundletypes:
515 raise util.Abort(_('unknown bundle type specified with --type'))
515 raise util.Abort(_('unknown bundle type specified with --type'))
516
516
517 changegroup.writebundle(cg, fname, bundletype)
517 changegroup.writebundle(cg, fname, bundletype)
518
518
519 def cat(ui, repo, file1, *pats, **opts):
519 def cat(ui, repo, file1, *pats, **opts):
520 """output the current or given revision of files
520 """output the current or given revision of files
521
521
522 Print the specified files as they were at the given revision.
522 Print the specified files as they were at the given revision.
523 If no revision is given, the parent of the working directory is used,
523 If no revision is given, the parent of the working directory is used,
524 or tip if no revision is checked out.
524 or tip if no revision is checked out.
525
525
526 Output may be to a file, in which case the name of the file is
526 Output may be to a file, in which case the name of the file is
527 given using a format string. The formatting rules are the same as
527 given using a format string. The formatting rules are the same as
528 for the export command, with the following additions:
528 for the export command, with the following additions:
529
529
530 %s basename of file being printed
530 %s basename of file being printed
531 %d dirname of file being printed, or '.' if in repo root
531 %d dirname of file being printed, or '.' if in repo root
532 %p root-relative path name of file being printed
532 %p root-relative path name of file being printed
533 """
533 """
534 ctx = repo[opts.get('rev')]
534 ctx = repo[opts.get('rev')]
535 err = 1
535 err = 1
536 m = cmdutil.match(repo, (file1,) + pats, opts)
536 m = cmdutil.match(repo, (file1,) + pats, opts)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
538 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
539 data = ctx[abs].data()
539 data = ctx[abs].data()
540 if opts.get('decode'):
540 if opts.get('decode'):
541 data = repo.wwritedata(abs, data)
541 data = repo.wwritedata(abs, data)
542 fp.write(data)
542 fp.write(data)
543 err = 0
543 err = 0
544 return err
544 return err
545
545
546 def clone(ui, source, dest=None, **opts):
546 def clone(ui, source, dest=None, **opts):
547 """make a copy of an existing repository
547 """make a copy of an existing repository
548
548
549 Create a copy of an existing repository in a new directory.
549 Create a copy of an existing repository in a new directory.
550
550
551 If no destination directory name is specified, it defaults to the
551 If no destination directory name is specified, it defaults to the
552 basename of the source.
552 basename of the source.
553
553
554 The location of the source is added to the new repository's
554 The location of the source is added to the new repository's
555 .hg/hgrc file, as the default to be used for future pulls.
555 .hg/hgrc file, as the default to be used for future pulls.
556
556
557 For efficiency, hardlinks are used for cloning whenever the source
557 For efficiency, hardlinks are used for cloning whenever the source
558 and destination are on the same filesystem (note this applies only
558 and destination are on the same filesystem (note this applies only
559 to the repository data, not to the checked out files). Some
559 to the repository data, not to the checked out files). Some
560 filesystems, such as AFS, implement hardlinking incorrectly, but
560 filesystems, such as AFS, implement hardlinking incorrectly, but
561 do not report errors. In these cases, use the --pull option to
561 do not report errors. In these cases, use the --pull option to
562 avoid hardlinking.
562 avoid hardlinking.
563
563
564 In some cases, you can clone repositories and checked out files
564 In some cases, you can clone repositories and checked out files
565 using full hardlinks with
565 using full hardlinks with
566
566
567 $ cp -al REPO REPOCLONE
567 $ cp -al REPO REPOCLONE
568
568
569 This is the fastest way to clone, but it is not always safe. The
569 This is the fastest way to clone, but it is not always safe. The
570 operation is not atomic (making sure REPO is not modified during
570 operation is not atomic (making sure REPO is not modified during
571 the operation is up to you) and you have to make sure your editor
571 the operation is up to you) and you have to make sure your editor
572 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
572 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
573 this is not compatible with certain extensions that place their
573 this is not compatible with certain extensions that place their
574 metadata under the .hg directory, such as mq.
574 metadata under the .hg directory, such as mq.
575
575
576 If you use the -r option to clone up to a specific revision, no
576 If you use the -r option to clone up to a specific revision, no
577 subsequent revisions will be present in the cloned repository.
577 subsequent revisions will be present in the cloned repository.
578 This option implies --pull, even on local repositories.
578 This option implies --pull, even on local repositories.
579
579
580 If the -U option is used, the new clone will contain only a repository
580 If the -U option is used, the new clone will contain only a repository
581 (.hg) and no working copy (the working copy parent is the null revision).
581 (.hg) and no working copy (the working copy parent is the null revision).
582
582
583 See pull for valid source format details.
583 See pull for valid source format details.
584
584
585 It is possible to specify an ssh:// URL as the destination, but no
585 It is possible to specify an ssh:// URL as the destination, but no
586 .hg/hgrc and working directory will be created on the remote side.
586 .hg/hgrc and working directory will be created on the remote side.
587 Look at the help text for the pull command for important details
587 Look at the help text for the pull command for important details
588 about ssh:// URLs.
588 about ssh:// URLs.
589 """
589 """
590 cmdutil.setremoteconfig(ui, opts)
590 cmdutil.setremoteconfig(ui, opts)
591 hg.clone(ui, source, dest,
591 hg.clone(ui, source, dest,
592 pull=opts.get('pull'),
592 pull=opts.get('pull'),
593 stream=opts.get('uncompressed'),
593 stream=opts.get('uncompressed'),
594 rev=opts.get('rev'),
594 rev=opts.get('rev'),
595 update=not opts.get('noupdate'))
595 update=not opts.get('noupdate'))
596
596
597 def commit(ui, repo, *pats, **opts):
597 def commit(ui, repo, *pats, **opts):
598 """commit the specified files or all outstanding changes
598 """commit the specified files or all outstanding changes
599
599
600 Commit changes to the given files into the repository.
600 Commit changes to the given files into the repository.
601
601
602 If a list of files is omitted, all changes reported by "hg status"
602 If a list of files is omitted, all changes reported by "hg status"
603 will be committed.
603 will be committed.
604
604
605 If you are committing the result of a merge, do not provide any
605 If you are committing the result of a merge, do not provide any
606 file names or -I/-X filters.
606 file names or -I/-X filters.
607
607
608 If no commit message is specified, the configured editor is started to
608 If no commit message is specified, the configured editor is started to
609 enter a message.
609 enter a message.
610
610
611 See 'hg help dates' for a list of formats valid for -d/--date.
611 See 'hg help dates' for a list of formats valid for -d/--date.
612 """
612 """
613 def commitfunc(ui, repo, message, match, opts):
613 def commitfunc(ui, repo, message, match, opts):
614 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
614 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
615 match, force_editor=opts.get('force_editor'))
615 match, force_editor=opts.get('force_editor'))
616
616
617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
618 if not node:
618 if not node:
619 return
619 return
620 cl = repo.changelog
620 cl = repo.changelog
621 rev = cl.rev(node)
621 rev = cl.rev(node)
622 parents = cl.parentrevs(rev)
622 parents = cl.parentrevs(rev)
623 if rev - 1 in parents:
623 if rev - 1 in parents:
624 # one of the parents was the old tip
624 # one of the parents was the old tip
625 pass
625 pass
626 elif (parents == (nullrev, nullrev) or
626 elif (parents == (nullrev, nullrev) or
627 len(cl.heads(cl.node(parents[0]))) > 1 and
627 len(cl.heads(cl.node(parents[0]))) > 1 and
628 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
628 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
629 ui.status(_('created new head\n'))
629 ui.status(_('created new head\n'))
630
630
631 if ui.debugflag:
631 if ui.debugflag:
632 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
632 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
633 elif ui.verbose:
633 elif ui.verbose:
634 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
634 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
635
635
636 def copy(ui, repo, *pats, **opts):
636 def copy(ui, repo, *pats, **opts):
637 """mark files as copied for the next commit
637 """mark files as copied for the next commit
638
638
639 Mark dest as having copies of source files. If dest is a
639 Mark dest as having copies of source files. If dest is a
640 directory, copies are put in that directory. If dest is a file,
640 directory, copies are put in that directory. If dest is a file,
641 there can only be one source.
641 there can only be one source.
642
642
643 By default, this command copies the contents of files as they
643 By default, this command copies the contents of files as they
644 stand in the working directory. If invoked with --after, the
644 stand in the working directory. If invoked with --after, the
645 operation is recorded, but no copying is performed.
645 operation is recorded, but no copying is performed.
646
646
647 This command takes effect in the next commit. To undo a copy
647 This command takes effect in the next commit. To undo a copy
648 before that, see hg revert.
648 before that, see hg revert.
649 """
649 """
650 wlock = repo.wlock(False)
650 wlock = repo.wlock(False)
651 try:
651 try:
652 return cmdutil.copy(ui, repo, pats, opts)
652 return cmdutil.copy(ui, repo, pats, opts)
653 finally:
653 finally:
654 del wlock
654 del wlock
655
655
656 def debugancestor(ui, repo, *args):
656 def debugancestor(ui, repo, *args):
657 """find the ancestor revision of two revisions in a given index"""
657 """find the ancestor revision of two revisions in a given index"""
658 if len(args) == 3:
658 if len(args) == 3:
659 index, rev1, rev2 = args
659 index, rev1, rev2 = args
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
661 lookup = r.lookup
661 lookup = r.lookup
662 elif len(args) == 2:
662 elif len(args) == 2:
663 if not repo:
663 if not repo:
664 raise util.Abort(_("There is no Mercurial repository here "
664 raise util.Abort(_("There is no Mercurial repository here "
665 "(.hg not found)"))
665 "(.hg not found)"))
666 rev1, rev2 = args
666 rev1, rev2 = args
667 r = repo.changelog
667 r = repo.changelog
668 lookup = repo.lookup
668 lookup = repo.lookup
669 else:
669 else:
670 raise util.Abort(_('either two or three arguments required'))
670 raise util.Abort(_('either two or three arguments required'))
671 a = r.ancestor(lookup(rev1), lookup(rev2))
671 a = r.ancestor(lookup(rev1), lookup(rev2))
672 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
672 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
673
673
674 def debugcomplete(ui, cmd='', **opts):
674 def debugcomplete(ui, cmd='', **opts):
675 """returns the completion list associated with the given command"""
675 """returns the completion list associated with the given command"""
676
676
677 if opts.get('options'):
677 if opts.get('options'):
678 options = []
678 options = []
679 otables = [globalopts]
679 otables = [globalopts]
680 if cmd:
680 if cmd:
681 aliases, entry = cmdutil.findcmd(cmd, table, False)
681 aliases, entry = cmdutil.findcmd(cmd, table, False)
682 otables.append(entry[1])
682 otables.append(entry[1])
683 for t in otables:
683 for t in otables:
684 for o in t:
684 for o in t:
685 if o[0]:
685 if o[0]:
686 options.append('-%s' % o[0])
686 options.append('-%s' % o[0])
687 options.append('--%s' % o[1])
687 options.append('--%s' % o[1])
688 ui.write("%s\n" % "\n".join(options))
688 ui.write("%s\n" % "\n".join(options))
689 return
689 return
690
690
691 ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table))))
691 ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table))))
692
692
693 def debugfsinfo(ui, path = "."):
693 def debugfsinfo(ui, path = "."):
694 file('.debugfsinfo', 'w').write('')
694 file('.debugfsinfo', 'w').write('')
695 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
695 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
696 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
696 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
697 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
697 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
698 and 'yes' or 'no'))
698 and 'yes' or 'no'))
699 os.unlink('.debugfsinfo')
699 os.unlink('.debugfsinfo')
700
700
701 def debugrebuildstate(ui, repo, rev="tip"):
701 def debugrebuildstate(ui, repo, rev="tip"):
702 """rebuild the dirstate as it would look like for the given revision"""
702 """rebuild the dirstate as it would look like for the given revision"""
703 ctx = repo[rev]
703 ctx = repo[rev]
704 wlock = repo.wlock()
704 wlock = repo.wlock()
705 try:
705 try:
706 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
706 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
707 finally:
707 finally:
708 del wlock
708 del wlock
709
709
710 def debugcheckstate(ui, repo):
710 def debugcheckstate(ui, repo):
711 """validate the correctness of the current dirstate"""
711 """validate the correctness of the current dirstate"""
712 parent1, parent2 = repo.dirstate.parents()
712 parent1, parent2 = repo.dirstate.parents()
713 m1 = repo[parent1].manifest()
713 m1 = repo[parent1].manifest()
714 m2 = repo[parent2].manifest()
714 m2 = repo[parent2].manifest()
715 errors = 0
715 errors = 0
716 for f in repo.dirstate:
716 for f in repo.dirstate:
717 state = repo.dirstate[f]
717 state = repo.dirstate[f]
718 if state in "nr" and f not in m1:
718 if state in "nr" and f not in m1:
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "a" and f in m1:
721 if state in "a" and f in m1:
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
723 errors += 1
723 errors += 1
724 if state in "m" and f not in m1 and f not in m2:
724 if state in "m" and f not in m1 and f not in m2:
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
726 (f, state))
726 (f, state))
727 errors += 1
727 errors += 1
728 for f in m1:
728 for f in m1:
729 state = repo.dirstate[f]
729 state = repo.dirstate[f]
730 if state not in "nrm":
730 if state not in "nrm":
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
732 errors += 1
732 errors += 1
733 if errors:
733 if errors:
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
735 raise util.Abort(error)
735 raise util.Abort(error)
736
736
737 def showconfig(ui, repo, *values, **opts):
737 def showconfig(ui, repo, *values, **opts):
738 """show combined config settings from all hgrc files
738 """show combined config settings from all hgrc files
739
739
740 With no args, print names and values of all config items.
740 With no args, print names and values of all config items.
741
741
742 With one arg of the form section.name, print just the value of
742 With one arg of the form section.name, print just the value of
743 that config item.
743 that config item.
744
744
745 With multiple args, print names and values of all config items
745 With multiple args, print names and values of all config items
746 with matching section names."""
746 with matching section names."""
747
747
748 untrusted = bool(opts.get('untrusted'))
748 untrusted = bool(opts.get('untrusted'))
749 if values:
749 if values:
750 if len([v for v in values if '.' in v]) > 1:
750 if len([v for v in values if '.' in v]) > 1:
751 raise util.Abort(_('only one config item permitted'))
751 raise util.Abort(_('only one config item permitted'))
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
753 sectname = section + '.' + name
753 sectname = section + '.' + name
754 if values:
754 if values:
755 for v in values:
755 for v in values:
756 if v == section:
756 if v == section:
757 ui.write('%s=%s\n' % (sectname, value))
757 ui.write('%s=%s\n' % (sectname, value))
758 elif v == sectname:
758 elif v == sectname:
759 ui.write(value, '\n')
759 ui.write(value, '\n')
760 else:
760 else:
761 ui.write('%s=%s\n' % (sectname, value))
761 ui.write('%s=%s\n' % (sectname, value))
762
762
763 def debugsetparents(ui, repo, rev1, rev2=None):
763 def debugsetparents(ui, repo, rev1, rev2=None):
764 """manually set the parents of the current working directory
764 """manually set the parents of the current working directory
765
765
766 This is useful for writing repository conversion tools, but should
766 This is useful for writing repository conversion tools, but should
767 be used with care.
767 be used with care.
768 """
768 """
769
769
770 if not rev2:
770 if not rev2:
771 rev2 = hex(nullid)
771 rev2 = hex(nullid)
772
772
773 wlock = repo.wlock()
773 wlock = repo.wlock()
774 try:
774 try:
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
776 finally:
776 finally:
777 del wlock
777 del wlock
778
778
779 def debugstate(ui, repo, nodates=None):
779 def debugstate(ui, repo, nodates=None):
780 """show the contents of the current dirstate"""
780 """show the contents of the current dirstate"""
781 timestr = ""
781 timestr = ""
782 showdate = not nodates
782 showdate = not nodates
783 for file_, ent in util.sort(repo.dirstate._map.items()):
783 for file_, ent in util.sort(repo.dirstate._map.items()):
784 if showdate:
784 if showdate:
785 if ent[3] == -1:
785 if ent[3] == -1:
786 # Pad or slice to locale representation
786 # Pad or slice to locale representation
787 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
787 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
788 timestr = 'unset'
788 timestr = 'unset'
789 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
789 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
790 else:
790 else:
791 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
791 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
792 if ent[1] & 020000:
792 if ent[1] & 020000:
793 mode = 'lnk'
793 mode = 'lnk'
794 else:
794 else:
795 mode = '%3o' % (ent[1] & 0777)
795 mode = '%3o' % (ent[1] & 0777)
796 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
796 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
797 for f in repo.dirstate.copies():
797 for f in repo.dirstate.copies():
798 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
798 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
799
799
800 def debugdata(ui, file_, rev):
800 def debugdata(ui, file_, rev):
801 """dump the contents of a data file revision"""
801 """dump the contents of a data file revision"""
802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
803 try:
803 try:
804 ui.write(r.revision(r.lookup(rev)))
804 ui.write(r.revision(r.lookup(rev)))
805 except KeyError:
805 except KeyError:
806 raise util.Abort(_('invalid revision identifier %s') % rev)
806 raise util.Abort(_('invalid revision identifier %s') % rev)
807
807
808 def debugdate(ui, date, range=None, **opts):
808 def debugdate(ui, date, range=None, **opts):
809 """parse and display a date"""
809 """parse and display a date"""
810 if opts["extended"]:
810 if opts["extended"]:
811 d = util.parsedate(date, util.extendeddateformats)
811 d = util.parsedate(date, util.extendeddateformats)
812 else:
812 else:
813 d = util.parsedate(date)
813 d = util.parsedate(date)
814 ui.write("internal: %s %s\n" % d)
814 ui.write("internal: %s %s\n" % d)
815 ui.write("standard: %s\n" % util.datestr(d))
815 ui.write("standard: %s\n" % util.datestr(d))
816 if range:
816 if range:
817 m = util.matchdate(range)
817 m = util.matchdate(range)
818 ui.write("match: %s\n" % m(d[0]))
818 ui.write("match: %s\n" % m(d[0]))
819
819
820 def debugindex(ui, file_):
820 def debugindex(ui, file_):
821 """dump the contents of an index file"""
821 """dump the contents of an index file"""
822 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
822 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
823 ui.write(" rev offset length base linkrev" +
823 ui.write(" rev offset length base linkrev" +
824 " nodeid p1 p2\n")
824 " nodeid p1 p2\n")
825 for i in r:
825 for i in r:
826 node = r.node(i)
826 node = r.node(i)
827 try:
827 try:
828 pp = r.parents(node)
828 pp = r.parents(node)
829 except:
829 except:
830 pp = [nullid, nullid]
830 pp = [nullid, nullid]
831 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
831 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
832 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
832 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
833 short(node), short(pp[0]), short(pp[1])))
833 short(node), short(pp[0]), short(pp[1])))
834
834
835 def debugindexdot(ui, file_):
835 def debugindexdot(ui, file_):
836 """dump an index DAG as a .dot file"""
836 """dump an index DAG as a .dot file"""
837 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
837 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
838 ui.write("digraph G {\n")
838 ui.write("digraph G {\n")
839 for i in r:
839 for i in r:
840 node = r.node(i)
840 node = r.node(i)
841 pp = r.parents(node)
841 pp = r.parents(node)
842 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
842 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
843 if pp[1] != nullid:
843 if pp[1] != nullid:
844 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
844 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
845 ui.write("}\n")
845 ui.write("}\n")
846
846
847 def debuginstall(ui):
847 def debuginstall(ui):
848 '''test Mercurial installation'''
848 '''test Mercurial installation'''
849
849
850 def writetemp(contents):
850 def writetemp(contents):
851 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
851 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
852 f = os.fdopen(fd, "wb")
852 f = os.fdopen(fd, "wb")
853 f.write(contents)
853 f.write(contents)
854 f.close()
854 f.close()
855 return name
855 return name
856
856
857 problems = 0
857 problems = 0
858
858
859 # encoding
859 # encoding
860 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
860 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
861 try:
861 try:
862 util.fromlocal("test")
862 util.fromlocal("test")
863 except util.Abort, inst:
863 except util.Abort, inst:
864 ui.write(" %s\n" % inst)
864 ui.write(" %s\n" % inst)
865 ui.write(_(" (check that your locale is properly set)\n"))
865 ui.write(_(" (check that your locale is properly set)\n"))
866 problems += 1
866 problems += 1
867
867
868 # compiled modules
868 # compiled modules
869 ui.status(_("Checking extensions...\n"))
869 ui.status(_("Checking extensions...\n"))
870 try:
870 try:
871 import bdiff, mpatch, base85
871 import bdiff, mpatch, base85
872 except Exception, inst:
872 except Exception, inst:
873 ui.write(" %s\n" % inst)
873 ui.write(" %s\n" % inst)
874 ui.write(_(" One or more extensions could not be found"))
874 ui.write(_(" One or more extensions could not be found"))
875 ui.write(_(" (check that you compiled the extensions)\n"))
875 ui.write(_(" (check that you compiled the extensions)\n"))
876 problems += 1
876 problems += 1
877
877
878 # templates
878 # templates
879 ui.status(_("Checking templates...\n"))
879 ui.status(_("Checking templates...\n"))
880 try:
880 try:
881 import templater
881 import templater
882 t = templater.templater(templater.templatepath("map-cmdline.default"))
882 t = templater.templater(templater.templatepath("map-cmdline.default"))
883 except Exception, inst:
883 except Exception, inst:
884 ui.write(" %s\n" % inst)
884 ui.write(" %s\n" % inst)
885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
886 problems += 1
886 problems += 1
887
887
888 # patch
888 # patch
889 ui.status(_("Checking patch...\n"))
889 ui.status(_("Checking patch...\n"))
890 patchproblems = 0
890 patchproblems = 0
891 a = "1\n2\n3\n4\n"
891 a = "1\n2\n3\n4\n"
892 b = "1\n2\n3\ninsert\n4\n"
892 b = "1\n2\n3\ninsert\n4\n"
893 fa = writetemp(a)
893 fa = writetemp(a)
894 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
894 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
895 os.path.basename(fa))
895 os.path.basename(fa))
896 fd = writetemp(d)
896 fd = writetemp(d)
897
897
898 files = {}
898 files = {}
899 try:
899 try:
900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
901 except util.Abort, e:
901 except util.Abort, e:
902 ui.write(_(" patch call failed:\n"))
902 ui.write(_(" patch call failed:\n"))
903 ui.write(" " + str(e) + "\n")
903 ui.write(" " + str(e) + "\n")
904 patchproblems += 1
904 patchproblems += 1
905 else:
905 else:
906 if list(files) != [os.path.basename(fa)]:
906 if list(files) != [os.path.basename(fa)]:
907 ui.write(_(" unexpected patch output!\n"))
907 ui.write(_(" unexpected patch output!\n"))
908 patchproblems += 1
908 patchproblems += 1
909 a = file(fa).read()
909 a = file(fa).read()
910 if a != b:
910 if a != b:
911 ui.write(_(" patch test failed!\n"))
911 ui.write(_(" patch test failed!\n"))
912 patchproblems += 1
912 patchproblems += 1
913
913
914 if patchproblems:
914 if patchproblems:
915 if ui.config('ui', 'patch'):
915 if ui.config('ui', 'patch'):
916 ui.write(_(" (Current patch tool may be incompatible with patch,"
916 ui.write(_(" (Current patch tool may be incompatible with patch,"
917 " or misconfigured. Please check your .hgrc file)\n"))
917 " or misconfigured. Please check your .hgrc file)\n"))
918 else:
918 else:
919 ui.write(_(" Internal patcher failure, please report this error"
919 ui.write(_(" Internal patcher failure, please report this error"
920 " to http://www.selenic.com/mercurial/bts\n"))
920 " to http://www.selenic.com/mercurial/bts\n"))
921 problems += patchproblems
921 problems += patchproblems
922
922
923 os.unlink(fa)
923 os.unlink(fa)
924 os.unlink(fd)
924 os.unlink(fd)
925
925
926 # editor
926 # editor
927 ui.status(_("Checking commit editor...\n"))
927 ui.status(_("Checking commit editor...\n"))
928 editor = ui.geteditor()
928 editor = ui.geteditor()
929 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
929 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
930 if not cmdpath:
930 if not cmdpath:
931 if editor == 'vi':
931 if editor == 'vi':
932 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
932 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
934 else:
934 else:
935 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
935 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
936 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
936 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
937 problems += 1
937 problems += 1
938
938
939 # check username
939 # check username
940 ui.status(_("Checking username...\n"))
940 ui.status(_("Checking username...\n"))
941 user = os.environ.get("HGUSER")
941 user = os.environ.get("HGUSER")
942 if user is None:
942 if user is None:
943 user = ui.config("ui", "username")
943 user = ui.config("ui", "username")
944 if user is None:
944 if user is None:
945 user = os.environ.get("EMAIL")
945 user = os.environ.get("EMAIL")
946 if not user:
946 if not user:
947 ui.warn(" ")
947 ui.warn(" ")
948 ui.username()
948 ui.username()
949 ui.write(_(" (specify a username in your .hgrc file)\n"))
949 ui.write(_(" (specify a username in your .hgrc file)\n"))
950
950
951 if not problems:
951 if not problems:
952 ui.status(_("No problems detected\n"))
952 ui.status(_("No problems detected\n"))
953 else:
953 else:
954 ui.write(_("%s problems detected,"
954 ui.write(_("%s problems detected,"
955 " please check your install!\n") % problems)
955 " please check your install!\n") % problems)
956
956
957 return problems
957 return problems
958
958
959 def debugrename(ui, repo, file1, *pats, **opts):
959 def debugrename(ui, repo, file1, *pats, **opts):
960 """dump rename information"""
960 """dump rename information"""
961
961
962 ctx = repo[opts.get('rev')]
962 ctx = repo[opts.get('rev')]
963 m = cmdutil.match(repo, (file1,) + pats, opts)
963 m = cmdutil.match(repo, (file1,) + pats, opts)
964 for abs in ctx.walk(m):
964 for abs in ctx.walk(m):
965 fctx = ctx[abs]
965 fctx = ctx[abs]
966 o = fctx.filelog().renamed(fctx.filenode())
966 o = fctx.filelog().renamed(fctx.filenode())
967 rel = m.rel(abs)
967 rel = m.rel(abs)
968 if o:
968 if o:
969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
970 else:
970 else:
971 ui.write(_("%s not renamed\n") % rel)
971 ui.write(_("%s not renamed\n") % rel)
972
972
973 def debugwalk(ui, repo, *pats, **opts):
973 def debugwalk(ui, repo, *pats, **opts):
974 """show how files match on given patterns"""
974 """show how files match on given patterns"""
975 m = cmdutil.match(repo, pats, opts)
975 m = cmdutil.match(repo, pats, opts)
976 items = list(repo.walk(m))
976 items = list(repo.walk(m))
977 if not items:
977 if not items:
978 return
978 return
979 fmt = 'f %%-%ds %%-%ds %%s' % (
979 fmt = 'f %%-%ds %%-%ds %%s' % (
980 max([len(abs) for abs in items]),
980 max([len(abs) for abs in items]),
981 max([len(m.rel(abs)) for abs in items]))
981 max([len(m.rel(abs)) for abs in items]))
982 for abs in items:
982 for abs in items:
983 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
983 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
984 ui.write("%s\n" % line.rstrip())
984 ui.write("%s\n" % line.rstrip())
985
985
986 def diff(ui, repo, *pats, **opts):
986 def diff(ui, repo, *pats, **opts):
987 """diff repository (or selected files)
987 """diff repository (or selected files)
988
988
989 Show differences between revisions for the specified files.
989 Show differences between revisions for the specified files.
990
990
991 Differences between files are shown using the unified diff format.
991 Differences between files are shown using the unified diff format.
992
992
993 NOTE: diff may generate unexpected results for merges, as it will
993 NOTE: diff may generate unexpected results for merges, as it will
994 default to comparing against the working directory's first parent
994 default to comparing against the working directory's first parent
995 changeset if no revisions are specified.
995 changeset if no revisions are specified.
996
996
997 When two revision arguments are given, then changes are shown
997 When two revision arguments are given, then changes are shown
998 between those revisions. If only one revision is specified then
998 between those revisions. If only one revision is specified then
999 that revision is compared to the working directory, and, when no
999 that revision is compared to the working directory, and, when no
1000 revisions are specified, the working directory files are compared
1000 revisions are specified, the working directory files are compared
1001 to its parent.
1001 to its parent.
1002
1002
1003 Without the -a option, diff will avoid generating diffs of files
1003 Without the -a option, diff will avoid generating diffs of files
1004 it detects as binary. With -a, diff will generate a diff anyway,
1004 it detects as binary. With -a, diff will generate a diff anyway,
1005 probably with undesirable results.
1005 probably with undesirable results.
1006 """
1006 """
1007 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1007 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1008
1008
1009 m = cmdutil.match(repo, pats, opts)
1009 m = cmdutil.match(repo, pats, opts)
1010 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1010 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1011
1011
1012 def export(ui, repo, *changesets, **opts):
1012 def export(ui, repo, *changesets, **opts):
1013 """dump the header and diffs for one or more changesets
1013 """dump the header and diffs for one or more changesets
1014
1014
1015 Print the changeset header and diffs for one or more revisions.
1015 Print the changeset header and diffs for one or more revisions.
1016
1016
1017 The information shown in the changeset header is: author,
1017 The information shown in the changeset header is: author,
1018 changeset hash, parent(s) and commit comment.
1018 changeset hash, parent(s) and commit comment.
1019
1019
1020 NOTE: export may generate unexpected diff output for merge changesets,
1020 NOTE: export may generate unexpected diff output for merge changesets,
1021 as it will compare the merge changeset against its first parent only.
1021 as it will compare the merge changeset against its first parent only.
1022
1022
1023 Output may be to a file, in which case the name of the file is
1023 Output may be to a file, in which case the name of the file is
1024 given using a format string. The formatting rules are as follows:
1024 given using a format string. The formatting rules are as follows:
1025
1025
1026 %% literal "%" character
1026 %% literal "%" character
1027 %H changeset hash (40 bytes of hexadecimal)
1027 %H changeset hash (40 bytes of hexadecimal)
1028 %N number of patches being generated
1028 %N number of patches being generated
1029 %R changeset revision number
1029 %R changeset revision number
1030 %b basename of the exporting repository
1030 %b basename of the exporting repository
1031 %h short-form changeset hash (12 bytes of hexadecimal)
1031 %h short-form changeset hash (12 bytes of hexadecimal)
1032 %n zero-padded sequence number, starting at 1
1032 %n zero-padded sequence number, starting at 1
1033 %r zero-padded changeset revision number
1033 %r zero-padded changeset revision number
1034
1034
1035 Without the -a option, export will avoid generating diffs of files
1035 Without the -a option, export will avoid generating diffs of files
1036 it detects as binary. With -a, export will generate a diff anyway,
1036 it detects as binary. With -a, export will generate a diff anyway,
1037 probably with undesirable results.
1037 probably with undesirable results.
1038
1038
1039 With the --switch-parent option, the diff will be against the second
1039 With the --switch-parent option, the diff will be against the second
1040 parent. It can be useful to review a merge.
1040 parent. It can be useful to review a merge.
1041 """
1041 """
1042 if not changesets:
1042 if not changesets:
1043 raise util.Abort(_("export requires at least one changeset"))
1043 raise util.Abort(_("export requires at least one changeset"))
1044 revs = cmdutil.revrange(repo, changesets)
1044 revs = cmdutil.revrange(repo, changesets)
1045 if len(revs) > 1:
1045 if len(revs) > 1:
1046 ui.note(_('exporting patches:\n'))
1046 ui.note(_('exporting patches:\n'))
1047 else:
1047 else:
1048 ui.note(_('exporting patch:\n'))
1048 ui.note(_('exporting patch:\n'))
1049 patch.export(repo, revs, template=opts.get('output'),
1049 patch.export(repo, revs, template=opts.get('output'),
1050 switch_parent=opts.get('switch_parent'),
1050 switch_parent=opts.get('switch_parent'),
1051 opts=patch.diffopts(ui, opts))
1051 opts=patch.diffopts(ui, opts))
1052
1052
1053 def grep(ui, repo, pattern, *pats, **opts):
1053 def grep(ui, repo, pattern, *pats, **opts):
1054 """search for a pattern in specified files and revisions
1054 """search for a pattern in specified files and revisions
1055
1055
1056 Search revisions of files for a regular expression.
1056 Search revisions of files for a regular expression.
1057
1057
1058 This command behaves differently than Unix grep. It only accepts
1058 This command behaves differently than Unix grep. It only accepts
1059 Python/Perl regexps. It searches repository history, not the
1059 Python/Perl regexps. It searches repository history, not the
1060 working directory. It always prints the revision number in which
1060 working directory. It always prints the revision number in which
1061 a match appears.
1061 a match appears.
1062
1062
1063 By default, grep only prints output for the first revision of a
1063 By default, grep only prints output for the first revision of a
1064 file in which it finds a match. To get it to print every revision
1064 file in which it finds a match. To get it to print every revision
1065 that contains a change in match status ("-" for a match that
1065 that contains a change in match status ("-" for a match that
1066 becomes a non-match, or "+" for a non-match that becomes a match),
1066 becomes a non-match, or "+" for a non-match that becomes a match),
1067 use the --all flag.
1067 use the --all flag.
1068 """
1068 """
1069 reflags = 0
1069 reflags = 0
1070 if opts.get('ignore_case'):
1070 if opts.get('ignore_case'):
1071 reflags |= re.I
1071 reflags |= re.I
1072 try:
1072 try:
1073 regexp = re.compile(pattern, reflags)
1073 regexp = re.compile(pattern, reflags)
1074 except Exception, inst:
1074 except Exception, inst:
1075 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1075 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1076 return None
1076 return None
1077 sep, eol = ':', '\n'
1077 sep, eol = ':', '\n'
1078 if opts.get('print0'):
1078 if opts.get('print0'):
1079 sep = eol = '\0'
1079 sep = eol = '\0'
1080
1080
1081 fcache = {}
1081 fcache = {}
1082 def getfile(fn):
1082 def getfile(fn):
1083 if fn not in fcache:
1083 if fn not in fcache:
1084 fcache[fn] = repo.file(fn)
1084 fcache[fn] = repo.file(fn)
1085 return fcache[fn]
1085 return fcache[fn]
1086
1086
1087 def matchlines(body):
1087 def matchlines(body):
1088 begin = 0
1088 begin = 0
1089 linenum = 0
1089 linenum = 0
1090 while True:
1090 while True:
1091 match = regexp.search(body, begin)
1091 match = regexp.search(body, begin)
1092 if not match:
1092 if not match:
1093 break
1093 break
1094 mstart, mend = match.span()
1094 mstart, mend = match.span()
1095 linenum += body.count('\n', begin, mstart) + 1
1095 linenum += body.count('\n', begin, mstart) + 1
1096 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1096 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1097 begin = body.find('\n', mend) + 1 or len(body)
1097 begin = body.find('\n', mend) + 1 or len(body)
1098 lend = begin - 1
1098 lend = begin - 1
1099 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1099 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1100
1100
1101 class linestate(object):
1101 class linestate(object):
1102 def __init__(self, line, linenum, colstart, colend):
1102 def __init__(self, line, linenum, colstart, colend):
1103 self.line = line
1103 self.line = line
1104 self.linenum = linenum
1104 self.linenum = linenum
1105 self.colstart = colstart
1105 self.colstart = colstart
1106 self.colend = colend
1106 self.colend = colend
1107
1107
1108 def __hash__(self):
1108 def __hash__(self):
1109 return hash((self.linenum, self.line))
1109 return hash((self.linenum, self.line))
1110
1110
1111 def __eq__(self, other):
1111 def __eq__(self, other):
1112 return self.line == other.line
1112 return self.line == other.line
1113
1113
1114 matches = {}
1114 matches = {}
1115 copies = {}
1115 copies = {}
1116 def grepbody(fn, rev, body):
1116 def grepbody(fn, rev, body):
1117 matches[rev].setdefault(fn, [])
1117 matches[rev].setdefault(fn, [])
1118 m = matches[rev][fn]
1118 m = matches[rev][fn]
1119 for lnum, cstart, cend, line in matchlines(body):
1119 for lnum, cstart, cend, line in matchlines(body):
1120 s = linestate(line, lnum, cstart, cend)
1120 s = linestate(line, lnum, cstart, cend)
1121 m.append(s)
1121 m.append(s)
1122
1122
1123 def difflinestates(a, b):
1123 def difflinestates(a, b):
1124 sm = difflib.SequenceMatcher(None, a, b)
1124 sm = difflib.SequenceMatcher(None, a, b)
1125 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1125 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1126 if tag == 'insert':
1126 if tag == 'insert':
1127 for i in xrange(blo, bhi):
1127 for i in xrange(blo, bhi):
1128 yield ('+', b[i])
1128 yield ('+', b[i])
1129 elif tag == 'delete':
1129 elif tag == 'delete':
1130 for i in xrange(alo, ahi):
1130 for i in xrange(alo, ahi):
1131 yield ('-', a[i])
1131 yield ('-', a[i])
1132 elif tag == 'replace':
1132 elif tag == 'replace':
1133 for i in xrange(alo, ahi):
1133 for i in xrange(alo, ahi):
1134 yield ('-', a[i])
1134 yield ('-', a[i])
1135 for i in xrange(blo, bhi):
1135 for i in xrange(blo, bhi):
1136 yield ('+', b[i])
1136 yield ('+', b[i])
1137
1137
1138 prev = {}
1138 prev = {}
1139 def display(fn, rev, states, prevstates):
1139 def display(fn, rev, states, prevstates):
1140 datefunc = ui.quiet and util.shortdate or util.datestr
1140 datefunc = ui.quiet and util.shortdate or util.datestr
1141 found = False
1141 found = False
1142 filerevmatches = {}
1142 filerevmatches = {}
1143 r = prev.get(fn, -1)
1143 r = prev.get(fn, -1)
1144 if opts.get('all'):
1144 if opts.get('all'):
1145 iter = difflinestates(states, prevstates)
1145 iter = difflinestates(states, prevstates)
1146 else:
1146 else:
1147 iter = [('', l) for l in prevstates]
1147 iter = [('', l) for l in prevstates]
1148 for change, l in iter:
1148 for change, l in iter:
1149 cols = [fn, str(r)]
1149 cols = [fn, str(r)]
1150 if opts.get('line_number'):
1150 if opts.get('line_number'):
1151 cols.append(str(l.linenum))
1151 cols.append(str(l.linenum))
1152 if opts.get('all'):
1152 if opts.get('all'):
1153 cols.append(change)
1153 cols.append(change)
1154 if opts.get('user'):
1154 if opts.get('user'):
1155 cols.append(ui.shortuser(get(r)[1]))
1155 cols.append(ui.shortuser(get(r)[1]))
1156 if opts.get('date'):
1156 if opts.get('date'):
1157 cols.append(datefunc(get(r)[2]))
1157 cols.append(datefunc(get(r)[2]))
1158 if opts.get('files_with_matches'):
1158 if opts.get('files_with_matches'):
1159 c = (fn, r)
1159 c = (fn, r)
1160 if c in filerevmatches:
1160 if c in filerevmatches:
1161 continue
1161 continue
1162 filerevmatches[c] = 1
1162 filerevmatches[c] = 1
1163 else:
1163 else:
1164 cols.append(l.line)
1164 cols.append(l.line)
1165 ui.write(sep.join(cols), eol)
1165 ui.write(sep.join(cols), eol)
1166 found = True
1166 found = True
1167 return found
1167 return found
1168
1168
1169 fstate = {}
1169 fstate = {}
1170 skip = {}
1170 skip = {}
1171 get = util.cachefunc(lambda r: repo[r].changeset())
1171 get = util.cachefunc(lambda r: repo[r].changeset())
1172 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1172 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1173 found = False
1173 found = False
1174 follow = opts.get('follow')
1174 follow = opts.get('follow')
1175 for st, rev, fns in changeiter:
1175 for st, rev, fns in changeiter:
1176 if st == 'window':
1176 if st == 'window':
1177 matches.clear()
1177 matches.clear()
1178 elif st == 'add':
1178 elif st == 'add':
1179 ctx = repo[rev]
1179 ctx = repo[rev]
1180 matches[rev] = {}
1180 matches[rev] = {}
1181 for fn in fns:
1181 for fn in fns:
1182 if fn in skip:
1182 if fn in skip:
1183 continue
1183 continue
1184 try:
1184 try:
1185 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1185 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1186 fstate.setdefault(fn, [])
1186 fstate.setdefault(fn, [])
1187 if follow:
1187 if follow:
1188 copied = getfile(fn).renamed(ctx.filenode(fn))
1188 copied = getfile(fn).renamed(ctx.filenode(fn))
1189 if copied:
1189 if copied:
1190 copies.setdefault(rev, {})[fn] = copied[0]
1190 copies.setdefault(rev, {})[fn] = copied[0]
1191 except revlog.LookupError:
1191 except revlog.LookupError:
1192 pass
1192 pass
1193 elif st == 'iter':
1193 elif st == 'iter':
1194 for fn, m in util.sort(matches[rev].items()):
1194 for fn, m in util.sort(matches[rev].items()):
1195 copy = copies.get(rev, {}).get(fn)
1195 copy = copies.get(rev, {}).get(fn)
1196 if fn in skip:
1196 if fn in skip:
1197 if copy:
1197 if copy:
1198 skip[copy] = True
1198 skip[copy] = True
1199 continue
1199 continue
1200 if fn in prev or fstate[fn]:
1200 if fn in prev or fstate[fn]:
1201 r = display(fn, rev, m, fstate[fn])
1201 r = display(fn, rev, m, fstate[fn])
1202 found = found or r
1202 found = found or r
1203 if r and not opts.get('all'):
1203 if r and not opts.get('all'):
1204 skip[fn] = True
1204 skip[fn] = True
1205 if copy:
1205 if copy:
1206 skip[copy] = True
1206 skip[copy] = True
1207 fstate[fn] = m
1207 fstate[fn] = m
1208 if copy:
1208 if copy:
1209 fstate[copy] = m
1209 fstate[copy] = m
1210 prev[fn] = rev
1210 prev[fn] = rev
1211
1211
1212 for fn, state in util.sort(fstate.items()):
1212 for fn, state in util.sort(fstate.items()):
1213 if fn in skip:
1213 if fn in skip:
1214 continue
1214 continue
1215 if fn not in copies.get(prev[fn], {}):
1215 if fn not in copies.get(prev[fn], {}):
1216 found = display(fn, rev, {}, state) or found
1216 found = display(fn, rev, {}, state) or found
1217 return (not found and 1) or 0
1217 return (not found and 1) or 0
1218
1218
1219 def heads(ui, repo, *branchrevs, **opts):
1219 def heads(ui, repo, *branchrevs, **opts):
1220 """show current repository heads or show branch heads
1220 """show current repository heads or show branch heads
1221
1221
1222 With no arguments, show all repository head changesets.
1222 With no arguments, show all repository head changesets.
1223
1223
1224 If branch or revisions names are given this will show the heads of
1224 If branch or revisions names are given this will show the heads of
1225 the specified branches or the branches those revisions are tagged
1225 the specified branches or the branches those revisions are tagged
1226 with.
1226 with.
1227
1227
1228 Repository "heads" are changesets that don't have child
1228 Repository "heads" are changesets that don't have child
1229 changesets. They are where development generally takes place and
1229 changesets. They are where development generally takes place and
1230 are the usual targets for update and merge operations.
1230 are the usual targets for update and merge operations.
1231
1231
1232 Branch heads are changesets that have a given branch tag, but have
1232 Branch heads are changesets that have a given branch tag, but have
1233 no child changesets with that tag. They are usually where
1233 no child changesets with that tag. They are usually where
1234 development on the given branch takes place.
1234 development on the given branch takes place.
1235 """
1235 """
1236 if opts.get('rev'):
1236 if opts.get('rev'):
1237 start = repo.lookup(opts['rev'])
1237 start = repo.lookup(opts['rev'])
1238 else:
1238 else:
1239 start = None
1239 start = None
1240 if not branchrevs:
1240 if not branchrevs:
1241 # Assume we're looking repo-wide heads if no revs were specified.
1241 # Assume we're looking repo-wide heads if no revs were specified.
1242 heads = repo.heads(start)
1242 heads = repo.heads(start)
1243 else:
1243 else:
1244 heads = []
1244 heads = []
1245 visitedset = util.set()
1245 visitedset = util.set()
1246 for branchrev in branchrevs:
1246 for branchrev in branchrevs:
1247 branch = repo[branchrev].branch()
1247 branch = repo[branchrev].branch()
1248 if branch in visitedset:
1248 if branch in visitedset:
1249 continue
1249 continue
1250 visitedset.add(branch)
1250 visitedset.add(branch)
1251 bheads = repo.branchheads(branch, start)
1251 bheads = repo.branchheads(branch, start)
1252 if not bheads:
1252 if not bheads:
1253 if branch != branchrev:
1253 if branch != branchrev:
1254 ui.warn(_("no changes on branch %s containing %s are "
1254 ui.warn(_("no changes on branch %s containing %s are "
1255 "reachable from %s\n")
1255 "reachable from %s\n")
1256 % (branch, branchrev, opts.get('rev')))
1256 % (branch, branchrev, opts.get('rev')))
1257 else:
1257 else:
1258 ui.warn(_("no changes on branch %s are reachable from %s\n")
1258 ui.warn(_("no changes on branch %s are reachable from %s\n")
1259 % (branch, opts.get('rev')))
1259 % (branch, opts.get('rev')))
1260 heads.extend(bheads)
1260 heads.extend(bheads)
1261 if not heads:
1261 if not heads:
1262 return 1
1262 return 1
1263 displayer = cmdutil.show_changeset(ui, repo, opts)
1263 displayer = cmdutil.show_changeset(ui, repo, opts)
1264 for n in heads:
1264 for n in heads:
1265 displayer.show(changenode=n)
1265 displayer.show(changenode=n)
1266
1266
1267 def help_(ui, name=None, with_version=False):
1267 def help_(ui, name=None, with_version=False):
1268 """show help for a given topic or a help overview
1268 """show help for a given topic or a help overview
1269
1269
1270 With no arguments, print a list of commands and short help.
1270 With no arguments, print a list of commands and short help.
1271
1271
1272 Given a topic, extension, or command name, print help for that topic."""
1272 Given a topic, extension, or command name, print help for that topic."""
1273 option_lists = []
1273 option_lists = []
1274
1274
1275 def addglobalopts(aliases):
1275 def addglobalopts(aliases):
1276 if ui.verbose:
1276 if ui.verbose:
1277 option_lists.append((_("global options:"), globalopts))
1277 option_lists.append((_("global options:"), globalopts))
1278 if name == 'shortlist':
1278 if name == 'shortlist':
1279 option_lists.append((_('use "hg help" for the full list '
1279 option_lists.append((_('use "hg help" for the full list '
1280 'of commands'), ()))
1280 'of commands'), ()))
1281 else:
1281 else:
1282 if name == 'shortlist':
1282 if name == 'shortlist':
1283 msg = _('use "hg help" for the full list of commands '
1283 msg = _('use "hg help" for the full list of commands '
1284 'or "hg -v" for details')
1284 'or "hg -v" for details')
1285 elif aliases:
1285 elif aliases:
1286 msg = _('use "hg -v help%s" to show aliases and '
1286 msg = _('use "hg -v help%s" to show aliases and '
1287 'global options') % (name and " " + name or "")
1287 'global options') % (name and " " + name or "")
1288 else:
1288 else:
1289 msg = _('use "hg -v help %s" to show global options') % name
1289 msg = _('use "hg -v help %s" to show global options') % name
1290 option_lists.append((msg, ()))
1290 option_lists.append((msg, ()))
1291
1291
1292 def helpcmd(name):
1292 def helpcmd(name):
1293 if with_version:
1293 if with_version:
1294 version_(ui)
1294 version_(ui)
1295 ui.write('\n')
1295 ui.write('\n')
1296
1296
1297 try:
1297 try:
1298 aliases, i = cmdutil.findcmd(name, table, False)
1298 aliases, i = cmdutil.findcmd(name, table, False)
1299 except cmdutil.AmbiguousCommand, inst:
1299 except cmdutil.AmbiguousCommand, inst:
1300 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1300 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1301 helplist(_('list of commands:\n\n'), select)
1301 helplist(_('list of commands:\n\n'), select)
1302 return
1302 return
1303
1303
1304 # synopsis
1304 # synopsis
1305 ui.write("%s\n" % i[2])
1305 ui.write("%s\n" % i[2])
1306
1306
1307 # aliases
1307 # aliases
1308 if not ui.quiet and len(aliases) > 1:
1308 if not ui.quiet and len(aliases) > 1:
1309 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1309 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1310
1310
1311 # description
1311 # description
1312 doc = gettext(i[0].__doc__)
1312 doc = gettext(i[0].__doc__)
1313 if not doc:
1313 if not doc:
1314 doc = _("(No help text available)")
1314 doc = _("(No help text available)")
1315 if ui.quiet:
1315 if ui.quiet:
1316 doc = doc.splitlines(0)[0]
1316 doc = doc.splitlines(0)[0]
1317 ui.write("\n%s\n" % doc.rstrip())
1317 ui.write("\n%s\n" % doc.rstrip())
1318
1318
1319 if not ui.quiet:
1319 if not ui.quiet:
1320 # options
1320 # options
1321 if i[1]:
1321 if i[1]:
1322 option_lists.append((_("options:\n"), i[1]))
1322 option_lists.append((_("options:\n"), i[1]))
1323
1323
1324 addglobalopts(False)
1324 addglobalopts(False)
1325
1325
1326 def helplist(header, select=None):
1326 def helplist(header, select=None):
1327 h = {}
1327 h = {}
1328 cmds = {}
1328 cmds = {}
1329 for c, e in table.items():
1329 for c, e in table.items():
1330 f = c.split("|", 1)[0]
1330 f = c.split("|", 1)[0]
1331 if select and not select(f):
1331 if select and not select(f):
1332 continue
1332 continue
1333 if (not select and name != 'shortlist' and
1333 if (not select and name != 'shortlist' and
1334 e[0].__module__ != __name__):
1334 e[0].__module__ != __name__):
1335 continue
1335 continue
1336 if name == "shortlist" and not f.startswith("^"):
1336 if name == "shortlist" and not f.startswith("^"):
1337 continue
1337 continue
1338 f = f.lstrip("^")
1338 f = f.lstrip("^")
1339 if not ui.debugflag and f.startswith("debug"):
1339 if not ui.debugflag and f.startswith("debug"):
1340 continue
1340 continue
1341 doc = gettext(e[0].__doc__)
1341 doc = gettext(e[0].__doc__)
1342 if not doc:
1342 if not doc:
1343 doc = _("(No help text available)")
1343 doc = _("(No help text available)")
1344 h[f] = doc.splitlines(0)[0].rstrip()
1344 h[f] = doc.splitlines(0)[0].rstrip()
1345 cmds[f] = c.lstrip("^")
1345 cmds[f] = c.lstrip("^")
1346
1346
1347 if not h:
1347 if not h:
1348 ui.status(_('no commands defined\n'))
1348 ui.status(_('no commands defined\n'))
1349 return
1349 return
1350
1350
1351 ui.status(header)
1351 ui.status(header)
1352 fns = util.sort(h)
1352 fns = util.sort(h)
1353 m = max(map(len, fns))
1353 m = max(map(len, fns))
1354 for f in fns:
1354 for f in fns:
1355 if ui.verbose:
1355 if ui.verbose:
1356 commands = cmds[f].replace("|",", ")
1356 commands = cmds[f].replace("|",", ")
1357 ui.write(" %s:\n %s\n"%(commands, h[f]))
1357 ui.write(" %s:\n %s\n"%(commands, h[f]))
1358 else:
1358 else:
1359 ui.write(' %-*s %s\n' % (m, f, h[f]))
1359 ui.write(' %-*s %s\n' % (m, f, h[f]))
1360
1360
1361 exts = list(extensions.extensions())
1361 exts = list(extensions.extensions())
1362 if exts and name != 'shortlist':
1362 if exts and name != 'shortlist':
1363 ui.write(_('\nenabled extensions:\n\n'))
1363 ui.write(_('\nenabled extensions:\n\n'))
1364 maxlength = 0
1364 maxlength = 0
1365 exthelps = []
1365 exthelps = []
1366 for ename, ext in exts:
1366 for ename, ext in exts:
1367 doc = (ext.__doc__ or _('(no help text available)'))
1367 doc = (ext.__doc__ or _('(no help text available)'))
1368 ename = ename.split('.')[-1]
1368 ename = ename.split('.')[-1]
1369 maxlength = max(len(ename), maxlength)
1369 maxlength = max(len(ename), maxlength)
1370 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1370 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1371 for ename, text in exthelps:
1371 for ename, text in exthelps:
1372 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1372 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1373
1373
1374 if not ui.quiet:
1374 if not ui.quiet:
1375 addglobalopts(True)
1375 addglobalopts(True)
1376
1376
1377 def helptopic(name):
1377 def helptopic(name):
1378 for names, header, doc in help.helptable:
1378 for names, header, doc in help.helptable:
1379 if name in names:
1379 if name in names:
1380 break
1380 break
1381 else:
1381 else:
1382 raise cmdutil.UnknownCommand(name)
1382 raise cmdutil.UnknownCommand(name)
1383
1383
1384 # description
1384 # description
1385 if not doc:
1385 if not doc:
1386 doc = _("(No help text available)")
1386 doc = _("(No help text available)")
1387 if callable(doc):
1387 if callable(doc):
1388 doc = doc()
1388 doc = doc()
1389
1389
1390 ui.write("%s\n" % header)
1390 ui.write("%s\n" % header)
1391 ui.write("%s\n" % doc.rstrip())
1391 ui.write("%s\n" % doc.rstrip())
1392
1392
1393 def helpext(name):
1393 def helpext(name):
1394 try:
1394 try:
1395 mod = extensions.find(name)
1395 mod = extensions.find(name)
1396 except KeyError:
1396 except KeyError:
1397 raise cmdutil.UnknownCommand(name)
1397 raise cmdutil.UnknownCommand(name)
1398
1398
1399 doc = gettext(mod.__doc__) or _('No help text available')
1399 doc = gettext(mod.__doc__) or _('No help text available')
1400 doc = doc.splitlines(0)
1400 doc = doc.splitlines(0)
1401 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1401 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1402 for d in doc[1:]:
1402 for d in doc[1:]:
1403 ui.write(d, '\n')
1403 ui.write(d, '\n')
1404
1404
1405 ui.status('\n')
1405 ui.status('\n')
1406
1406
1407 try:
1407 try:
1408 ct = mod.cmdtable
1408 ct = mod.cmdtable
1409 except AttributeError:
1409 except AttributeError:
1410 ct = {}
1410 ct = {}
1411
1411
1412 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1412 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1413 helplist(_('list of commands:\n\n'), modcmds.has_key)
1413 helplist(_('list of commands:\n\n'), modcmds.has_key)
1414
1414
1415 if name and name != 'shortlist':
1415 if name and name != 'shortlist':
1416 i = None
1416 i = None
1417 for f in (helpcmd, helptopic, helpext):
1417 for f in (helpcmd, helptopic, helpext):
1418 try:
1418 try:
1419 f(name)
1419 f(name)
1420 i = None
1420 i = None
1421 break
1421 break
1422 except cmdutil.UnknownCommand, inst:
1422 except cmdutil.UnknownCommand, inst:
1423 i = inst
1423 i = inst
1424 if i:
1424 if i:
1425 raise i
1425 raise i
1426
1426
1427 else:
1427 else:
1428 # program name
1428 # program name
1429 if ui.verbose or with_version:
1429 if ui.verbose or with_version:
1430 version_(ui)
1430 version_(ui)
1431 else:
1431 else:
1432 ui.status(_("Mercurial Distributed SCM\n"))
1432 ui.status(_("Mercurial Distributed SCM\n"))
1433 ui.status('\n')
1433 ui.status('\n')
1434
1434
1435 # list of commands
1435 # list of commands
1436 if name == "shortlist":
1436 if name == "shortlist":
1437 header = _('basic commands:\n\n')
1437 header = _('basic commands:\n\n')
1438 else:
1438 else:
1439 header = _('list of commands:\n\n')
1439 header = _('list of commands:\n\n')
1440
1440
1441 helplist(header)
1441 helplist(header)
1442
1442
1443 # list all option lists
1443 # list all option lists
1444 opt_output = []
1444 opt_output = []
1445 for title, options in option_lists:
1445 for title, options in option_lists:
1446 opt_output.append(("\n%s" % title, None))
1446 opt_output.append(("\n%s" % title, None))
1447 for shortopt, longopt, default, desc in options:
1447 for shortopt, longopt, default, desc in options:
1448 if "DEPRECATED" in desc and not ui.verbose: continue
1448 if "DEPRECATED" in desc and not ui.verbose: continue
1449 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1449 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1450 longopt and " --%s" % longopt),
1450 longopt and " --%s" % longopt),
1451 "%s%s" % (desc,
1451 "%s%s" % (desc,
1452 default
1452 default
1453 and _(" (default: %s)") % default
1453 and _(" (default: %s)") % default
1454 or "")))
1454 or "")))
1455
1455
1456 if not name:
1456 if not name:
1457 ui.write(_("\nadditional help topics:\n\n"))
1457 ui.write(_("\nadditional help topics:\n\n"))
1458 topics = []
1458 topics = []
1459 for names, header, doc in help.helptable:
1459 for names, header, doc in help.helptable:
1460 names = [(-len(name), name) for name in names]
1460 names = [(-len(name), name) for name in names]
1461 names.sort()
1461 names.sort()
1462 topics.append((names[0][1], header))
1462 topics.append((names[0][1], header))
1463 topics_len = max([len(s[0]) for s in topics])
1463 topics_len = max([len(s[0]) for s in topics])
1464 for t, desc in topics:
1464 for t, desc in topics:
1465 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1465 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1466
1466
1467 if opt_output:
1467 if opt_output:
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1469 for first, second in opt_output:
1469 for first, second in opt_output:
1470 if second:
1470 if second:
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1472 else:
1472 else:
1473 ui.write("%s\n" % first)
1473 ui.write("%s\n" % first)
1474
1474
1475 def identify(ui, repo, source=None,
1475 def identify(ui, repo, source=None,
1476 rev=None, num=None, id=None, branch=None, tags=None):
1476 rev=None, num=None, id=None, branch=None, tags=None):
1477 """identify the working copy or specified revision
1477 """identify the working copy or specified revision
1478
1478
1479 With no revision, print a summary of the current state of the repo.
1479 With no revision, print a summary of the current state of the repo.
1480
1480
1481 With a path, do a lookup in another repository.
1481 With a path, do a lookup in another repository.
1482
1482
1483 This summary identifies the repository state using one or two parent
1483 This summary identifies the repository state using one or two parent
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1485 in the working directory, a list of tags for this revision and a branch
1485 in the working directory, a list of tags for this revision and a branch
1486 name for non-default branches.
1486 name for non-default branches.
1487 """
1487 """
1488
1488
1489 if not repo and not source:
1489 if not repo and not source:
1490 raise util.Abort(_("There is no Mercurial repository here "
1490 raise util.Abort(_("There is no Mercurial repository here "
1491 "(.hg not found)"))
1491 "(.hg not found)"))
1492
1492
1493 hexfunc = ui.debugflag and hex or short
1493 hexfunc = ui.debugflag and hex or short
1494 default = not (num or id or branch or tags)
1494 default = not (num or id or branch or tags)
1495 output = []
1495 output = []
1496
1496
1497 if source:
1497 if source:
1498 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1498 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1499 srepo = hg.repository(ui, source)
1499 srepo = hg.repository(ui, source)
1500 if not rev and revs:
1500 if not rev and revs:
1501 rev = revs[0]
1501 rev = revs[0]
1502 if not rev:
1502 if not rev:
1503 rev = "tip"
1503 rev = "tip"
1504 if num or branch or tags:
1504 if num or branch or tags:
1505 raise util.Abort(
1505 raise util.Abort(
1506 "can't query remote revision number, branch, or tags")
1506 "can't query remote revision number, branch, or tags")
1507 output = [hexfunc(srepo.lookup(rev))]
1507 output = [hexfunc(srepo.lookup(rev))]
1508 elif not rev:
1508 elif not rev:
1509 ctx = repo[None]
1509 ctx = repo[None]
1510 parents = ctx.parents()
1510 parents = ctx.parents()
1511 changed = False
1511 changed = False
1512 if default or id or num:
1512 if default or id or num:
1513 changed = ctx.files() + ctx.deleted()
1513 changed = ctx.files() + ctx.deleted()
1514 if default or id:
1514 if default or id:
1515 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1515 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1516 (changed) and "+" or "")]
1516 (changed) and "+" or "")]
1517 if num:
1517 if num:
1518 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1518 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1519 (changed) and "+" or ""))
1519 (changed) and "+" or ""))
1520 else:
1520 else:
1521 ctx = repo[rev]
1521 ctx = repo[rev]
1522 if default or id:
1522 if default or id:
1523 output = [hexfunc(ctx.node())]
1523 output = [hexfunc(ctx.node())]
1524 if num:
1524 if num:
1525 output.append(str(ctx.rev()))
1525 output.append(str(ctx.rev()))
1526
1526
1527 if not source and default and not ui.quiet:
1527 if not source and default and not ui.quiet:
1528 b = util.tolocal(ctx.branch())
1528 b = util.tolocal(ctx.branch())
1529 if b != 'default':
1529 if b != 'default':
1530 output.append("(%s)" % b)
1530 output.append("(%s)" % b)
1531
1531
1532 # multiple tags for a single parent separated by '/'
1532 # multiple tags for a single parent separated by '/'
1533 t = "/".join(ctx.tags())
1533 t = "/".join(ctx.tags())
1534 if t:
1534 if t:
1535 output.append(t)
1535 output.append(t)
1536
1536
1537 if branch:
1537 if branch:
1538 output.append(util.tolocal(ctx.branch()))
1538 output.append(util.tolocal(ctx.branch()))
1539
1539
1540 if tags:
1540 if tags:
1541 output.extend(ctx.tags())
1541 output.extend(ctx.tags())
1542
1542
1543 ui.write("%s\n" % ' '.join(output))
1543 ui.write("%s\n" % ' '.join(output))
1544
1544
1545 def import_(ui, repo, patch1, *patches, **opts):
1545 def import_(ui, repo, patch1, *patches, **opts):
1546 """import an ordered set of patches
1546 """import an ordered set of patches
1547
1547
1548 Import a list of patches and commit them individually.
1548 Import a list of patches and commit them individually.
1549
1549
1550 If there are outstanding changes in the working directory, import
1550 If there are outstanding changes in the working directory, import
1551 will abort unless given the -f flag.
1551 will abort unless given the -f flag.
1552
1552
1553 You can import a patch straight from a mail message. Even patches
1553 You can import a patch straight from a mail message. Even patches
1554 as attachments work (body part must be type text/plain or
1554 as attachments work (body part must be type text/plain or
1555 text/x-patch to be used). From and Subject headers of email
1555 text/x-patch to be used). From and Subject headers of email
1556 message are used as default committer and commit message. All
1556 message are used as default committer and commit message. All
1557 text/plain body parts before first diff are added to commit
1557 text/plain body parts before first diff are added to commit
1558 message.
1558 message.
1559
1559
1560 If the imported patch was generated by hg export, user and description
1560 If the imported patch was generated by hg export, user and description
1561 from patch override values from message headers and body. Values
1561 from patch override values from message headers and body. Values
1562 given on command line with -m and -u override these.
1562 given on command line with -m and -u override these.
1563
1563
1564 If --exact is specified, import will set the working directory
1564 If --exact is specified, import will set the working directory
1565 to the parent of each patch before applying it, and will abort
1565 to the parent of each patch before applying it, and will abort
1566 if the resulting changeset has a different ID than the one
1566 if the resulting changeset has a different ID than the one
1567 recorded in the patch. This may happen due to character set
1567 recorded in the patch. This may happen due to character set
1568 problems or other deficiencies in the text patch format.
1568 problems or other deficiencies in the text patch format.
1569
1569
1570 To read a patch from standard input, use patch name "-".
1570 To read a patch from standard input, use patch name "-".
1571 See 'hg help dates' for a list of formats valid for -d/--date.
1571 See 'hg help dates' for a list of formats valid for -d/--date.
1572 """
1572 """
1573 patches = (patch1,) + patches
1573 patches = (patch1,) + patches
1574
1574
1575 date = opts.get('date')
1575 date = opts.get('date')
1576 if date:
1576 if date:
1577 opts['date'] = util.parsedate(date)
1577 opts['date'] = util.parsedate(date)
1578
1578
1579 if opts.get('exact') or not opts.get('force'):
1579 if opts.get('exact') or not opts.get('force'):
1580 cmdutil.bail_if_changed(repo)
1580 cmdutil.bail_if_changed(repo)
1581
1581
1582 d = opts["base"]
1582 d = opts["base"]
1583 strip = opts["strip"]
1583 strip = opts["strip"]
1584 wlock = lock = None
1584 wlock = lock = None
1585 try:
1585 try:
1586 wlock = repo.wlock()
1586 wlock = repo.wlock()
1587 lock = repo.lock()
1587 lock = repo.lock()
1588 for p in patches:
1588 for p in patches:
1589 pf = os.path.join(d, p)
1589 pf = os.path.join(d, p)
1590
1590
1591 if pf == '-':
1591 if pf == '-':
1592 ui.status(_("applying patch from stdin\n"))
1592 ui.status(_("applying patch from stdin\n"))
1593 data = patch.extract(ui, sys.stdin)
1593 pf = sys.stdin
1594 else:
1594 else:
1595 ui.status(_("applying %s\n") % p)
1595 ui.status(_("applying %s\n") % p)
1596 if os.path.exists(pf):
1596 pf = url.open(ui, pf)
1597 data = patch.extract(ui, file(pf, 'rb'))
1597 data = patch.extract(ui, pf)
1598 else:
1599 data = patch.extract(ui, urllib.urlopen(pf))
1600 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1598 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1601
1599
1602 if tmpname is None:
1600 if tmpname is None:
1603 raise util.Abort(_('no diffs found'))
1601 raise util.Abort(_('no diffs found'))
1604
1602
1605 try:
1603 try:
1606 cmdline_message = cmdutil.logmessage(opts)
1604 cmdline_message = cmdutil.logmessage(opts)
1607 if cmdline_message:
1605 if cmdline_message:
1608 # pickup the cmdline msg
1606 # pickup the cmdline msg
1609 message = cmdline_message
1607 message = cmdline_message
1610 elif message:
1608 elif message:
1611 # pickup the patch msg
1609 # pickup the patch msg
1612 message = message.strip()
1610 message = message.strip()
1613 else:
1611 else:
1614 # launch the editor
1612 # launch the editor
1615 message = None
1613 message = None
1616 ui.debug(_('message:\n%s\n') % message)
1614 ui.debug(_('message:\n%s\n') % message)
1617
1615
1618 wp = repo.parents()
1616 wp = repo.parents()
1619 if opts.get('exact'):
1617 if opts.get('exact'):
1620 if not nodeid or not p1:
1618 if not nodeid or not p1:
1621 raise util.Abort(_('not a mercurial patch'))
1619 raise util.Abort(_('not a mercurial patch'))
1622 p1 = repo.lookup(p1)
1620 p1 = repo.lookup(p1)
1623 p2 = repo.lookup(p2 or hex(nullid))
1621 p2 = repo.lookup(p2 or hex(nullid))
1624
1622
1625 if p1 != wp[0].node():
1623 if p1 != wp[0].node():
1626 hg.clean(repo, p1)
1624 hg.clean(repo, p1)
1627 repo.dirstate.setparents(p1, p2)
1625 repo.dirstate.setparents(p1, p2)
1628 elif p2:
1626 elif p2:
1629 try:
1627 try:
1630 p1 = repo.lookup(p1)
1628 p1 = repo.lookup(p1)
1631 p2 = repo.lookup(p2)
1629 p2 = repo.lookup(p2)
1632 if p1 == wp[0].node():
1630 if p1 == wp[0].node():
1633 repo.dirstate.setparents(p1, p2)
1631 repo.dirstate.setparents(p1, p2)
1634 except RepoError:
1632 except RepoError:
1635 pass
1633 pass
1636 if opts.get('exact') or opts.get('import_branch'):
1634 if opts.get('exact') or opts.get('import_branch'):
1637 repo.dirstate.setbranch(branch or 'default')
1635 repo.dirstate.setbranch(branch or 'default')
1638
1636
1639 files = {}
1637 files = {}
1640 try:
1638 try:
1641 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1639 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1642 files=files)
1640 files=files)
1643 finally:
1641 finally:
1644 files = patch.updatedir(ui, repo, files)
1642 files = patch.updatedir(ui, repo, files)
1645 if not opts.get('no_commit'):
1643 if not opts.get('no_commit'):
1646 n = repo.commit(files, message, opts.get('user') or user,
1644 n = repo.commit(files, message, opts.get('user') or user,
1647 opts.get('date') or date)
1645 opts.get('date') or date)
1648 if opts.get('exact'):
1646 if opts.get('exact'):
1649 if hex(n) != nodeid:
1647 if hex(n) != nodeid:
1650 repo.rollback()
1648 repo.rollback()
1651 raise util.Abort(_('patch is damaged'
1649 raise util.Abort(_('patch is damaged'
1652 ' or loses information'))
1650 ' or loses information'))
1653 # Force a dirstate write so that the next transaction
1651 # Force a dirstate write so that the next transaction
1654 # backups an up-do-date file.
1652 # backups an up-do-date file.
1655 repo.dirstate.write()
1653 repo.dirstate.write()
1656 finally:
1654 finally:
1657 os.unlink(tmpname)
1655 os.unlink(tmpname)
1658 finally:
1656 finally:
1659 del lock, wlock
1657 del lock, wlock
1660
1658
1661 def incoming(ui, repo, source="default", **opts):
1659 def incoming(ui, repo, source="default", **opts):
1662 """show new changesets found in source
1660 """show new changesets found in source
1663
1661
1664 Show new changesets found in the specified path/URL or the default
1662 Show new changesets found in the specified path/URL or the default
1665 pull location. These are the changesets that would be pulled if a pull
1663 pull location. These are the changesets that would be pulled if a pull
1666 was requested.
1664 was requested.
1667
1665
1668 For remote repository, using --bundle avoids downloading the changesets
1666 For remote repository, using --bundle avoids downloading the changesets
1669 twice if the incoming is followed by a pull.
1667 twice if the incoming is followed by a pull.
1670
1668
1671 See pull for valid source format details.
1669 See pull for valid source format details.
1672 """
1670 """
1673 limit = cmdutil.loglimit(opts)
1671 limit = cmdutil.loglimit(opts)
1674 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1672 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1675 cmdutil.setremoteconfig(ui, opts)
1673 cmdutil.setremoteconfig(ui, opts)
1676
1674
1677 other = hg.repository(ui, source)
1675 other = hg.repository(ui, source)
1678 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1676 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1679 if revs:
1677 if revs:
1680 revs = [other.lookup(rev) for rev in revs]
1678 revs = [other.lookup(rev) for rev in revs]
1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1679 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1682 if not incoming:
1680 if not incoming:
1683 try:
1681 try:
1684 os.unlink(opts["bundle"])
1682 os.unlink(opts["bundle"])
1685 except:
1683 except:
1686 pass
1684 pass
1687 ui.status(_("no changes found\n"))
1685 ui.status(_("no changes found\n"))
1688 return 1
1686 return 1
1689
1687
1690 cleanup = None
1688 cleanup = None
1691 try:
1689 try:
1692 fname = opts["bundle"]
1690 fname = opts["bundle"]
1693 if fname or not other.local():
1691 if fname or not other.local():
1694 # create a bundle (uncompressed if other repo is not local)
1692 # create a bundle (uncompressed if other repo is not local)
1695 if revs is None:
1693 if revs is None:
1696 cg = other.changegroup(incoming, "incoming")
1694 cg = other.changegroup(incoming, "incoming")
1697 else:
1695 else:
1698 cg = other.changegroupsubset(incoming, revs, 'incoming')
1696 cg = other.changegroupsubset(incoming, revs, 'incoming')
1699 bundletype = other.local() and "HG10BZ" or "HG10UN"
1697 bundletype = other.local() and "HG10BZ" or "HG10UN"
1700 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1698 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1701 # keep written bundle?
1699 # keep written bundle?
1702 if opts["bundle"]:
1700 if opts["bundle"]:
1703 cleanup = None
1701 cleanup = None
1704 if not other.local():
1702 if not other.local():
1705 # use the created uncompressed bundlerepo
1703 # use the created uncompressed bundlerepo
1706 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1704 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1707
1705
1708 o = other.changelog.nodesbetween(incoming, revs)[0]
1706 o = other.changelog.nodesbetween(incoming, revs)[0]
1709 if opts.get('newest_first'):
1707 if opts.get('newest_first'):
1710 o.reverse()
1708 o.reverse()
1711 displayer = cmdutil.show_changeset(ui, other, opts)
1709 displayer = cmdutil.show_changeset(ui, other, opts)
1712 count = 0
1710 count = 0
1713 for n in o:
1711 for n in o:
1714 if count >= limit:
1712 if count >= limit:
1715 break
1713 break
1716 parents = [p for p in other.changelog.parents(n) if p != nullid]
1714 parents = [p for p in other.changelog.parents(n) if p != nullid]
1717 if opts.get('no_merges') and len(parents) == 2:
1715 if opts.get('no_merges') and len(parents) == 2:
1718 continue
1716 continue
1719 count += 1
1717 count += 1
1720 displayer.show(changenode=n)
1718 displayer.show(changenode=n)
1721 finally:
1719 finally:
1722 if hasattr(other, 'close'):
1720 if hasattr(other, 'close'):
1723 other.close()
1721 other.close()
1724 if cleanup:
1722 if cleanup:
1725 os.unlink(cleanup)
1723 os.unlink(cleanup)
1726
1724
1727 def init(ui, dest=".", **opts):
1725 def init(ui, dest=".", **opts):
1728 """create a new repository in the given directory
1726 """create a new repository in the given directory
1729
1727
1730 Initialize a new repository in the given directory. If the given
1728 Initialize a new repository in the given directory. If the given
1731 directory does not exist, it is created.
1729 directory does not exist, it is created.
1732
1730
1733 If no directory is given, the current directory is used.
1731 If no directory is given, the current directory is used.
1734
1732
1735 It is possible to specify an ssh:// URL as the destination.
1733 It is possible to specify an ssh:// URL as the destination.
1736 Look at the help text for the pull command for important details
1734 Look at the help text for the pull command for important details
1737 about ssh:// URLs.
1735 about ssh:// URLs.
1738 """
1736 """
1739 cmdutil.setremoteconfig(ui, opts)
1737 cmdutil.setremoteconfig(ui, opts)
1740 hg.repository(ui, dest, create=1)
1738 hg.repository(ui, dest, create=1)
1741
1739
1742 def locate(ui, repo, *pats, **opts):
1740 def locate(ui, repo, *pats, **opts):
1743 """locate files matching specific patterns
1741 """locate files matching specific patterns
1744
1742
1745 Print all files under Mercurial control whose names match the
1743 Print all files under Mercurial control whose names match the
1746 given patterns.
1744 given patterns.
1747
1745
1748 This command searches the entire repository by default. To search
1746 This command searches the entire repository by default. To search
1749 just the current directory and its subdirectories, use
1747 just the current directory and its subdirectories, use
1750 "--include .".
1748 "--include .".
1751
1749
1752 If no patterns are given to match, this command prints all file
1750 If no patterns are given to match, this command prints all file
1753 names.
1751 names.
1754
1752
1755 If you want to feed the output of this command into the "xargs"
1753 If you want to feed the output of this command into the "xargs"
1756 command, use the "-0" option to both this command and "xargs".
1754 command, use the "-0" option to both this command and "xargs".
1757 This will avoid the problem of "xargs" treating single filenames
1755 This will avoid the problem of "xargs" treating single filenames
1758 that contain white space as multiple filenames.
1756 that contain white space as multiple filenames.
1759 """
1757 """
1760 end = opts.get('print0') and '\0' or '\n'
1758 end = opts.get('print0') and '\0' or '\n'
1761 rev = opts.get('rev') or None
1759 rev = opts.get('rev') or None
1762
1760
1763 ret = 1
1761 ret = 1
1764 m = cmdutil.match(repo, pats, opts, default='relglob')
1762 m = cmdutil.match(repo, pats, opts, default='relglob')
1765 m.bad = lambda x,y: False
1763 m.bad = lambda x,y: False
1766 for abs in repo[rev].walk(m):
1764 for abs in repo[rev].walk(m):
1767 if not rev and abs not in repo.dirstate:
1765 if not rev and abs not in repo.dirstate:
1768 continue
1766 continue
1769 if opts.get('fullpath'):
1767 if opts.get('fullpath'):
1770 ui.write(os.path.join(repo.root, abs), end)
1768 ui.write(os.path.join(repo.root, abs), end)
1771 else:
1769 else:
1772 ui.write(((pats and m.rel(abs)) or abs), end)
1770 ui.write(((pats and m.rel(abs)) or abs), end)
1773 ret = 0
1771 ret = 0
1774
1772
1775 return ret
1773 return ret
1776
1774
1777 def log(ui, repo, *pats, **opts):
1775 def log(ui, repo, *pats, **opts):
1778 """show revision history of entire repository or files
1776 """show revision history of entire repository or files
1779
1777
1780 Print the revision history of the specified files or the entire
1778 Print the revision history of the specified files or the entire
1781 project.
1779 project.
1782
1780
1783 File history is shown without following rename or copy history of
1781 File history is shown without following rename or copy history of
1784 files. Use -f/--follow with a file name to follow history across
1782 files. Use -f/--follow with a file name to follow history across
1785 renames and copies. --follow without a file name will only show
1783 renames and copies. --follow without a file name will only show
1786 ancestors or descendants of the starting revision. --follow-first
1784 ancestors or descendants of the starting revision. --follow-first
1787 only follows the first parent of merge revisions.
1785 only follows the first parent of merge revisions.
1788
1786
1789 If no revision range is specified, the default is tip:0 unless
1787 If no revision range is specified, the default is tip:0 unless
1790 --follow is set, in which case the working directory parent is
1788 --follow is set, in which case the working directory parent is
1791 used as the starting revision.
1789 used as the starting revision.
1792
1790
1793 See 'hg help dates' for a list of formats valid for -d/--date.
1791 See 'hg help dates' for a list of formats valid for -d/--date.
1794
1792
1795 By default this command outputs: changeset id and hash, tags,
1793 By default this command outputs: changeset id and hash, tags,
1796 non-trivial parents, user, date and time, and a summary for each
1794 non-trivial parents, user, date and time, and a summary for each
1797 commit. When the -v/--verbose switch is used, the list of changed
1795 commit. When the -v/--verbose switch is used, the list of changed
1798 files and full commit message is shown.
1796 files and full commit message is shown.
1799
1797
1800 NOTE: log -p may generate unexpected diff output for merge
1798 NOTE: log -p may generate unexpected diff output for merge
1801 changesets, as it will compare the merge changeset against its
1799 changesets, as it will compare the merge changeset against its
1802 first parent only. Also, the files: list will only reflect files
1800 first parent only. Also, the files: list will only reflect files
1803 that are different from BOTH parents.
1801 that are different from BOTH parents.
1804
1802
1805 """
1803 """
1806
1804
1807 get = util.cachefunc(lambda r: repo[r].changeset())
1805 get = util.cachefunc(lambda r: repo[r].changeset())
1808 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1806 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1809
1807
1810 limit = cmdutil.loglimit(opts)
1808 limit = cmdutil.loglimit(opts)
1811 count = 0
1809 count = 0
1812
1810
1813 if opts.get('copies') and opts.get('rev'):
1811 if opts.get('copies') and opts.get('rev'):
1814 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1812 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1815 else:
1813 else:
1816 endrev = len(repo)
1814 endrev = len(repo)
1817 rcache = {}
1815 rcache = {}
1818 ncache = {}
1816 ncache = {}
1819 def getrenamed(fn, rev):
1817 def getrenamed(fn, rev):
1820 '''looks up all renames for a file (up to endrev) the first
1818 '''looks up all renames for a file (up to endrev) the first
1821 time the file is given. It indexes on the changerev and only
1819 time the file is given. It indexes on the changerev and only
1822 parses the manifest if linkrev != changerev.
1820 parses the manifest if linkrev != changerev.
1823 Returns rename info for fn at changerev rev.'''
1821 Returns rename info for fn at changerev rev.'''
1824 if fn not in rcache:
1822 if fn not in rcache:
1825 rcache[fn] = {}
1823 rcache[fn] = {}
1826 ncache[fn] = {}
1824 ncache[fn] = {}
1827 fl = repo.file(fn)
1825 fl = repo.file(fn)
1828 for i in fl:
1826 for i in fl:
1829 node = fl.node(i)
1827 node = fl.node(i)
1830 lr = fl.linkrev(node)
1828 lr = fl.linkrev(node)
1831 renamed = fl.renamed(node)
1829 renamed = fl.renamed(node)
1832 rcache[fn][lr] = renamed
1830 rcache[fn][lr] = renamed
1833 if renamed:
1831 if renamed:
1834 ncache[fn][node] = renamed
1832 ncache[fn][node] = renamed
1835 if lr >= endrev:
1833 if lr >= endrev:
1836 break
1834 break
1837 if rev in rcache[fn]:
1835 if rev in rcache[fn]:
1838 return rcache[fn][rev]
1836 return rcache[fn][rev]
1839
1837
1840 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1838 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1841 # filectx logic.
1839 # filectx logic.
1842
1840
1843 try:
1841 try:
1844 return repo[rev][fn].renamed()
1842 return repo[rev][fn].renamed()
1845 except revlog.LookupError:
1843 except revlog.LookupError:
1846 pass
1844 pass
1847 return None
1845 return None
1848
1846
1849 df = False
1847 df = False
1850 if opts["date"]:
1848 if opts["date"]:
1851 df = util.matchdate(opts["date"])
1849 df = util.matchdate(opts["date"])
1852
1850
1853 only_branches = opts.get('only_branch')
1851 only_branches = opts.get('only_branch')
1854
1852
1855 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1853 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1856 for st, rev, fns in changeiter:
1854 for st, rev, fns in changeiter:
1857 if st == 'add':
1855 if st == 'add':
1858 changenode = repo.changelog.node(rev)
1856 changenode = repo.changelog.node(rev)
1859 parents = [p for p in repo.changelog.parentrevs(rev)
1857 parents = [p for p in repo.changelog.parentrevs(rev)
1860 if p != nullrev]
1858 if p != nullrev]
1861 if opts.get('no_merges') and len(parents) == 2:
1859 if opts.get('no_merges') and len(parents) == 2:
1862 continue
1860 continue
1863 if opts.get('only_merges') and len(parents) != 2:
1861 if opts.get('only_merges') and len(parents) != 2:
1864 continue
1862 continue
1865
1863
1866 if only_branches:
1864 if only_branches:
1867 revbranch = get(rev)[5]['branch']
1865 revbranch = get(rev)[5]['branch']
1868 if revbranch not in only_branches:
1866 if revbranch not in only_branches:
1869 continue
1867 continue
1870
1868
1871 if df:
1869 if df:
1872 changes = get(rev)
1870 changes = get(rev)
1873 if not df(changes[2][0]):
1871 if not df(changes[2][0]):
1874 continue
1872 continue
1875
1873
1876 if opts.get('keyword'):
1874 if opts.get('keyword'):
1877 changes = get(rev)
1875 changes = get(rev)
1878 miss = 0
1876 miss = 0
1879 for k in [kw.lower() for kw in opts['keyword']]:
1877 for k in [kw.lower() for kw in opts['keyword']]:
1880 if not (k in changes[1].lower() or
1878 if not (k in changes[1].lower() or
1881 k in changes[4].lower() or
1879 k in changes[4].lower() or
1882 k in " ".join(changes[3]).lower()):
1880 k in " ".join(changes[3]).lower()):
1883 miss = 1
1881 miss = 1
1884 break
1882 break
1885 if miss:
1883 if miss:
1886 continue
1884 continue
1887
1885
1888 if opts['user']:
1886 if opts['user']:
1889 changes = get(rev)
1887 changes = get(rev)
1890 miss = 0
1888 miss = 0
1891 for k in opts['user']:
1889 for k in opts['user']:
1892 if k != changes[1]:
1890 if k != changes[1]:
1893 miss = 1
1891 miss = 1
1894 break
1892 break
1895 if miss:
1893 if miss:
1896 continue
1894 continue
1897
1895
1898 copies = []
1896 copies = []
1899 if opts.get('copies') and rev:
1897 if opts.get('copies') and rev:
1900 for fn in get(rev)[3]:
1898 for fn in get(rev)[3]:
1901 rename = getrenamed(fn, rev)
1899 rename = getrenamed(fn, rev)
1902 if rename:
1900 if rename:
1903 copies.append((fn, rename[0]))
1901 copies.append((fn, rename[0]))
1904 displayer.show(rev, changenode, copies=copies)
1902 displayer.show(rev, changenode, copies=copies)
1905 elif st == 'iter':
1903 elif st == 'iter':
1906 if count == limit: break
1904 if count == limit: break
1907 if displayer.flush(rev):
1905 if displayer.flush(rev):
1908 count += 1
1906 count += 1
1909
1907
1910 def manifest(ui, repo, node=None, rev=None):
1908 def manifest(ui, repo, node=None, rev=None):
1911 """output the current or given revision of the project manifest
1909 """output the current or given revision of the project manifest
1912
1910
1913 Print a list of version controlled files for the given revision.
1911 Print a list of version controlled files for the given revision.
1914 If no revision is given, the parent of the working directory is used,
1912 If no revision is given, the parent of the working directory is used,
1915 or tip if no revision is checked out.
1913 or tip if no revision is checked out.
1916
1914
1917 The manifest is the list of files being version controlled. If no revision
1915 The manifest is the list of files being version controlled. If no revision
1918 is given then the first parent of the working directory is used.
1916 is given then the first parent of the working directory is used.
1919
1917
1920 With -v flag, print file permissions, symlink and executable bits. With
1918 With -v flag, print file permissions, symlink and executable bits. With
1921 --debug flag, print file revision hashes.
1919 --debug flag, print file revision hashes.
1922 """
1920 """
1923
1921
1924 if rev and node:
1922 if rev and node:
1925 raise util.Abort(_("please specify just one revision"))
1923 raise util.Abort(_("please specify just one revision"))
1926
1924
1927 if not node:
1925 if not node:
1928 node = rev
1926 node = rev
1929
1927
1930 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1928 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1931 ctx = repo[node]
1929 ctx = repo[node]
1932 for f in ctx:
1930 for f in ctx:
1933 if ui.debugflag:
1931 if ui.debugflag:
1934 ui.write("%40s " % hex(ctx.manifest()[f]))
1932 ui.write("%40s " % hex(ctx.manifest()[f]))
1935 if ui.verbose:
1933 if ui.verbose:
1936 ui.write(decor[ctx.flags(f)])
1934 ui.write(decor[ctx.flags(f)])
1937 ui.write("%s\n" % f)
1935 ui.write("%s\n" % f)
1938
1936
1939 def merge(ui, repo, node=None, force=None, rev=None):
1937 def merge(ui, repo, node=None, force=None, rev=None):
1940 """merge working directory with another revision
1938 """merge working directory with another revision
1941
1939
1942 Merge the contents of the current working directory and the
1940 Merge the contents of the current working directory and the
1943 requested revision. Files that changed between either parent are
1941 requested revision. Files that changed between either parent are
1944 marked as changed for the next commit and a commit must be
1942 marked as changed for the next commit and a commit must be
1945 performed before any further updates are allowed.
1943 performed before any further updates are allowed.
1946
1944
1947 If no revision is specified, the working directory's parent is a
1945 If no revision is specified, the working directory's parent is a
1948 head revision, and the current branch contains exactly one other head,
1946 head revision, and the current branch contains exactly one other head,
1949 the other head is merged with by default. Otherwise, an explicit
1947 the other head is merged with by default. Otherwise, an explicit
1950 revision to merge with must be provided.
1948 revision to merge with must be provided.
1951 """
1949 """
1952
1950
1953 if rev and node:
1951 if rev and node:
1954 raise util.Abort(_("please specify just one revision"))
1952 raise util.Abort(_("please specify just one revision"))
1955 if not node:
1953 if not node:
1956 node = rev
1954 node = rev
1957
1955
1958 if not node:
1956 if not node:
1959 branch = repo.changectx(None).branch()
1957 branch = repo.changectx(None).branch()
1960 bheads = repo.branchheads(branch)
1958 bheads = repo.branchheads(branch)
1961 if len(bheads) > 2:
1959 if len(bheads) > 2:
1962 raise util.Abort(_("branch '%s' has %d heads - "
1960 raise util.Abort(_("branch '%s' has %d heads - "
1963 "please merge with an explicit rev") %
1961 "please merge with an explicit rev") %
1964 (branch, len(bheads)))
1962 (branch, len(bheads)))
1965
1963
1966 parent = repo.dirstate.parents()[0]
1964 parent = repo.dirstate.parents()[0]
1967 if len(bheads) == 1:
1965 if len(bheads) == 1:
1968 if len(repo.heads()) > 1:
1966 if len(repo.heads()) > 1:
1969 raise util.Abort(_("branch '%s' has one head - "
1967 raise util.Abort(_("branch '%s' has one head - "
1970 "please merge with an explicit rev") %
1968 "please merge with an explicit rev") %
1971 branch)
1969 branch)
1972 msg = _('there is nothing to merge')
1970 msg = _('there is nothing to merge')
1973 if parent != repo.lookup(repo[None].branch()):
1971 if parent != repo.lookup(repo[None].branch()):
1974 msg = _('%s - use "hg update" instead') % msg
1972 msg = _('%s - use "hg update" instead') % msg
1975 raise util.Abort(msg)
1973 raise util.Abort(msg)
1976
1974
1977 if parent not in bheads:
1975 if parent not in bheads:
1978 raise util.Abort(_('working dir not at a head rev - '
1976 raise util.Abort(_('working dir not at a head rev - '
1979 'use "hg update" or merge with an explicit rev'))
1977 'use "hg update" or merge with an explicit rev'))
1980 node = parent == bheads[0] and bheads[-1] or bheads[0]
1978 node = parent == bheads[0] and bheads[-1] or bheads[0]
1981 return hg.merge(repo, node, force=force)
1979 return hg.merge(repo, node, force=force)
1982
1980
1983 def outgoing(ui, repo, dest=None, **opts):
1981 def outgoing(ui, repo, dest=None, **opts):
1984 """show changesets not found in destination
1982 """show changesets not found in destination
1985
1983
1986 Show changesets not found in the specified destination repository or
1984 Show changesets not found in the specified destination repository or
1987 the default push location. These are the changesets that would be pushed
1985 the default push location. These are the changesets that would be pushed
1988 if a push was requested.
1986 if a push was requested.
1989
1987
1990 See pull for valid destination format details.
1988 See pull for valid destination format details.
1991 """
1989 """
1992 limit = cmdutil.loglimit(opts)
1990 limit = cmdutil.loglimit(opts)
1993 dest, revs, checkout = hg.parseurl(
1991 dest, revs, checkout = hg.parseurl(
1994 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
1992 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
1995 cmdutil.setremoteconfig(ui, opts)
1993 cmdutil.setremoteconfig(ui, opts)
1996 if revs:
1994 if revs:
1997 revs = [repo.lookup(rev) for rev in revs]
1995 revs = [repo.lookup(rev) for rev in revs]
1998
1996
1999 other = hg.repository(ui, dest)
1997 other = hg.repository(ui, dest)
2000 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
1998 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2001 o = repo.findoutgoing(other, force=opts.get('force'))
1999 o = repo.findoutgoing(other, force=opts.get('force'))
2002 if not o:
2000 if not o:
2003 ui.status(_("no changes found\n"))
2001 ui.status(_("no changes found\n"))
2004 return 1
2002 return 1
2005 o = repo.changelog.nodesbetween(o, revs)[0]
2003 o = repo.changelog.nodesbetween(o, revs)[0]
2006 if opts.get('newest_first'):
2004 if opts.get('newest_first'):
2007 o.reverse()
2005 o.reverse()
2008 displayer = cmdutil.show_changeset(ui, repo, opts)
2006 displayer = cmdutil.show_changeset(ui, repo, opts)
2009 count = 0
2007 count = 0
2010 for n in o:
2008 for n in o:
2011 if count >= limit:
2009 if count >= limit:
2012 break
2010 break
2013 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2011 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2014 if opts.get('no_merges') and len(parents) == 2:
2012 if opts.get('no_merges') and len(parents) == 2:
2015 continue
2013 continue
2016 count += 1
2014 count += 1
2017 displayer.show(changenode=n)
2015 displayer.show(changenode=n)
2018
2016
2019 def parents(ui, repo, file_=None, **opts):
2017 def parents(ui, repo, file_=None, **opts):
2020 """show the parents of the working dir or revision
2018 """show the parents of the working dir or revision
2021
2019
2022 Print the working directory's parent revisions. If a
2020 Print the working directory's parent revisions. If a
2023 revision is given via --rev, the parent of that revision
2021 revision is given via --rev, the parent of that revision
2024 will be printed. If a file argument is given, revision in
2022 will be printed. If a file argument is given, revision in
2025 which the file was last changed (before the working directory
2023 which the file was last changed (before the working directory
2026 revision or the argument to --rev if given) is printed.
2024 revision or the argument to --rev if given) is printed.
2027 """
2025 """
2028 rev = opts.get('rev')
2026 rev = opts.get('rev')
2029 if rev:
2027 if rev:
2030 ctx = repo[rev]
2028 ctx = repo[rev]
2031 else:
2029 else:
2032 ctx = repo[None]
2030 ctx = repo[None]
2033
2031
2034 if file_:
2032 if file_:
2035 m = cmdutil.match(repo, (file_,), opts)
2033 m = cmdutil.match(repo, (file_,), opts)
2036 if m.anypats() or len(m.files()) != 1:
2034 if m.anypats() or len(m.files()) != 1:
2037 raise util.Abort(_('can only specify an explicit file name'))
2035 raise util.Abort(_('can only specify an explicit file name'))
2038 file_ = m.files()[0]
2036 file_ = m.files()[0]
2039 filenodes = []
2037 filenodes = []
2040 for cp in ctx.parents():
2038 for cp in ctx.parents():
2041 if not cp:
2039 if not cp:
2042 continue
2040 continue
2043 try:
2041 try:
2044 filenodes.append(cp.filenode(file_))
2042 filenodes.append(cp.filenode(file_))
2045 except revlog.LookupError:
2043 except revlog.LookupError:
2046 pass
2044 pass
2047 if not filenodes:
2045 if not filenodes:
2048 raise util.Abort(_("'%s' not found in manifest!") % file_)
2046 raise util.Abort(_("'%s' not found in manifest!") % file_)
2049 fl = repo.file(file_)
2047 fl = repo.file(file_)
2050 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
2048 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
2051 else:
2049 else:
2052 p = [cp.node() for cp in ctx.parents()]
2050 p = [cp.node() for cp in ctx.parents()]
2053
2051
2054 displayer = cmdutil.show_changeset(ui, repo, opts)
2052 displayer = cmdutil.show_changeset(ui, repo, opts)
2055 for n in p:
2053 for n in p:
2056 if n != nullid:
2054 if n != nullid:
2057 displayer.show(changenode=n)
2055 displayer.show(changenode=n)
2058
2056
2059 def paths(ui, repo, search=None):
2057 def paths(ui, repo, search=None):
2060 """show definition of symbolic path names
2058 """show definition of symbolic path names
2061
2059
2062 Show definition of symbolic path name NAME. If no name is given, show
2060 Show definition of symbolic path name NAME. If no name is given, show
2063 definition of available names.
2061 definition of available names.
2064
2062
2065 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2063 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2066 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2064 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2067 """
2065 """
2068 if search:
2066 if search:
2069 for name, path in ui.configitems("paths"):
2067 for name, path in ui.configitems("paths"):
2070 if name == search:
2068 if name == search:
2071 ui.write("%s\n" % url.hidepassword(path))
2069 ui.write("%s\n" % url.hidepassword(path))
2072 return
2070 return
2073 ui.warn(_("not found!\n"))
2071 ui.warn(_("not found!\n"))
2074 return 1
2072 return 1
2075 else:
2073 else:
2076 for name, path in ui.configitems("paths"):
2074 for name, path in ui.configitems("paths"):
2077 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2075 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2078
2076
2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2077 def postincoming(ui, repo, modheads, optupdate, checkout):
2080 if modheads == 0:
2078 if modheads == 0:
2081 return
2079 return
2082 if optupdate:
2080 if optupdate:
2083 if modheads <= 1 or checkout:
2081 if modheads <= 1 or checkout:
2084 return hg.update(repo, checkout)
2082 return hg.update(repo, checkout)
2085 else:
2083 else:
2086 ui.status(_("not updating, since new heads added\n"))
2084 ui.status(_("not updating, since new heads added\n"))
2087 if modheads > 1:
2085 if modheads > 1:
2088 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2086 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2089 else:
2087 else:
2090 ui.status(_("(run 'hg update' to get a working copy)\n"))
2088 ui.status(_("(run 'hg update' to get a working copy)\n"))
2091
2089
2092 def pull(ui, repo, source="default", **opts):
2090 def pull(ui, repo, source="default", **opts):
2093 """pull changes from the specified source
2091 """pull changes from the specified source
2094
2092
2095 Pull changes from a remote repository to a local one.
2093 Pull changes from a remote repository to a local one.
2096
2094
2097 This finds all changes from the repository at the specified path
2095 This finds all changes from the repository at the specified path
2098 or URL and adds them to the local repository. By default, this
2096 or URL and adds them to the local repository. By default, this
2099 does not update the copy of the project in the working directory.
2097 does not update the copy of the project in the working directory.
2100
2098
2101 Valid URLs are of the form:
2099 Valid URLs are of the form:
2102
2100
2103 local/filesystem/path (or file://local/filesystem/path)
2101 local/filesystem/path (or file://local/filesystem/path)
2104 http://[user[:pass]@]host[:port]/[path]
2102 http://[user[:pass]@]host[:port]/[path]
2105 https://[user[:pass]@]host[:port]/[path]
2103 https://[user[:pass]@]host[:port]/[path]
2106 ssh://[user[:pass]@]host[:port]/[path]
2104 ssh://[user[:pass]@]host[:port]/[path]
2107
2105
2108 Paths in the local filesystem can either point to Mercurial
2106 Paths in the local filesystem can either point to Mercurial
2109 repositories or to bundle files (as created by 'hg bundle' or
2107 repositories or to bundle files (as created by 'hg bundle' or
2110 'hg incoming --bundle').
2108 'hg incoming --bundle').
2111
2109
2112 An optional identifier after # indicates a particular branch, tag,
2110 An optional identifier after # indicates a particular branch, tag,
2113 or changeset to pull.
2111 or changeset to pull.
2114
2112
2115 Some notes about using SSH with Mercurial:
2113 Some notes about using SSH with Mercurial:
2116 - SSH requires an accessible shell account on the destination machine
2114 - SSH requires an accessible shell account on the destination machine
2117 and a copy of hg in the remote path or specified with as remotecmd.
2115 and a copy of hg in the remote path or specified with as remotecmd.
2118 - path is relative to the remote user's home directory by default.
2116 - path is relative to the remote user's home directory by default.
2119 Use an extra slash at the start of a path to specify an absolute path:
2117 Use an extra slash at the start of a path to specify an absolute path:
2120 ssh://example.com//tmp/repository
2118 ssh://example.com//tmp/repository
2121 - Mercurial doesn't use its own compression via SSH; the right thing
2119 - Mercurial doesn't use its own compression via SSH; the right thing
2122 to do is to configure it in your ~/.ssh/config, e.g.:
2120 to do is to configure it in your ~/.ssh/config, e.g.:
2123 Host *.mylocalnetwork.example.com
2121 Host *.mylocalnetwork.example.com
2124 Compression no
2122 Compression no
2125 Host *
2123 Host *
2126 Compression yes
2124 Compression yes
2127 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2125 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2128 with the --ssh command line option.
2126 with the --ssh command line option.
2129 """
2127 """
2130 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2128 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2131 cmdutil.setremoteconfig(ui, opts)
2129 cmdutil.setremoteconfig(ui, opts)
2132
2130
2133 other = hg.repository(ui, source)
2131 other = hg.repository(ui, source)
2134 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2132 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2135 if revs:
2133 if revs:
2136 try:
2134 try:
2137 revs = [other.lookup(rev) for rev in revs]
2135 revs = [other.lookup(rev) for rev in revs]
2138 except NoCapability:
2136 except NoCapability:
2139 error = _("Other repository doesn't support revision lookup, "
2137 error = _("Other repository doesn't support revision lookup, "
2140 "so a rev cannot be specified.")
2138 "so a rev cannot be specified.")
2141 raise util.Abort(error)
2139 raise util.Abort(error)
2142
2140
2143 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2141 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2144 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2142 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2145
2143
2146 def push(ui, repo, dest=None, **opts):
2144 def push(ui, repo, dest=None, **opts):
2147 """push changes to the specified destination
2145 """push changes to the specified destination
2148
2146
2149 Push changes from the local repository to the given destination.
2147 Push changes from the local repository to the given destination.
2150
2148
2151 This is the symmetrical operation for pull. It helps to move
2149 This is the symmetrical operation for pull. It helps to move
2152 changes from the current repository to a different one. If the
2150 changes from the current repository to a different one. If the
2153 destination is local this is identical to a pull in that directory
2151 destination is local this is identical to a pull in that directory
2154 from the current one.
2152 from the current one.
2155
2153
2156 By default, push will refuse to run if it detects the result would
2154 By default, push will refuse to run if it detects the result would
2157 increase the number of remote heads. This generally indicates the
2155 increase the number of remote heads. This generally indicates the
2158 the client has forgotten to pull and merge before pushing.
2156 the client has forgotten to pull and merge before pushing.
2159
2157
2160 Valid URLs are of the form:
2158 Valid URLs are of the form:
2161
2159
2162 local/filesystem/path (or file://local/filesystem/path)
2160 local/filesystem/path (or file://local/filesystem/path)
2163 ssh://[user[:pass]@]host[:port]/[path]
2161 ssh://[user[:pass]@]host[:port]/[path]
2164 http://[user[:pass]@]host[:port]/[path]
2162 http://[user[:pass]@]host[:port]/[path]
2165 https://[user[:pass]@]host[:port]/[path]
2163 https://[user[:pass]@]host[:port]/[path]
2166
2164
2167 An optional identifier after # indicates a particular branch, tag,
2165 An optional identifier after # indicates a particular branch, tag,
2168 or changeset to push. If -r is used, the named changeset and all its
2166 or changeset to push. If -r is used, the named changeset and all its
2169 ancestors will be pushed to the remote repository.
2167 ancestors will be pushed to the remote repository.
2170
2168
2171 Look at the help text for the pull command for important details
2169 Look at the help text for the pull command for important details
2172 about ssh:// URLs.
2170 about ssh:// URLs.
2173
2171
2174 Pushing to http:// and https:// URLs is only possible, if this
2172 Pushing to http:// and https:// URLs is only possible, if this
2175 feature is explicitly enabled on the remote Mercurial server.
2173 feature is explicitly enabled on the remote Mercurial server.
2176 """
2174 """
2177 dest, revs, checkout = hg.parseurl(
2175 dest, revs, checkout = hg.parseurl(
2178 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2176 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2179 cmdutil.setremoteconfig(ui, opts)
2177 cmdutil.setremoteconfig(ui, opts)
2180
2178
2181 other = hg.repository(ui, dest)
2179 other = hg.repository(ui, dest)
2182 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2180 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2183 if revs:
2181 if revs:
2184 revs = [repo.lookup(rev) for rev in revs]
2182 revs = [repo.lookup(rev) for rev in revs]
2185 r = repo.push(other, opts.get('force'), revs=revs)
2183 r = repo.push(other, opts.get('force'), revs=revs)
2186 return r == 0
2184 return r == 0
2187
2185
2188 def rawcommit(ui, repo, *pats, **opts):
2186 def rawcommit(ui, repo, *pats, **opts):
2189 """raw commit interface (DEPRECATED)
2187 """raw commit interface (DEPRECATED)
2190
2188
2191 (DEPRECATED)
2189 (DEPRECATED)
2192 Lowlevel commit, for use in helper scripts.
2190 Lowlevel commit, for use in helper scripts.
2193
2191
2194 This command is not intended to be used by normal users, as it is
2192 This command is not intended to be used by normal users, as it is
2195 primarily useful for importing from other SCMs.
2193 primarily useful for importing from other SCMs.
2196
2194
2197 This command is now deprecated and will be removed in a future
2195 This command is now deprecated and will be removed in a future
2198 release, please use debugsetparents and commit instead.
2196 release, please use debugsetparents and commit instead.
2199 """
2197 """
2200
2198
2201 ui.warn(_("(the rawcommit command is deprecated)\n"))
2199 ui.warn(_("(the rawcommit command is deprecated)\n"))
2202
2200
2203 message = cmdutil.logmessage(opts)
2201 message = cmdutil.logmessage(opts)
2204
2202
2205 files = cmdutil.match(repo, pats, opts).files()
2203 files = cmdutil.match(repo, pats, opts).files()
2206 if opts.get('files'):
2204 if opts.get('files'):
2207 files += open(opts['files']).read().splitlines()
2205 files += open(opts['files']).read().splitlines()
2208
2206
2209 parents = [repo.lookup(p) for p in opts['parent']]
2207 parents = [repo.lookup(p) for p in opts['parent']]
2210
2208
2211 try:
2209 try:
2212 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2210 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2213 except ValueError, inst:
2211 except ValueError, inst:
2214 raise util.Abort(str(inst))
2212 raise util.Abort(str(inst))
2215
2213
2216 def recover(ui, repo):
2214 def recover(ui, repo):
2217 """roll back an interrupted transaction
2215 """roll back an interrupted transaction
2218
2216
2219 Recover from an interrupted commit or pull.
2217 Recover from an interrupted commit or pull.
2220
2218
2221 This command tries to fix the repository status after an interrupted
2219 This command tries to fix the repository status after an interrupted
2222 operation. It should only be necessary when Mercurial suggests it.
2220 operation. It should only be necessary when Mercurial suggests it.
2223 """
2221 """
2224 if repo.recover():
2222 if repo.recover():
2225 return hg.verify(repo)
2223 return hg.verify(repo)
2226 return 1
2224 return 1
2227
2225
2228 def remove(ui, repo, *pats, **opts):
2226 def remove(ui, repo, *pats, **opts):
2229 """remove the specified files on the next commit
2227 """remove the specified files on the next commit
2230
2228
2231 Schedule the indicated files for removal from the repository.
2229 Schedule the indicated files for removal from the repository.
2232
2230
2233 This only removes files from the current branch, not from the entire
2231 This only removes files from the current branch, not from the entire
2234 project history. -A can be used to remove only files that have already
2232 project history. -A can be used to remove only files that have already
2235 been deleted, -f can be used to force deletion, and -Af can be used
2233 been deleted, -f can be used to force deletion, and -Af can be used
2236 to remove files from the next revision without deleting them.
2234 to remove files from the next revision without deleting them.
2237
2235
2238 The following table details the behavior of remove for different file
2236 The following table details the behavior of remove for different file
2239 states (columns) and option combinations (rows). The file states are
2237 states (columns) and option combinations (rows). The file states are
2240 Added, Clean, Modified and Missing (as reported by hg status). The
2238 Added, Clean, Modified and Missing (as reported by hg status). The
2241 actions are Warn, Remove (from branch) and Delete (from disk).
2239 actions are Warn, Remove (from branch) and Delete (from disk).
2242
2240
2243 A C M !
2241 A C M !
2244 none W RD W R
2242 none W RD W R
2245 -f R RD RD R
2243 -f R RD RD R
2246 -A W W W R
2244 -A W W W R
2247 -Af R R R R
2245 -Af R R R R
2248
2246
2249 This command schedules the files to be removed at the next commit.
2247 This command schedules the files to be removed at the next commit.
2250 To undo a remove before that, see hg revert.
2248 To undo a remove before that, see hg revert.
2251 """
2249 """
2252
2250
2253 after, force = opts.get('after'), opts.get('force')
2251 after, force = opts.get('after'), opts.get('force')
2254 if not pats and not after:
2252 if not pats and not after:
2255 raise util.Abort(_('no files specified'))
2253 raise util.Abort(_('no files specified'))
2256
2254
2257 m = cmdutil.match(repo, pats, opts)
2255 m = cmdutil.match(repo, pats, opts)
2258 s = repo.status(match=m, clean=True)
2256 s = repo.status(match=m, clean=True)
2259 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2257 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2260
2258
2261 def warn(files, reason):
2259 def warn(files, reason):
2262 for f in files:
2260 for f in files:
2263 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2261 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2264 % (m.rel(f), reason))
2262 % (m.rel(f), reason))
2265
2263
2266 if force:
2264 if force:
2267 remove, forget = modified + deleted + clean, added
2265 remove, forget = modified + deleted + clean, added
2268 elif after:
2266 elif after:
2269 remove, forget = deleted, []
2267 remove, forget = deleted, []
2270 warn(modified + added + clean, _('still exists'))
2268 warn(modified + added + clean, _('still exists'))
2271 else:
2269 else:
2272 remove, forget = deleted + clean, []
2270 remove, forget = deleted + clean, []
2273 warn(modified, _('is modified'))
2271 warn(modified, _('is modified'))
2274 warn(added, _('has been marked for add'))
2272 warn(added, _('has been marked for add'))
2275
2273
2276 for f in util.sort(remove + forget):
2274 for f in util.sort(remove + forget):
2277 if ui.verbose or not m.exact(f):
2275 if ui.verbose or not m.exact(f):
2278 ui.status(_('removing %s\n') % m.rel(f))
2276 ui.status(_('removing %s\n') % m.rel(f))
2279
2277
2280 repo.forget(forget)
2278 repo.forget(forget)
2281 repo.remove(remove, unlink=not after)
2279 repo.remove(remove, unlink=not after)
2282
2280
2283 def rename(ui, repo, *pats, **opts):
2281 def rename(ui, repo, *pats, **opts):
2284 """rename files; equivalent of copy + remove
2282 """rename files; equivalent of copy + remove
2285
2283
2286 Mark dest as copies of sources; mark sources for deletion. If
2284 Mark dest as copies of sources; mark sources for deletion. If
2287 dest is a directory, copies are put in that directory. If dest is
2285 dest is a directory, copies are put in that directory. If dest is
2288 a file, there can only be one source.
2286 a file, there can only be one source.
2289
2287
2290 By default, this command copies the contents of files as they
2288 By default, this command copies the contents of files as they
2291 stand in the working directory. If invoked with --after, the
2289 stand in the working directory. If invoked with --after, the
2292 operation is recorded, but no copying is performed.
2290 operation is recorded, but no copying is performed.
2293
2291
2294 This command takes effect in the next commit. To undo a rename
2292 This command takes effect in the next commit. To undo a rename
2295 before that, see hg revert.
2293 before that, see hg revert.
2296 """
2294 """
2297 wlock = repo.wlock(False)
2295 wlock = repo.wlock(False)
2298 try:
2296 try:
2299 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2297 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2300 finally:
2298 finally:
2301 del wlock
2299 del wlock
2302
2300
2303 def resolve(ui, repo, *pats, **opts):
2301 def resolve(ui, repo, *pats, **opts):
2304 """resolve file merges from a branch merge or update
2302 """resolve file merges from a branch merge or update
2305
2303
2306 This command will attempt to resolve unresolved merges from the
2304 This command will attempt to resolve unresolved merges from the
2307 last update or merge command. This will use the local file
2305 last update or merge command. This will use the local file
2308 revision preserved at the last update or merge to cleanly retry
2306 revision preserved at the last update or merge to cleanly retry
2309 the file merge attempt. With no file or options specified, this
2307 the file merge attempt. With no file or options specified, this
2310 command will attempt to resolve all unresolved files.
2308 command will attempt to resolve all unresolved files.
2311
2309
2312 The codes used to show the status of files are:
2310 The codes used to show the status of files are:
2313 U = unresolved
2311 U = unresolved
2314 R = resolved
2312 R = resolved
2315 """
2313 """
2316
2314
2317 if len([x for x in opts if opts[x]]) > 1:
2315 if len([x for x in opts if opts[x]]) > 1:
2318 raise util.Abort(_("too many options specified"))
2316 raise util.Abort(_("too many options specified"))
2319
2317
2320 ms = merge_.mergestate(repo)
2318 ms = merge_.mergestate(repo)
2321 m = cmdutil.match(repo, pats, opts)
2319 m = cmdutil.match(repo, pats, opts)
2322
2320
2323 for f in ms:
2321 for f in ms:
2324 if m(f):
2322 if m(f):
2325 if opts.get("list"):
2323 if opts.get("list"):
2326 ui.write("%s %s\n" % (ms[f].upper(), f))
2324 ui.write("%s %s\n" % (ms[f].upper(), f))
2327 elif opts.get("mark"):
2325 elif opts.get("mark"):
2328 ms.mark(f, "r")
2326 ms.mark(f, "r")
2329 elif opts.get("unmark"):
2327 elif opts.get("unmark"):
2330 ms.mark(f, "u")
2328 ms.mark(f, "u")
2331 else:
2329 else:
2332 wctx = repo[None]
2330 wctx = repo[None]
2333 mctx = wctx.parents()[-1]
2331 mctx = wctx.parents()[-1]
2334 ms.resolve(f, wctx, mctx)
2332 ms.resolve(f, wctx, mctx)
2335
2333
2336 def revert(ui, repo, *pats, **opts):
2334 def revert(ui, repo, *pats, **opts):
2337 """restore individual files or dirs to an earlier state
2335 """restore individual files or dirs to an earlier state
2338
2336
2339 (use update -r to check out earlier revisions, revert does not
2337 (use update -r to check out earlier revisions, revert does not
2340 change the working dir parents)
2338 change the working dir parents)
2341
2339
2342 With no revision specified, revert the named files or directories
2340 With no revision specified, revert the named files or directories
2343 to the contents they had in the parent of the working directory.
2341 to the contents they had in the parent of the working directory.
2344 This restores the contents of the affected files to an unmodified
2342 This restores the contents of the affected files to an unmodified
2345 state and unschedules adds, removes, copies, and renames. If the
2343 state and unschedules adds, removes, copies, and renames. If the
2346 working directory has two parents, you must explicitly specify the
2344 working directory has two parents, you must explicitly specify the
2347 revision to revert to.
2345 revision to revert to.
2348
2346
2349 Using the -r option, revert the given files or directories to their
2347 Using the -r option, revert the given files or directories to their
2350 contents as of a specific revision. This can be helpful to "roll
2348 contents as of a specific revision. This can be helpful to "roll
2351 back" some or all of an earlier change.
2349 back" some or all of an earlier change.
2352 See 'hg help dates' for a list of formats valid for -d/--date.
2350 See 'hg help dates' for a list of formats valid for -d/--date.
2353
2351
2354 Revert modifies the working directory. It does not commit any
2352 Revert modifies the working directory. It does not commit any
2355 changes, or change the parent of the working directory. If you
2353 changes, or change the parent of the working directory. If you
2356 revert to a revision other than the parent of the working
2354 revert to a revision other than the parent of the working
2357 directory, the reverted files will thus appear modified
2355 directory, the reverted files will thus appear modified
2358 afterwards.
2356 afterwards.
2359
2357
2360 If a file has been deleted, it is restored. If the executable
2358 If a file has been deleted, it is restored. If the executable
2361 mode of a file was changed, it is reset.
2359 mode of a file was changed, it is reset.
2362
2360
2363 If names are given, all files matching the names are reverted.
2361 If names are given, all files matching the names are reverted.
2364 If no arguments are given, no files are reverted.
2362 If no arguments are given, no files are reverted.
2365
2363
2366 Modified files are saved with a .orig suffix before reverting.
2364 Modified files are saved with a .orig suffix before reverting.
2367 To disable these backups, use --no-backup.
2365 To disable these backups, use --no-backup.
2368 """
2366 """
2369
2367
2370 if opts["date"]:
2368 if opts["date"]:
2371 if opts["rev"]:
2369 if opts["rev"]:
2372 raise util.Abort(_("you can't specify a revision and a date"))
2370 raise util.Abort(_("you can't specify a revision and a date"))
2373 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2371 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2374
2372
2375 if not pats and not opts.get('all'):
2373 if not pats and not opts.get('all'):
2376 raise util.Abort(_('no files or directories specified; '
2374 raise util.Abort(_('no files or directories specified; '
2377 'use --all to revert the whole repo'))
2375 'use --all to revert the whole repo'))
2378
2376
2379 parent, p2 = repo.dirstate.parents()
2377 parent, p2 = repo.dirstate.parents()
2380 if not opts.get('rev') and p2 != nullid:
2378 if not opts.get('rev') and p2 != nullid:
2381 raise util.Abort(_('uncommitted merge - please provide a '
2379 raise util.Abort(_('uncommitted merge - please provide a '
2382 'specific revision'))
2380 'specific revision'))
2383 ctx = repo[opts.get('rev')]
2381 ctx = repo[opts.get('rev')]
2384 node = ctx.node()
2382 node = ctx.node()
2385 mf = ctx.manifest()
2383 mf = ctx.manifest()
2386 if node == parent:
2384 if node == parent:
2387 pmf = mf
2385 pmf = mf
2388 else:
2386 else:
2389 pmf = None
2387 pmf = None
2390
2388
2391 # need all matching names in dirstate and manifest of target rev,
2389 # need all matching names in dirstate and manifest of target rev,
2392 # so have to walk both. do not print errors if files exist in one
2390 # so have to walk both. do not print errors if files exist in one
2393 # but not other.
2391 # but not other.
2394
2392
2395 names = {}
2393 names = {}
2396
2394
2397 wlock = repo.wlock()
2395 wlock = repo.wlock()
2398 try:
2396 try:
2399 # walk dirstate.
2397 # walk dirstate.
2400 files = []
2398 files = []
2401
2399
2402 m = cmdutil.match(repo, pats, opts)
2400 m = cmdutil.match(repo, pats, opts)
2403 m.bad = lambda x,y: False
2401 m.bad = lambda x,y: False
2404 for abs in repo.walk(m):
2402 for abs in repo.walk(m):
2405 names[abs] = m.rel(abs), m.exact(abs)
2403 names[abs] = m.rel(abs), m.exact(abs)
2406
2404
2407 # walk target manifest.
2405 # walk target manifest.
2408
2406
2409 def badfn(path, msg):
2407 def badfn(path, msg):
2410 if path in names:
2408 if path in names:
2411 return False
2409 return False
2412 path_ = path + '/'
2410 path_ = path + '/'
2413 for f in names:
2411 for f in names:
2414 if f.startswith(path_):
2412 if f.startswith(path_):
2415 return False
2413 return False
2416 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2414 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2417 return False
2415 return False
2418
2416
2419 m = cmdutil.match(repo, pats, opts)
2417 m = cmdutil.match(repo, pats, opts)
2420 m.bad = badfn
2418 m.bad = badfn
2421 for abs in repo[node].walk(m):
2419 for abs in repo[node].walk(m):
2422 if abs not in names:
2420 if abs not in names:
2423 names[abs] = m.rel(abs), m.exact(abs)
2421 names[abs] = m.rel(abs), m.exact(abs)
2424
2422
2425 m = cmdutil.matchfiles(repo, names)
2423 m = cmdutil.matchfiles(repo, names)
2426 changes = repo.status(match=m)[:4]
2424 changes = repo.status(match=m)[:4]
2427 modified, added, removed, deleted = map(dict.fromkeys, changes)
2425 modified, added, removed, deleted = map(dict.fromkeys, changes)
2428
2426
2429 # if f is a rename, also revert the source
2427 # if f is a rename, also revert the source
2430 cwd = repo.getcwd()
2428 cwd = repo.getcwd()
2431 for f in added:
2429 for f in added:
2432 src = repo.dirstate.copied(f)
2430 src = repo.dirstate.copied(f)
2433 if src and src not in names and repo.dirstate[src] == 'r':
2431 if src and src not in names and repo.dirstate[src] == 'r':
2434 removed[src] = None
2432 removed[src] = None
2435 names[src] = (repo.pathto(src, cwd), True)
2433 names[src] = (repo.pathto(src, cwd), True)
2436
2434
2437 def removeforget(abs):
2435 def removeforget(abs):
2438 if repo.dirstate[abs] == 'a':
2436 if repo.dirstate[abs] == 'a':
2439 return _('forgetting %s\n')
2437 return _('forgetting %s\n')
2440 return _('removing %s\n')
2438 return _('removing %s\n')
2441
2439
2442 revert = ([], _('reverting %s\n'))
2440 revert = ([], _('reverting %s\n'))
2443 add = ([], _('adding %s\n'))
2441 add = ([], _('adding %s\n'))
2444 remove = ([], removeforget)
2442 remove = ([], removeforget)
2445 undelete = ([], _('undeleting %s\n'))
2443 undelete = ([], _('undeleting %s\n'))
2446
2444
2447 disptable = (
2445 disptable = (
2448 # dispatch table:
2446 # dispatch table:
2449 # file state
2447 # file state
2450 # action if in target manifest
2448 # action if in target manifest
2451 # action if not in target manifest
2449 # action if not in target manifest
2452 # make backup if in target manifest
2450 # make backup if in target manifest
2453 # make backup if not in target manifest
2451 # make backup if not in target manifest
2454 (modified, revert, remove, True, True),
2452 (modified, revert, remove, True, True),
2455 (added, revert, remove, True, False),
2453 (added, revert, remove, True, False),
2456 (removed, undelete, None, False, False),
2454 (removed, undelete, None, False, False),
2457 (deleted, revert, remove, False, False),
2455 (deleted, revert, remove, False, False),
2458 )
2456 )
2459
2457
2460 for abs, (rel, exact) in util.sort(names.items()):
2458 for abs, (rel, exact) in util.sort(names.items()):
2461 mfentry = mf.get(abs)
2459 mfentry = mf.get(abs)
2462 target = repo.wjoin(abs)
2460 target = repo.wjoin(abs)
2463 def handle(xlist, dobackup):
2461 def handle(xlist, dobackup):
2464 xlist[0].append(abs)
2462 xlist[0].append(abs)
2465 if dobackup and not opts.get('no_backup') and util.lexists(target):
2463 if dobackup and not opts.get('no_backup') and util.lexists(target):
2466 bakname = "%s.orig" % rel
2464 bakname = "%s.orig" % rel
2467 ui.note(_('saving current version of %s as %s\n') %
2465 ui.note(_('saving current version of %s as %s\n') %
2468 (rel, bakname))
2466 (rel, bakname))
2469 if not opts.get('dry_run'):
2467 if not opts.get('dry_run'):
2470 util.copyfile(target, bakname)
2468 util.copyfile(target, bakname)
2471 if ui.verbose or not exact:
2469 if ui.verbose or not exact:
2472 msg = xlist[1]
2470 msg = xlist[1]
2473 if not isinstance(msg, basestring):
2471 if not isinstance(msg, basestring):
2474 msg = msg(abs)
2472 msg = msg(abs)
2475 ui.status(msg % rel)
2473 ui.status(msg % rel)
2476 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2474 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2477 if abs not in table: continue
2475 if abs not in table: continue
2478 # file has changed in dirstate
2476 # file has changed in dirstate
2479 if mfentry:
2477 if mfentry:
2480 handle(hitlist, backuphit)
2478 handle(hitlist, backuphit)
2481 elif misslist is not None:
2479 elif misslist is not None:
2482 handle(misslist, backupmiss)
2480 handle(misslist, backupmiss)
2483 break
2481 break
2484 else:
2482 else:
2485 if abs not in repo.dirstate:
2483 if abs not in repo.dirstate:
2486 if mfentry:
2484 if mfentry:
2487 handle(add, True)
2485 handle(add, True)
2488 elif exact:
2486 elif exact:
2489 ui.warn(_('file not managed: %s\n') % rel)
2487 ui.warn(_('file not managed: %s\n') % rel)
2490 continue
2488 continue
2491 # file has not changed in dirstate
2489 # file has not changed in dirstate
2492 if node == parent:
2490 if node == parent:
2493 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2491 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2494 continue
2492 continue
2495 if pmf is None:
2493 if pmf is None:
2496 # only need parent manifest in this unlikely case,
2494 # only need parent manifest in this unlikely case,
2497 # so do not read by default
2495 # so do not read by default
2498 pmf = repo[parent].manifest()
2496 pmf = repo[parent].manifest()
2499 if abs in pmf:
2497 if abs in pmf:
2500 if mfentry:
2498 if mfentry:
2501 # if version of file is same in parent and target
2499 # if version of file is same in parent and target
2502 # manifests, do nothing
2500 # manifests, do nothing
2503 if (pmf[abs] != mfentry or
2501 if (pmf[abs] != mfentry or
2504 pmf.flags(abs) != mf.flags(abs)):
2502 pmf.flags(abs) != mf.flags(abs)):
2505 handle(revert, False)
2503 handle(revert, False)
2506 else:
2504 else:
2507 handle(remove, False)
2505 handle(remove, False)
2508
2506
2509 if not opts.get('dry_run'):
2507 if not opts.get('dry_run'):
2510 def checkout(f):
2508 def checkout(f):
2511 fc = ctx[f]
2509 fc = ctx[f]
2512 repo.wwrite(f, fc.data(), fc.flags())
2510 repo.wwrite(f, fc.data(), fc.flags())
2513
2511
2514 audit_path = util.path_auditor(repo.root)
2512 audit_path = util.path_auditor(repo.root)
2515 for f in remove[0]:
2513 for f in remove[0]:
2516 if repo.dirstate[f] == 'a':
2514 if repo.dirstate[f] == 'a':
2517 repo.dirstate.forget(f)
2515 repo.dirstate.forget(f)
2518 continue
2516 continue
2519 audit_path(f)
2517 audit_path(f)
2520 try:
2518 try:
2521 util.unlink(repo.wjoin(f))
2519 util.unlink(repo.wjoin(f))
2522 except OSError:
2520 except OSError:
2523 pass
2521 pass
2524 repo.dirstate.remove(f)
2522 repo.dirstate.remove(f)
2525
2523
2526 normal = None
2524 normal = None
2527 if node == parent:
2525 if node == parent:
2528 # We're reverting to our parent. If possible, we'd like status
2526 # We're reverting to our parent. If possible, we'd like status
2529 # to report the file as clean. We have to use normallookup for
2527 # to report the file as clean. We have to use normallookup for
2530 # merges to avoid losing information about merged/dirty files.
2528 # merges to avoid losing information about merged/dirty files.
2531 if p2 != nullid:
2529 if p2 != nullid:
2532 normal = repo.dirstate.normallookup
2530 normal = repo.dirstate.normallookup
2533 else:
2531 else:
2534 normal = repo.dirstate.normal
2532 normal = repo.dirstate.normal
2535 for f in revert[0]:
2533 for f in revert[0]:
2536 checkout(f)
2534 checkout(f)
2537 if normal:
2535 if normal:
2538 normal(f)
2536 normal(f)
2539
2537
2540 for f in add[0]:
2538 for f in add[0]:
2541 checkout(f)
2539 checkout(f)
2542 repo.dirstate.add(f)
2540 repo.dirstate.add(f)
2543
2541
2544 normal = repo.dirstate.normallookup
2542 normal = repo.dirstate.normallookup
2545 if node == parent and p2 == nullid:
2543 if node == parent and p2 == nullid:
2546 normal = repo.dirstate.normal
2544 normal = repo.dirstate.normal
2547 for f in undelete[0]:
2545 for f in undelete[0]:
2548 checkout(f)
2546 checkout(f)
2549 normal(f)
2547 normal(f)
2550
2548
2551 finally:
2549 finally:
2552 del wlock
2550 del wlock
2553
2551
2554 def rollback(ui, repo):
2552 def rollback(ui, repo):
2555 """roll back the last transaction
2553 """roll back the last transaction
2556
2554
2557 This command should be used with care. There is only one level of
2555 This command should be used with care. There is only one level of
2558 rollback, and there is no way to undo a rollback. It will also
2556 rollback, and there is no way to undo a rollback. It will also
2559 restore the dirstate at the time of the last transaction, losing
2557 restore the dirstate at the time of the last transaction, losing
2560 any dirstate changes since that time.
2558 any dirstate changes since that time.
2561
2559
2562 Transactions are used to encapsulate the effects of all commands
2560 Transactions are used to encapsulate the effects of all commands
2563 that create new changesets or propagate existing changesets into a
2561 that create new changesets or propagate existing changesets into a
2564 repository. For example, the following commands are transactional,
2562 repository. For example, the following commands are transactional,
2565 and their effects can be rolled back:
2563 and their effects can be rolled back:
2566
2564
2567 commit
2565 commit
2568 import
2566 import
2569 pull
2567 pull
2570 push (with this repository as destination)
2568 push (with this repository as destination)
2571 unbundle
2569 unbundle
2572
2570
2573 This command is not intended for use on public repositories. Once
2571 This command is not intended for use on public repositories. Once
2574 changes are visible for pull by other users, rolling a transaction
2572 changes are visible for pull by other users, rolling a transaction
2575 back locally is ineffective (someone else may already have pulled
2573 back locally is ineffective (someone else may already have pulled
2576 the changes). Furthermore, a race is possible with readers of the
2574 the changes). Furthermore, a race is possible with readers of the
2577 repository; for example an in-progress pull from the repository
2575 repository; for example an in-progress pull from the repository
2578 may fail if a rollback is performed.
2576 may fail if a rollback is performed.
2579 """
2577 """
2580 repo.rollback()
2578 repo.rollback()
2581
2579
2582 def root(ui, repo):
2580 def root(ui, repo):
2583 """print the root (top) of the current working dir
2581 """print the root (top) of the current working dir
2584
2582
2585 Print the root directory of the current repository.
2583 Print the root directory of the current repository.
2586 """
2584 """
2587 ui.write(repo.root + "\n")
2585 ui.write(repo.root + "\n")
2588
2586
2589 def serve(ui, repo, **opts):
2587 def serve(ui, repo, **opts):
2590 """export the repository via HTTP
2588 """export the repository via HTTP
2591
2589
2592 Start a local HTTP repository browser and pull server.
2590 Start a local HTTP repository browser and pull server.
2593
2591
2594 By default, the server logs accesses to stdout and errors to
2592 By default, the server logs accesses to stdout and errors to
2595 stderr. Use the "-A" and "-E" options to log to files.
2593 stderr. Use the "-A" and "-E" options to log to files.
2596 """
2594 """
2597
2595
2598 if opts["stdio"]:
2596 if opts["stdio"]:
2599 if repo is None:
2597 if repo is None:
2600 raise RepoError(_("There is no Mercurial repository here"
2598 raise RepoError(_("There is no Mercurial repository here"
2601 " (.hg not found)"))
2599 " (.hg not found)"))
2602 s = sshserver.sshserver(ui, repo)
2600 s = sshserver.sshserver(ui, repo)
2603 s.serve_forever()
2601 s.serve_forever()
2604
2602
2605 parentui = ui.parentui or ui
2603 parentui = ui.parentui or ui
2606 optlist = ("name templates style address port prefix ipv6"
2604 optlist = ("name templates style address port prefix ipv6"
2607 " accesslog errorlog webdir_conf certificate")
2605 " accesslog errorlog webdir_conf certificate")
2608 for o in optlist.split():
2606 for o in optlist.split():
2609 if opts[o]:
2607 if opts[o]:
2610 parentui.setconfig("web", o, str(opts[o]))
2608 parentui.setconfig("web", o, str(opts[o]))
2611 if (repo is not None) and (repo.ui != parentui):
2609 if (repo is not None) and (repo.ui != parentui):
2612 repo.ui.setconfig("web", o, str(opts[o]))
2610 repo.ui.setconfig("web", o, str(opts[o]))
2613
2611
2614 if repo is None and not ui.config("web", "webdir_conf"):
2612 if repo is None and not ui.config("web", "webdir_conf"):
2615 raise RepoError(_("There is no Mercurial repository here"
2613 raise RepoError(_("There is no Mercurial repository here"
2616 " (.hg not found)"))
2614 " (.hg not found)"))
2617
2615
2618 class service:
2616 class service:
2619 def init(self):
2617 def init(self):
2620 util.set_signal_handler()
2618 util.set_signal_handler()
2621 self.httpd = hgweb.server.create_server(parentui, repo)
2619 self.httpd = hgweb.server.create_server(parentui, repo)
2622
2620
2623 if not ui.verbose: return
2621 if not ui.verbose: return
2624
2622
2625 if self.httpd.prefix:
2623 if self.httpd.prefix:
2626 prefix = self.httpd.prefix.strip('/') + '/'
2624 prefix = self.httpd.prefix.strip('/') + '/'
2627 else:
2625 else:
2628 prefix = ''
2626 prefix = ''
2629
2627
2630 port = ':%d' % self.httpd.port
2628 port = ':%d' % self.httpd.port
2631 if port == ':80':
2629 if port == ':80':
2632 port = ''
2630 port = ''
2633
2631
2634 bindaddr = self.httpd.addr
2632 bindaddr = self.httpd.addr
2635 if bindaddr == '0.0.0.0':
2633 if bindaddr == '0.0.0.0':
2636 bindaddr = '*'
2634 bindaddr = '*'
2637 elif ':' in bindaddr: # IPv6
2635 elif ':' in bindaddr: # IPv6
2638 bindaddr = '[%s]' % bindaddr
2636 bindaddr = '[%s]' % bindaddr
2639
2637
2640 fqaddr = self.httpd.fqaddr
2638 fqaddr = self.httpd.fqaddr
2641 if ':' in fqaddr:
2639 if ':' in fqaddr:
2642 fqaddr = '[%s]' % fqaddr
2640 fqaddr = '[%s]' % fqaddr
2643 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2641 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2644 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2642 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2645
2643
2646 def run(self):
2644 def run(self):
2647 self.httpd.serve_forever()
2645 self.httpd.serve_forever()
2648
2646
2649 service = service()
2647 service = service()
2650
2648
2651 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2649 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2652
2650
2653 def status(ui, repo, *pats, **opts):
2651 def status(ui, repo, *pats, **opts):
2654 """show changed files in the working directory
2652 """show changed files in the working directory
2655
2653
2656 Show status of files in the repository. If names are given, only
2654 Show status of files in the repository. If names are given, only
2657 files that match are shown. Files that are clean or ignored or
2655 files that match are shown. Files that are clean or ignored or
2658 source of a copy/move operation, are not listed unless -c (clean),
2656 source of a copy/move operation, are not listed unless -c (clean),
2659 -i (ignored), -C (copies) or -A is given. Unless options described
2657 -i (ignored), -C (copies) or -A is given. Unless options described
2660 with "show only ..." are given, the options -mardu are used.
2658 with "show only ..." are given, the options -mardu are used.
2661
2659
2662 Option -q/--quiet hides untracked (unknown and ignored) files
2660 Option -q/--quiet hides untracked (unknown and ignored) files
2663 unless explicitly requested with -u/--unknown or -i/-ignored.
2661 unless explicitly requested with -u/--unknown or -i/-ignored.
2664
2662
2665 NOTE: status may appear to disagree with diff if permissions have
2663 NOTE: status may appear to disagree with diff if permissions have
2666 changed or a merge has occurred. The standard diff format does not
2664 changed or a merge has occurred. The standard diff format does not
2667 report permission changes and diff only reports changes relative
2665 report permission changes and diff only reports changes relative
2668 to one merge parent.
2666 to one merge parent.
2669
2667
2670 If one revision is given, it is used as the base revision.
2668 If one revision is given, it is used as the base revision.
2671 If two revisions are given, the difference between them is shown.
2669 If two revisions are given, the difference between them is shown.
2672
2670
2673 The codes used to show the status of files are:
2671 The codes used to show the status of files are:
2674 M = modified
2672 M = modified
2675 A = added
2673 A = added
2676 R = removed
2674 R = removed
2677 C = clean
2675 C = clean
2678 ! = deleted, but still tracked
2676 ! = deleted, but still tracked
2679 ? = not tracked
2677 ? = not tracked
2680 I = ignored
2678 I = ignored
2681 = the previous added file was copied from here
2679 = the previous added file was copied from here
2682 """
2680 """
2683
2681
2684 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2682 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2685 cwd = (pats and repo.getcwd()) or ''
2683 cwd = (pats and repo.getcwd()) or ''
2686 end = opts.get('print0') and '\0' or '\n'
2684 end = opts.get('print0') and '\0' or '\n'
2687 copy = {}
2685 copy = {}
2688 states = 'modified added removed deleted unknown ignored clean'.split()
2686 states = 'modified added removed deleted unknown ignored clean'.split()
2689 show = [k for k in states if opts[k]]
2687 show = [k for k in states if opts[k]]
2690 if opts.get('all'):
2688 if opts.get('all'):
2691 show += ui.quiet and (states[:4] + ['clean']) or states
2689 show += ui.quiet and (states[:4] + ['clean']) or states
2692 if not show:
2690 if not show:
2693 show = ui.quiet and states[:4] or states[:5]
2691 show = ui.quiet and states[:4] or states[:5]
2694
2692
2695 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2693 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2696 'ignored' in show, 'clean' in show, 'unknown' in show)
2694 'ignored' in show, 'clean' in show, 'unknown' in show)
2697 changestates = zip(states, 'MAR!?IC', stat)
2695 changestates = zip(states, 'MAR!?IC', stat)
2698
2696
2699 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2697 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2700 ctxn = repo[nullid]
2698 ctxn = repo[nullid]
2701 ctx1 = repo[node1]
2699 ctx1 = repo[node1]
2702 ctx2 = repo[node2]
2700 ctx2 = repo[node2]
2703 added = stat[1]
2701 added = stat[1]
2704 if node2 is None:
2702 if node2 is None:
2705 added = stat[0] + stat[1] # merged?
2703 added = stat[0] + stat[1] # merged?
2706
2704
2707 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2705 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2708 if k in added:
2706 if k in added:
2709 copy[k] = v
2707 copy[k] = v
2710 elif v in added:
2708 elif v in added:
2711 copy[v] = k
2709 copy[v] = k
2712
2710
2713 for state, char, files in changestates:
2711 for state, char, files in changestates:
2714 if state in show:
2712 if state in show:
2715 format = "%s %%s%s" % (char, end)
2713 format = "%s %%s%s" % (char, end)
2716 if opts.get('no_status'):
2714 if opts.get('no_status'):
2717 format = "%%s%s" % end
2715 format = "%%s%s" % end
2718
2716
2719 for f in files:
2717 for f in files:
2720 ui.write(format % repo.pathto(f, cwd))
2718 ui.write(format % repo.pathto(f, cwd))
2721 if f in copy:
2719 if f in copy:
2722 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2720 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2723
2721
2724 def tag(ui, repo, name1, *names, **opts):
2722 def tag(ui, repo, name1, *names, **opts):
2725 """add one or more tags for the current or given revision
2723 """add one or more tags for the current or given revision
2726
2724
2727 Name a particular revision using <name>.
2725 Name a particular revision using <name>.
2728
2726
2729 Tags are used to name particular revisions of the repository and are
2727 Tags are used to name particular revisions of the repository and are
2730 very useful to compare different revisions, to go back to significant
2728 very useful to compare different revisions, to go back to significant
2731 earlier versions or to mark branch points as releases, etc.
2729 earlier versions or to mark branch points as releases, etc.
2732
2730
2733 If no revision is given, the parent of the working directory is used,
2731 If no revision is given, the parent of the working directory is used,
2734 or tip if no revision is checked out.
2732 or tip if no revision is checked out.
2735
2733
2736 To facilitate version control, distribution, and merging of tags,
2734 To facilitate version control, distribution, and merging of tags,
2737 they are stored as a file named ".hgtags" which is managed
2735 they are stored as a file named ".hgtags" which is managed
2738 similarly to other project files and can be hand-edited if
2736 similarly to other project files and can be hand-edited if
2739 necessary. The file '.hg/localtags' is used for local tags (not
2737 necessary. The file '.hg/localtags' is used for local tags (not
2740 shared among repositories).
2738 shared among repositories).
2741
2739
2742 See 'hg help dates' for a list of formats valid for -d/--date.
2740 See 'hg help dates' for a list of formats valid for -d/--date.
2743 """
2741 """
2744
2742
2745 rev_ = "."
2743 rev_ = "."
2746 names = (name1,) + names
2744 names = (name1,) + names
2747 if len(names) != len(dict.fromkeys(names)):
2745 if len(names) != len(dict.fromkeys(names)):
2748 raise util.Abort(_('tag names must be unique'))
2746 raise util.Abort(_('tag names must be unique'))
2749 for n in names:
2747 for n in names:
2750 if n in ['tip', '.', 'null']:
2748 if n in ['tip', '.', 'null']:
2751 raise util.Abort(_('the name \'%s\' is reserved') % n)
2749 raise util.Abort(_('the name \'%s\' is reserved') % n)
2752 if opts.get('rev') and opts.get('remove'):
2750 if opts.get('rev') and opts.get('remove'):
2753 raise util.Abort(_("--rev and --remove are incompatible"))
2751 raise util.Abort(_("--rev and --remove are incompatible"))
2754 if opts.get('rev'):
2752 if opts.get('rev'):
2755 rev_ = opts['rev']
2753 rev_ = opts['rev']
2756 message = opts.get('message')
2754 message = opts.get('message')
2757 if opts.get('remove'):
2755 if opts.get('remove'):
2758 expectedtype = opts.get('local') and 'local' or 'global'
2756 expectedtype = opts.get('local') and 'local' or 'global'
2759 for n in names:
2757 for n in names:
2760 if not repo.tagtype(n):
2758 if not repo.tagtype(n):
2761 raise util.Abort(_('tag \'%s\' does not exist') % n)
2759 raise util.Abort(_('tag \'%s\' does not exist') % n)
2762 if repo.tagtype(n) != expectedtype:
2760 if repo.tagtype(n) != expectedtype:
2763 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2761 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2764 (n, expectedtype))
2762 (n, expectedtype))
2765 rev_ = nullid
2763 rev_ = nullid
2766 if not message:
2764 if not message:
2767 message = _('Removed tag %s') % ', '.join(names)
2765 message = _('Removed tag %s') % ', '.join(names)
2768 elif not opts.get('force'):
2766 elif not opts.get('force'):
2769 for n in names:
2767 for n in names:
2770 if n in repo.tags():
2768 if n in repo.tags():
2771 raise util.Abort(_('tag \'%s\' already exists '
2769 raise util.Abort(_('tag \'%s\' already exists '
2772 '(use -f to force)') % n)
2770 '(use -f to force)') % n)
2773 if not rev_ and repo.dirstate.parents()[1] != nullid:
2771 if not rev_ and repo.dirstate.parents()[1] != nullid:
2774 raise util.Abort(_('uncommitted merge - please provide a '
2772 raise util.Abort(_('uncommitted merge - please provide a '
2775 'specific revision'))
2773 'specific revision'))
2776 r = repo[rev_].node()
2774 r = repo[rev_].node()
2777
2775
2778 if not message:
2776 if not message:
2779 message = (_('Added tag %s for changeset %s') %
2777 message = (_('Added tag %s for changeset %s') %
2780 (', '.join(names), short(r)))
2778 (', '.join(names), short(r)))
2781
2779
2782 date = opts.get('date')
2780 date = opts.get('date')
2783 if date:
2781 if date:
2784 date = util.parsedate(date)
2782 date = util.parsedate(date)
2785
2783
2786 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2784 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2787
2785
2788 def tags(ui, repo):
2786 def tags(ui, repo):
2789 """list repository tags
2787 """list repository tags
2790
2788
2791 List the repository tags.
2789 List the repository tags.
2792
2790
2793 This lists both regular and local tags. When the -v/--verbose switch
2791 This lists both regular and local tags. When the -v/--verbose switch
2794 is used, a third column "local" is printed for local tags.
2792 is used, a third column "local" is printed for local tags.
2795 """
2793 """
2796
2794
2797 l = repo.tagslist()
2795 l = repo.tagslist()
2798 l.reverse()
2796 l.reverse()
2799 hexfunc = ui.debugflag and hex or short
2797 hexfunc = ui.debugflag and hex or short
2800 tagtype = ""
2798 tagtype = ""
2801
2799
2802 for t, n in l:
2800 for t, n in l:
2803 if ui.quiet:
2801 if ui.quiet:
2804 ui.write("%s\n" % t)
2802 ui.write("%s\n" % t)
2805 continue
2803 continue
2806
2804
2807 try:
2805 try:
2808 hn = hexfunc(n)
2806 hn = hexfunc(n)
2809 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2807 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2810 except revlog.LookupError:
2808 except revlog.LookupError:
2811 r = " ?:%s" % hn
2809 r = " ?:%s" % hn
2812 else:
2810 else:
2813 spaces = " " * (30 - util.locallen(t))
2811 spaces = " " * (30 - util.locallen(t))
2814 if ui.verbose:
2812 if ui.verbose:
2815 if repo.tagtype(t) == 'local':
2813 if repo.tagtype(t) == 'local':
2816 tagtype = " local"
2814 tagtype = " local"
2817 else:
2815 else:
2818 tagtype = ""
2816 tagtype = ""
2819 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2817 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2820
2818
2821 def tip(ui, repo, **opts):
2819 def tip(ui, repo, **opts):
2822 """show the tip revision
2820 """show the tip revision
2823
2821
2824 The tip revision (usually just called the tip) is the most
2822 The tip revision (usually just called the tip) is the most
2825 recently added changeset in the repository, the most recently
2823 recently added changeset in the repository, the most recently
2826 changed head.
2824 changed head.
2827
2825
2828 If you have just made a commit, that commit will be the tip. If
2826 If you have just made a commit, that commit will be the tip. If
2829 you have just pulled changes from another repository, the tip of
2827 you have just pulled changes from another repository, the tip of
2830 that repository becomes the current tip. The "tip" tag is special
2828 that repository becomes the current tip. The "tip" tag is special
2831 and cannot be renamed or assigned to a different changeset.
2829 and cannot be renamed or assigned to a different changeset.
2832 """
2830 """
2833 cmdutil.show_changeset(ui, repo, opts).show(len(repo) - 1)
2831 cmdutil.show_changeset(ui, repo, opts).show(len(repo) - 1)
2834
2832
2835 def unbundle(ui, repo, fname1, *fnames, **opts):
2833 def unbundle(ui, repo, fname1, *fnames, **opts):
2836 """apply one or more changegroup files
2834 """apply one or more changegroup files
2837
2835
2838 Apply one or more compressed changegroup files generated by the
2836 Apply one or more compressed changegroup files generated by the
2839 bundle command.
2837 bundle command.
2840 """
2838 """
2841 fnames = (fname1,) + fnames
2839 fnames = (fname1,) + fnames
2842
2840
2843 lock = None
2841 lock = None
2844 try:
2842 try:
2845 lock = repo.lock()
2843 lock = repo.lock()
2846 for fname in fnames:
2844 for fname in fnames:
2847 if os.path.exists(fname):
2845 f = url.open(ui, fname)
2848 f = open(fname, "rb")
2849 else:
2850 f = urllib.urlopen(fname)
2851 gen = changegroup.readbundle(f, fname)
2846 gen = changegroup.readbundle(f, fname)
2852 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2847 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2853 finally:
2848 finally:
2854 del lock
2849 del lock
2855
2850
2856 return postincoming(ui, repo, modheads, opts.get('update'), None)
2851 return postincoming(ui, repo, modheads, opts.get('update'), None)
2857
2852
2858 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2853 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2859 """update working directory
2854 """update working directory
2860
2855
2861 Update the repository's working directory to the specified revision,
2856 Update the repository's working directory to the specified revision,
2862 or the tip of the current branch if none is specified. Use null as
2857 or the tip of the current branch if none is specified. Use null as
2863 the revision to remove the working copy (like 'hg clone -U').
2858 the revision to remove the working copy (like 'hg clone -U').
2864
2859
2865 If the requested revision is a descendant of the working
2860 If the requested revision is a descendant of the working
2866 directory, any outstanding changes in the working directory will
2861 directory, any outstanding changes in the working directory will
2867 be merged into the result. If it is not directly descended but is
2862 be merged into the result. If it is not directly descended but is
2868 on the same named branch, update aborts with a suggestion to use
2863 on the same named branch, update aborts with a suggestion to use
2869 merge or update -C instead.
2864 merge or update -C instead.
2870
2865
2871 If the requested revision is on a different named branch and the
2866 If the requested revision is on a different named branch and the
2872 working directory is clean, update quietly switches branches.
2867 working directory is clean, update quietly switches branches.
2873
2868
2874 If you want to update just one file to an older revision, use revert.
2869 If you want to update just one file to an older revision, use revert.
2875
2870
2876 See 'hg help dates' for a list of formats valid for --date.
2871 See 'hg help dates' for a list of formats valid for --date.
2877 """
2872 """
2878 if rev and node:
2873 if rev and node:
2879 raise util.Abort(_("please specify just one revision"))
2874 raise util.Abort(_("please specify just one revision"))
2880
2875
2881 if not rev:
2876 if not rev:
2882 rev = node
2877 rev = node
2883
2878
2884 if date:
2879 if date:
2885 if rev:
2880 if rev:
2886 raise util.Abort(_("you can't specify a revision and a date"))
2881 raise util.Abort(_("you can't specify a revision and a date"))
2887 rev = cmdutil.finddate(ui, repo, date)
2882 rev = cmdutil.finddate(ui, repo, date)
2888
2883
2889 if clean:
2884 if clean:
2890 return hg.clean(repo, rev)
2885 return hg.clean(repo, rev)
2891 else:
2886 else:
2892 return hg.update(repo, rev)
2887 return hg.update(repo, rev)
2893
2888
2894 def verify(ui, repo):
2889 def verify(ui, repo):
2895 """verify the integrity of the repository
2890 """verify the integrity of the repository
2896
2891
2897 Verify the integrity of the current repository.
2892 Verify the integrity of the current repository.
2898
2893
2899 This will perform an extensive check of the repository's
2894 This will perform an extensive check of the repository's
2900 integrity, validating the hashes and checksums of each entry in
2895 integrity, validating the hashes and checksums of each entry in
2901 the changelog, manifest, and tracked files, as well as the
2896 the changelog, manifest, and tracked files, as well as the
2902 integrity of their crosslinks and indices.
2897 integrity of their crosslinks and indices.
2903 """
2898 """
2904 return hg.verify(repo)
2899 return hg.verify(repo)
2905
2900
2906 def version_(ui):
2901 def version_(ui):
2907 """output version and copyright information"""
2902 """output version and copyright information"""
2908 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2903 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2909 % version.get_version())
2904 % version.get_version())
2910 ui.status(_(
2905 ui.status(_(
2911 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2906 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2912 "This is free software; see the source for copying conditions. "
2907 "This is free software; see the source for copying conditions. "
2913 "There is NO\nwarranty; "
2908 "There is NO\nwarranty; "
2914 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2909 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2915 ))
2910 ))
2916
2911
2917 # Command options and aliases are listed here, alphabetically
2912 # Command options and aliases are listed here, alphabetically
2918
2913
2919 globalopts = [
2914 globalopts = [
2920 ('R', 'repository', '',
2915 ('R', 'repository', '',
2921 _('repository root directory or symbolic path name')),
2916 _('repository root directory or symbolic path name')),
2922 ('', 'cwd', '', _('change working directory')),
2917 ('', 'cwd', '', _('change working directory')),
2923 ('y', 'noninteractive', None,
2918 ('y', 'noninteractive', None,
2924 _('do not prompt, assume \'yes\' for any required answers')),
2919 _('do not prompt, assume \'yes\' for any required answers')),
2925 ('q', 'quiet', None, _('suppress output')),
2920 ('q', 'quiet', None, _('suppress output')),
2926 ('v', 'verbose', None, _('enable additional output')),
2921 ('v', 'verbose', None, _('enable additional output')),
2927 ('', 'config', [], _('set/override config option')),
2922 ('', 'config', [], _('set/override config option')),
2928 ('', 'debug', None, _('enable debugging output')),
2923 ('', 'debug', None, _('enable debugging output')),
2929 ('', 'debugger', None, _('start debugger')),
2924 ('', 'debugger', None, _('start debugger')),
2930 ('', 'encoding', util._encoding, _('set the charset encoding')),
2925 ('', 'encoding', util._encoding, _('set the charset encoding')),
2931 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2926 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2932 ('', 'lsprof', None, _('print improved command execution profile')),
2927 ('', 'lsprof', None, _('print improved command execution profile')),
2933 ('', 'traceback', None, _('print traceback on exception')),
2928 ('', 'traceback', None, _('print traceback on exception')),
2934 ('', 'time', None, _('time how long the command takes')),
2929 ('', 'time', None, _('time how long the command takes')),
2935 ('', 'profile', None, _('print command execution profile')),
2930 ('', 'profile', None, _('print command execution profile')),
2936 ('', 'version', None, _('output version information and exit')),
2931 ('', 'version', None, _('output version information and exit')),
2937 ('h', 'help', None, _('display help and exit')),
2932 ('h', 'help', None, _('display help and exit')),
2938 ]
2933 ]
2939
2934
2940 dryrunopts = [('n', 'dry-run', None,
2935 dryrunopts = [('n', 'dry-run', None,
2941 _('do not perform actions, just print output'))]
2936 _('do not perform actions, just print output'))]
2942
2937
2943 remoteopts = [
2938 remoteopts = [
2944 ('e', 'ssh', '', _('specify ssh command to use')),
2939 ('e', 'ssh', '', _('specify ssh command to use')),
2945 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2940 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2946 ]
2941 ]
2947
2942
2948 walkopts = [
2943 walkopts = [
2949 ('I', 'include', [], _('include names matching the given patterns')),
2944 ('I', 'include', [], _('include names matching the given patterns')),
2950 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2945 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2951 ]
2946 ]
2952
2947
2953 commitopts = [
2948 commitopts = [
2954 ('m', 'message', '', _('use <text> as commit message')),
2949 ('m', 'message', '', _('use <text> as commit message')),
2955 ('l', 'logfile', '', _('read commit message from <file>')),
2950 ('l', 'logfile', '', _('read commit message from <file>')),
2956 ]
2951 ]
2957
2952
2958 commitopts2 = [
2953 commitopts2 = [
2959 ('d', 'date', '', _('record datecode as commit date')),
2954 ('d', 'date', '', _('record datecode as commit date')),
2960 ('u', 'user', '', _('record user as committer')),
2955 ('u', 'user', '', _('record user as committer')),
2961 ]
2956 ]
2962
2957
2963 templateopts = [
2958 templateopts = [
2964 ('', 'style', '', _('display using template map file')),
2959 ('', 'style', '', _('display using template map file')),
2965 ('', 'template', '', _('display with template')),
2960 ('', 'template', '', _('display with template')),
2966 ]
2961 ]
2967
2962
2968 logopts = [
2963 logopts = [
2969 ('p', 'patch', None, _('show patch')),
2964 ('p', 'patch', None, _('show patch')),
2970 ('l', 'limit', '', _('limit number of changes displayed')),
2965 ('l', 'limit', '', _('limit number of changes displayed')),
2971 ('M', 'no-merges', None, _('do not show merges')),
2966 ('M', 'no-merges', None, _('do not show merges')),
2972 ] + templateopts
2967 ] + templateopts
2973
2968
2974 diffopts = [
2969 diffopts = [
2975 ('a', 'text', None, _('treat all files as text')),
2970 ('a', 'text', None, _('treat all files as text')),
2976 ('g', 'git', None, _('use git extended diff format')),
2971 ('g', 'git', None, _('use git extended diff format')),
2977 ('', 'nodates', None, _("don't include dates in diff headers"))
2972 ('', 'nodates', None, _("don't include dates in diff headers"))
2978 ]
2973 ]
2979
2974
2980 diffopts2 = [
2975 diffopts2 = [
2981 ('p', 'show-function', None, _('show which function each change is in')),
2976 ('p', 'show-function', None, _('show which function each change is in')),
2982 ('w', 'ignore-all-space', None,
2977 ('w', 'ignore-all-space', None,
2983 _('ignore white space when comparing lines')),
2978 _('ignore white space when comparing lines')),
2984 ('b', 'ignore-space-change', None,
2979 ('b', 'ignore-space-change', None,
2985 _('ignore changes in the amount of white space')),
2980 _('ignore changes in the amount of white space')),
2986 ('B', 'ignore-blank-lines', None,
2981 ('B', 'ignore-blank-lines', None,
2987 _('ignore changes whose lines are all blank')),
2982 _('ignore changes whose lines are all blank')),
2988 ('U', 'unified', '', _('number of lines of context to show'))
2983 ('U', 'unified', '', _('number of lines of context to show'))
2989 ]
2984 ]
2990
2985
2991 table = {
2986 table = {
2992 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2987 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2993 "addremove":
2988 "addremove":
2994 (addremove,
2989 (addremove,
2995 [('s', 'similarity', '',
2990 [('s', 'similarity', '',
2996 _('guess renamed files by similarity (0<=s<=100)')),
2991 _('guess renamed files by similarity (0<=s<=100)')),
2997 ] + walkopts + dryrunopts,
2992 ] + walkopts + dryrunopts,
2998 _('hg addremove [OPTION]... [FILE]...')),
2993 _('hg addremove [OPTION]... [FILE]...')),
2999 "^annotate|blame":
2994 "^annotate|blame":
3000 (annotate,
2995 (annotate,
3001 [('r', 'rev', '', _('annotate the specified revision')),
2996 [('r', 'rev', '', _('annotate the specified revision')),
3002 ('f', 'follow', None, _('follow file copies and renames')),
2997 ('f', 'follow', None, _('follow file copies and renames')),
3003 ('a', 'text', None, _('treat all files as text')),
2998 ('a', 'text', None, _('treat all files as text')),
3004 ('u', 'user', None, _('list the author (long with -v)')),
2999 ('u', 'user', None, _('list the author (long with -v)')),
3005 ('d', 'date', None, _('list the date (short with -q)')),
3000 ('d', 'date', None, _('list the date (short with -q)')),
3006 ('n', 'number', None, _('list the revision number (default)')),
3001 ('n', 'number', None, _('list the revision number (default)')),
3007 ('c', 'changeset', None, _('list the changeset')),
3002 ('c', 'changeset', None, _('list the changeset')),
3008 ('l', 'line-number', None,
3003 ('l', 'line-number', None,
3009 _('show line number at the first appearance'))
3004 _('show line number at the first appearance'))
3010 ] + walkopts,
3005 ] + walkopts,
3011 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3006 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3012 "archive":
3007 "archive":
3013 (archive,
3008 (archive,
3014 [('', 'no-decode', None, _('do not pass files through decoders')),
3009 [('', 'no-decode', None, _('do not pass files through decoders')),
3015 ('p', 'prefix', '', _('directory prefix for files in archive')),
3010 ('p', 'prefix', '', _('directory prefix for files in archive')),
3016 ('r', 'rev', '', _('revision to distribute')),
3011 ('r', 'rev', '', _('revision to distribute')),
3017 ('t', 'type', '', _('type of distribution to create')),
3012 ('t', 'type', '', _('type of distribution to create')),
3018 ] + walkopts,
3013 ] + walkopts,
3019 _('hg archive [OPTION]... DEST')),
3014 _('hg archive [OPTION]... DEST')),
3020 "backout":
3015 "backout":
3021 (backout,
3016 (backout,
3022 [('', 'merge', None,
3017 [('', 'merge', None,
3023 _('merge with old dirstate parent after backout')),
3018 _('merge with old dirstate parent after backout')),
3024 ('', 'parent', '', _('parent to choose when backing out merge')),
3019 ('', 'parent', '', _('parent to choose when backing out merge')),
3025 ('r', 'rev', '', _('revision to backout')),
3020 ('r', 'rev', '', _('revision to backout')),
3026 ] + walkopts + commitopts + commitopts2,
3021 ] + walkopts + commitopts + commitopts2,
3027 _('hg backout [OPTION]... [-r] REV')),
3022 _('hg backout [OPTION]... [-r] REV')),
3028 "bisect":
3023 "bisect":
3029 (bisect,
3024 (bisect,
3030 [('r', 'reset', False, _('reset bisect state')),
3025 [('r', 'reset', False, _('reset bisect state')),
3031 ('g', 'good', False, _('mark changeset good')),
3026 ('g', 'good', False, _('mark changeset good')),
3032 ('b', 'bad', False, _('mark changeset bad')),
3027 ('b', 'bad', False, _('mark changeset bad')),
3033 ('s', 'skip', False, _('skip testing changeset')),
3028 ('s', 'skip', False, _('skip testing changeset')),
3034 ('c', 'command', '', _('Use command to check changeset state')),
3029 ('c', 'command', '', _('Use command to check changeset state')),
3035 ('U', 'noupdate', False, _('do not update to target'))],
3030 ('U', 'noupdate', False, _('do not update to target'))],
3036 _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
3031 _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
3037 "branch":
3032 "branch":
3038 (branch,
3033 (branch,
3039 [('f', 'force', None,
3034 [('f', 'force', None,
3040 _('set branch name even if it shadows an existing branch')),
3035 _('set branch name even if it shadows an existing branch')),
3041 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3036 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3042 _('hg branch [-fC] [NAME]')),
3037 _('hg branch [-fC] [NAME]')),
3043 "branches":
3038 "branches":
3044 (branches,
3039 (branches,
3045 [('a', 'active', False,
3040 [('a', 'active', False,
3046 _('show only branches that have unmerged heads'))],
3041 _('show only branches that have unmerged heads'))],
3047 _('hg branches [-a]')),
3042 _('hg branches [-a]')),
3048 "bundle":
3043 "bundle":
3049 (bundle,
3044 (bundle,
3050 [('f', 'force', None,
3045 [('f', 'force', None,
3051 _('run even when remote repository is unrelated')),
3046 _('run even when remote repository is unrelated')),
3052 ('r', 'rev', [],
3047 ('r', 'rev', [],
3053 _('a changeset up to which you would like to bundle')),
3048 _('a changeset up to which you would like to bundle')),
3054 ('', 'base', [],
3049 ('', 'base', [],
3055 _('a base changeset to specify instead of a destination')),
3050 _('a base changeset to specify instead of a destination')),
3056 ('a', 'all', None, _('bundle all changesets in the repository')),
3051 ('a', 'all', None, _('bundle all changesets in the repository')),
3057 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3052 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3058 ] + remoteopts,
3053 ] + remoteopts,
3059 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3054 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3060 "cat":
3055 "cat":
3061 (cat,
3056 (cat,
3062 [('o', 'output', '', _('print output to file with formatted name')),
3057 [('o', 'output', '', _('print output to file with formatted name')),
3063 ('r', 'rev', '', _('print the given revision')),
3058 ('r', 'rev', '', _('print the given revision')),
3064 ('', 'decode', None, _('apply any matching decode filter')),
3059 ('', 'decode', None, _('apply any matching decode filter')),
3065 ] + walkopts,
3060 ] + walkopts,
3066 _('hg cat [OPTION]... FILE...')),
3061 _('hg cat [OPTION]... FILE...')),
3067 "^clone":
3062 "^clone":
3068 (clone,
3063 (clone,
3069 [('U', 'noupdate', None,
3064 [('U', 'noupdate', None,
3070 _('the clone will only contain a repository (no working copy)')),
3065 _('the clone will only contain a repository (no working copy)')),
3071 ('r', 'rev', [],
3066 ('r', 'rev', [],
3072 _('a changeset you would like to have after cloning')),
3067 _('a changeset you would like to have after cloning')),
3073 ('', 'pull', None, _('use pull protocol to copy metadata')),
3068 ('', 'pull', None, _('use pull protocol to copy metadata')),
3074 ('', 'uncompressed', None,
3069 ('', 'uncompressed', None,
3075 _('use uncompressed transfer (fast over LAN)')),
3070 _('use uncompressed transfer (fast over LAN)')),
3076 ] + remoteopts,
3071 ] + remoteopts,
3077 _('hg clone [OPTION]... SOURCE [DEST]')),
3072 _('hg clone [OPTION]... SOURCE [DEST]')),
3078 "^commit|ci":
3073 "^commit|ci":
3079 (commit,
3074 (commit,
3080 [('A', 'addremove', None,
3075 [('A', 'addremove', None,
3081 _('mark new/missing files as added/removed before committing')),
3076 _('mark new/missing files as added/removed before committing')),
3082 ] + walkopts + commitopts + commitopts2,
3077 ] + walkopts + commitopts + commitopts2,
3083 _('hg commit [OPTION]... [FILE]...')),
3078 _('hg commit [OPTION]... [FILE]...')),
3084 "copy|cp":
3079 "copy|cp":
3085 (copy,
3080 (copy,
3086 [('A', 'after', None, _('record a copy that has already occurred')),
3081 [('A', 'after', None, _('record a copy that has already occurred')),
3087 ('f', 'force', None,
3082 ('f', 'force', None,
3088 _('forcibly copy over an existing managed file')),
3083 _('forcibly copy over an existing managed file')),
3089 ] + walkopts + dryrunopts,
3084 ] + walkopts + dryrunopts,
3090 _('hg copy [OPTION]... [SOURCE]... DEST')),
3085 _('hg copy [OPTION]... [SOURCE]... DEST')),
3091 "debugancestor": (debugancestor, [],
3086 "debugancestor": (debugancestor, [],
3092 _('hg debugancestor [INDEX] REV1 REV2')),
3087 _('hg debugancestor [INDEX] REV1 REV2')),
3093 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3088 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3094 "debugcomplete":
3089 "debugcomplete":
3095 (debugcomplete,
3090 (debugcomplete,
3096 [('o', 'options', None, _('show the command options'))],
3091 [('o', 'options', None, _('show the command options'))],
3097 _('hg debugcomplete [-o] CMD')),
3092 _('hg debugcomplete [-o] CMD')),
3098 "debugdate":
3093 "debugdate":
3099 (debugdate,
3094 (debugdate,
3100 [('e', 'extended', None, _('try extended date formats'))],
3095 [('e', 'extended', None, _('try extended date formats'))],
3101 _('hg debugdate [-e] DATE [RANGE]')),
3096 _('hg debugdate [-e] DATE [RANGE]')),
3102 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3097 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3103 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3098 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3104 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3099 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3105 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3100 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3106 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3101 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3107 "debugrawcommit|rawcommit":
3102 "debugrawcommit|rawcommit":
3108 (rawcommit,
3103 (rawcommit,
3109 [('p', 'parent', [], _('parent')),
3104 [('p', 'parent', [], _('parent')),
3110 ('F', 'files', '', _('file list'))
3105 ('F', 'files', '', _('file list'))
3111 ] + commitopts + commitopts2,
3106 ] + commitopts + commitopts2,
3112 _('hg debugrawcommit [OPTION]... [FILE]...')),
3107 _('hg debugrawcommit [OPTION]... [FILE]...')),
3113 "debugrebuildstate":
3108 "debugrebuildstate":
3114 (debugrebuildstate,
3109 (debugrebuildstate,
3115 [('r', 'rev', '', _('revision to rebuild to'))],
3110 [('r', 'rev', '', _('revision to rebuild to'))],
3116 _('hg debugrebuildstate [-r REV] [REV]')),
3111 _('hg debugrebuildstate [-r REV] [REV]')),
3117 "debugrename":
3112 "debugrename":
3118 (debugrename,
3113 (debugrename,
3119 [('r', 'rev', '', _('revision to debug'))],
3114 [('r', 'rev', '', _('revision to debug'))],
3120 _('hg debugrename [-r REV] FILE')),
3115 _('hg debugrename [-r REV] FILE')),
3121 "debugsetparents":
3116 "debugsetparents":
3122 (debugsetparents,
3117 (debugsetparents,
3123 [],
3118 [],
3124 _('hg debugsetparents REV1 [REV2]')),
3119 _('hg debugsetparents REV1 [REV2]')),
3125 "debugstate":
3120 "debugstate":
3126 (debugstate,
3121 (debugstate,
3127 [('', 'nodates', None, _('do not display the saved mtime'))],
3122 [('', 'nodates', None, _('do not display the saved mtime'))],
3128 _('hg debugstate [OPTS]')),
3123 _('hg debugstate [OPTS]')),
3129 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3124 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3130 "^diff":
3125 "^diff":
3131 (diff,
3126 (diff,
3132 [('r', 'rev', [], _('revision'))
3127 [('r', 'rev', [], _('revision'))
3133 ] + diffopts + diffopts2 + walkopts,
3128 ] + diffopts + diffopts2 + walkopts,
3134 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3129 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3135 "^export":
3130 "^export":
3136 (export,
3131 (export,
3137 [('o', 'output', '', _('print output to file with formatted name')),
3132 [('o', 'output', '', _('print output to file with formatted name')),
3138 ('', 'switch-parent', None, _('diff against the second parent'))
3133 ('', 'switch-parent', None, _('diff against the second parent'))
3139 ] + diffopts,
3134 ] + diffopts,
3140 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3135 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3141 "grep":
3136 "grep":
3142 (grep,
3137 (grep,
3143 [('0', 'print0', None, _('end fields with NUL')),
3138 [('0', 'print0', None, _('end fields with NUL')),
3144 ('', 'all', None, _('print all revisions that match')),
3139 ('', 'all', None, _('print all revisions that match')),
3145 ('f', 'follow', None,
3140 ('f', 'follow', None,
3146 _('follow changeset history, or file history across copies and renames')),
3141 _('follow changeset history, or file history across copies and renames')),
3147 ('i', 'ignore-case', None, _('ignore case when matching')),
3142 ('i', 'ignore-case', None, _('ignore case when matching')),
3148 ('l', 'files-with-matches', None,
3143 ('l', 'files-with-matches', None,
3149 _('print only filenames and revs that match')),
3144 _('print only filenames and revs that match')),
3150 ('n', 'line-number', None, _('print matching line numbers')),
3145 ('n', 'line-number', None, _('print matching line numbers')),
3151 ('r', 'rev', [], _('search in given revision range')),
3146 ('r', 'rev', [], _('search in given revision range')),
3152 ('u', 'user', None, _('list the author (long with -v)')),
3147 ('u', 'user', None, _('list the author (long with -v)')),
3153 ('d', 'date', None, _('list the date (short with -q)')),
3148 ('d', 'date', None, _('list the date (short with -q)')),
3154 ] + walkopts,
3149 ] + walkopts,
3155 _('hg grep [OPTION]... PATTERN [FILE]...')),
3150 _('hg grep [OPTION]... PATTERN [FILE]...')),
3156 "heads":
3151 "heads":
3157 (heads,
3152 (heads,
3158 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3153 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3159 ] + templateopts,
3154 ] + templateopts,
3160 _('hg heads [-r REV] [REV]...')),
3155 _('hg heads [-r REV] [REV]...')),
3161 "help": (help_, [], _('hg help [TOPIC]')),
3156 "help": (help_, [], _('hg help [TOPIC]')),
3162 "identify|id":
3157 "identify|id":
3163 (identify,
3158 (identify,
3164 [('r', 'rev', '', _('identify the specified rev')),
3159 [('r', 'rev', '', _('identify the specified rev')),
3165 ('n', 'num', None, _('show local revision number')),
3160 ('n', 'num', None, _('show local revision number')),
3166 ('i', 'id', None, _('show global revision id')),
3161 ('i', 'id', None, _('show global revision id')),
3167 ('b', 'branch', None, _('show branch')),
3162 ('b', 'branch', None, _('show branch')),
3168 ('t', 'tags', None, _('show tags'))],
3163 ('t', 'tags', None, _('show tags'))],
3169 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3164 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3170 "import|patch":
3165 "import|patch":
3171 (import_,
3166 (import_,
3172 [('p', 'strip', 1,
3167 [('p', 'strip', 1,
3173 _('directory strip option for patch. This has the same\n'
3168 _('directory strip option for patch. This has the same\n'
3174 'meaning as the corresponding patch option')),
3169 'meaning as the corresponding patch option')),
3175 ('b', 'base', '', _('base path')),
3170 ('b', 'base', '', _('base path')),
3176 ('f', 'force', None,
3171 ('f', 'force', None,
3177 _('skip check for outstanding uncommitted changes')),
3172 _('skip check for outstanding uncommitted changes')),
3178 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3173 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3179 ('', 'exact', None,
3174 ('', 'exact', None,
3180 _('apply patch to the nodes from which it was generated')),
3175 _('apply patch to the nodes from which it was generated')),
3181 ('', 'import-branch', None,
3176 ('', 'import-branch', None,
3182 _('Use any branch information in patch (implied by --exact)'))] +
3177 _('Use any branch information in patch (implied by --exact)'))] +
3183 commitopts + commitopts2,
3178 commitopts + commitopts2,
3184 _('hg import [OPTION]... PATCH...')),
3179 _('hg import [OPTION]... PATCH...')),
3185 "incoming|in":
3180 "incoming|in":
3186 (incoming,
3181 (incoming,
3187 [('f', 'force', None,
3182 [('f', 'force', None,
3188 _('run even when remote repository is unrelated')),
3183 _('run even when remote repository is unrelated')),
3189 ('n', 'newest-first', None, _('show newest record first')),
3184 ('n', 'newest-first', None, _('show newest record first')),
3190 ('', 'bundle', '', _('file to store the bundles into')),
3185 ('', 'bundle', '', _('file to store the bundles into')),
3191 ('r', 'rev', [],
3186 ('r', 'rev', [],
3192 _('a specific revision up to which you would like to pull')),
3187 _('a specific revision up to which you would like to pull')),
3193 ] + logopts + remoteopts,
3188 ] + logopts + remoteopts,
3194 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3189 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3195 ' [--bundle FILENAME] [SOURCE]')),
3190 ' [--bundle FILENAME] [SOURCE]')),
3196 "^init":
3191 "^init":
3197 (init,
3192 (init,
3198 remoteopts,
3193 remoteopts,
3199 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3194 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3200 "locate":
3195 "locate":
3201 (locate,
3196 (locate,
3202 [('r', 'rev', '', _('search the repository as it stood at rev')),
3197 [('r', 'rev', '', _('search the repository as it stood at rev')),
3203 ('0', 'print0', None,
3198 ('0', 'print0', None,
3204 _('end filenames with NUL, for use with xargs')),
3199 _('end filenames with NUL, for use with xargs')),
3205 ('f', 'fullpath', None,
3200 ('f', 'fullpath', None,
3206 _('print complete paths from the filesystem root')),
3201 _('print complete paths from the filesystem root')),
3207 ] + walkopts,
3202 ] + walkopts,
3208 _('hg locate [OPTION]... [PATTERN]...')),
3203 _('hg locate [OPTION]... [PATTERN]...')),
3209 "^log|history":
3204 "^log|history":
3210 (log,
3205 (log,
3211 [('f', 'follow', None,
3206 [('f', 'follow', None,
3212 _('follow changeset history, or file history across copies and renames')),
3207 _('follow changeset history, or file history across copies and renames')),
3213 ('', 'follow-first', None,
3208 ('', 'follow-first', None,
3214 _('only follow the first parent of merge changesets')),
3209 _('only follow the first parent of merge changesets')),
3215 ('d', 'date', '', _('show revs matching date spec')),
3210 ('d', 'date', '', _('show revs matching date spec')),
3216 ('C', 'copies', None, _('show copied files')),
3211 ('C', 'copies', None, _('show copied files')),
3217 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3212 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3218 ('r', 'rev', [], _('show the specified revision or range')),
3213 ('r', 'rev', [], _('show the specified revision or range')),
3219 ('', 'removed', None, _('include revs where files were removed')),
3214 ('', 'removed', None, _('include revs where files were removed')),
3220 ('m', 'only-merges', None, _('show only merges')),
3215 ('m', 'only-merges', None, _('show only merges')),
3221 ('u', 'user', [], _('revs committed by user')),
3216 ('u', 'user', [], _('revs committed by user')),
3222 ('b', 'only-branch', [],
3217 ('b', 'only-branch', [],
3223 _('show only changesets within the given named branch')),
3218 _('show only changesets within the given named branch')),
3224 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3219 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3225 ] + logopts + walkopts,
3220 ] + logopts + walkopts,
3226 _('hg log [OPTION]... [FILE]')),
3221 _('hg log [OPTION]... [FILE]')),
3227 "manifest":
3222 "manifest":
3228 (manifest,
3223 (manifest,
3229 [('r', 'rev', '', _('revision to display'))],
3224 [('r', 'rev', '', _('revision to display'))],
3230 _('hg manifest [-r REV]')),
3225 _('hg manifest [-r REV]')),
3231 "^merge":
3226 "^merge":
3232 (merge,
3227 (merge,
3233 [('f', 'force', None, _('force a merge with outstanding changes')),
3228 [('f', 'force', None, _('force a merge with outstanding changes')),
3234 ('r', 'rev', '', _('revision to merge')),
3229 ('r', 'rev', '', _('revision to merge')),
3235 ],
3230 ],
3236 _('hg merge [-f] [[-r] REV]')),
3231 _('hg merge [-f] [[-r] REV]')),
3237 "outgoing|out":
3232 "outgoing|out":
3238 (outgoing,
3233 (outgoing,
3239 [('f', 'force', None,
3234 [('f', 'force', None,
3240 _('run even when remote repository is unrelated')),
3235 _('run even when remote repository is unrelated')),
3241 ('r', 'rev', [],
3236 ('r', 'rev', [],
3242 _('a specific revision up to which you would like to push')),
3237 _('a specific revision up to which you would like to push')),
3243 ('n', 'newest-first', None, _('show newest record first')),
3238 ('n', 'newest-first', None, _('show newest record first')),
3244 ] + logopts + remoteopts,
3239 ] + logopts + remoteopts,
3245 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3240 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3246 "^parents":
3241 "^parents":
3247 (parents,
3242 (parents,
3248 [('r', 'rev', '', _('show parents from the specified rev')),
3243 [('r', 'rev', '', _('show parents from the specified rev')),
3249 ] + templateopts,
3244 ] + templateopts,
3250 _('hg parents [-r REV] [FILE]')),
3245 _('hg parents [-r REV] [FILE]')),
3251 "paths": (paths, [], _('hg paths [NAME]')),
3246 "paths": (paths, [], _('hg paths [NAME]')),
3252 "^pull":
3247 "^pull":
3253 (pull,
3248 (pull,
3254 [('u', 'update', None,
3249 [('u', 'update', None,
3255 _('update to new tip if changesets were pulled')),
3250 _('update to new tip if changesets were pulled')),
3256 ('f', 'force', None,
3251 ('f', 'force', None,
3257 _('run even when remote repository is unrelated')),
3252 _('run even when remote repository is unrelated')),
3258 ('r', 'rev', [],
3253 ('r', 'rev', [],
3259 _('a specific revision up to which you would like to pull')),
3254 _('a specific revision up to which you would like to pull')),
3260 ] + remoteopts,
3255 ] + remoteopts,
3261 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3256 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3262 "^push":
3257 "^push":
3263 (push,
3258 (push,
3264 [('f', 'force', None, _('force push')),
3259 [('f', 'force', None, _('force push')),
3265 ('r', 'rev', [],
3260 ('r', 'rev', [],
3266 _('a specific revision up to which you would like to push')),
3261 _('a specific revision up to which you would like to push')),
3267 ] + remoteopts,
3262 ] + remoteopts,
3268 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3263 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3269 "recover": (recover, [], _('hg recover')),
3264 "recover": (recover, [], _('hg recover')),
3270 "^remove|rm":
3265 "^remove|rm":
3271 (remove,
3266 (remove,
3272 [('A', 'after', None, _('record delete for missing files')),
3267 [('A', 'after', None, _('record delete for missing files')),
3273 ('f', 'force', None,
3268 ('f', 'force', None,
3274 _('remove (and delete) file even if added or modified')),
3269 _('remove (and delete) file even if added or modified')),
3275 ] + walkopts,
3270 ] + walkopts,
3276 _('hg remove [OPTION]... FILE...')),
3271 _('hg remove [OPTION]... FILE...')),
3277 "rename|mv":
3272 "rename|mv":
3278 (rename,
3273 (rename,
3279 [('A', 'after', None, _('record a rename that has already occurred')),
3274 [('A', 'after', None, _('record a rename that has already occurred')),
3280 ('f', 'force', None,
3275 ('f', 'force', None,
3281 _('forcibly copy over an existing managed file')),
3276 _('forcibly copy over an existing managed file')),
3282 ] + walkopts + dryrunopts,
3277 ] + walkopts + dryrunopts,
3283 _('hg rename [OPTION]... SOURCE... DEST')),
3278 _('hg rename [OPTION]... SOURCE... DEST')),
3284 "resolve":
3279 "resolve":
3285 (resolve,
3280 (resolve,
3286 [('l', 'list', None, _('list state of files needing merge')),
3281 [('l', 'list', None, _('list state of files needing merge')),
3287 ('m', 'mark', None, _('mark files as resolved')),
3282 ('m', 'mark', None, _('mark files as resolved')),
3288 ('u', 'unmark', None, _('unmark files as resolved'))],
3283 ('u', 'unmark', None, _('unmark files as resolved'))],
3289 _('hg resolve [OPTION] [FILES...]')),
3284 _('hg resolve [OPTION] [FILES...]')),
3290 "revert":
3285 "revert":
3291 (revert,
3286 (revert,
3292 [('a', 'all', None, _('revert all changes when no arguments given')),
3287 [('a', 'all', None, _('revert all changes when no arguments given')),
3293 ('d', 'date', '', _('tipmost revision matching date')),
3288 ('d', 'date', '', _('tipmost revision matching date')),
3294 ('r', 'rev', '', _('revision to revert to')),
3289 ('r', 'rev', '', _('revision to revert to')),
3295 ('', 'no-backup', None, _('do not save backup copies of files')),
3290 ('', 'no-backup', None, _('do not save backup copies of files')),
3296 ] + walkopts + dryrunopts,
3291 ] + walkopts + dryrunopts,
3297 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3292 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3298 "rollback": (rollback, [], _('hg rollback')),
3293 "rollback": (rollback, [], _('hg rollback')),
3299 "root": (root, [], _('hg root')),
3294 "root": (root, [], _('hg root')),
3300 "^serve":
3295 "^serve":
3301 (serve,
3296 (serve,
3302 [('A', 'accesslog', '', _('name of access log file to write to')),
3297 [('A', 'accesslog', '', _('name of access log file to write to')),
3303 ('d', 'daemon', None, _('run server in background')),
3298 ('d', 'daemon', None, _('run server in background')),
3304 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3299 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3305 ('E', 'errorlog', '', _('name of error log file to write to')),
3300 ('E', 'errorlog', '', _('name of error log file to write to')),
3306 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3301 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3307 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3302 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3308 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3303 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3309 ('n', 'name', '',
3304 ('n', 'name', '',
3310 _('name to show in web pages (default: working dir)')),
3305 _('name to show in web pages (default: working dir)')),
3311 ('', 'webdir-conf', '', _('name of the webdir config file'
3306 ('', 'webdir-conf', '', _('name of the webdir config file'
3312 ' (serve more than one repo)')),
3307 ' (serve more than one repo)')),
3313 ('', 'pid-file', '', _('name of file to write process ID to')),
3308 ('', 'pid-file', '', _('name of file to write process ID to')),
3314 ('', 'stdio', None, _('for remote clients')),
3309 ('', 'stdio', None, _('for remote clients')),
3315 ('t', 'templates', '', _('web templates to use')),
3310 ('t', 'templates', '', _('web templates to use')),
3316 ('', 'style', '', _('template style to use')),
3311 ('', 'style', '', _('template style to use')),
3317 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3312 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3318 ('', 'certificate', '', _('SSL certificate file'))],
3313 ('', 'certificate', '', _('SSL certificate file'))],
3319 _('hg serve [OPTION]...')),
3314 _('hg serve [OPTION]...')),
3320 "showconfig|debugconfig":
3315 "showconfig|debugconfig":
3321 (showconfig,
3316 (showconfig,
3322 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3317 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3323 _('hg showconfig [-u] [NAME]...')),
3318 _('hg showconfig [-u] [NAME]...')),
3324 "^status|st":
3319 "^status|st":
3325 (status,
3320 (status,
3326 [('A', 'all', None, _('show status of all files')),
3321 [('A', 'all', None, _('show status of all files')),
3327 ('m', 'modified', None, _('show only modified files')),
3322 ('m', 'modified', None, _('show only modified files')),
3328 ('a', 'added', None, _('show only added files')),
3323 ('a', 'added', None, _('show only added files')),
3329 ('r', 'removed', None, _('show only removed files')),
3324 ('r', 'removed', None, _('show only removed files')),
3330 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3325 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3331 ('c', 'clean', None, _('show only files without changes')),
3326 ('c', 'clean', None, _('show only files without changes')),
3332 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3327 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3333 ('i', 'ignored', None, _('show only ignored files')),
3328 ('i', 'ignored', None, _('show only ignored files')),
3334 ('n', 'no-status', None, _('hide status prefix')),
3329 ('n', 'no-status', None, _('hide status prefix')),
3335 ('C', 'copies', None, _('show source of copied files')),
3330 ('C', 'copies', None, _('show source of copied files')),
3336 ('0', 'print0', None,
3331 ('0', 'print0', None,
3337 _('end filenames with NUL, for use with xargs')),
3332 _('end filenames with NUL, for use with xargs')),
3338 ('', 'rev', [], _('show difference from revision')),
3333 ('', 'rev', [], _('show difference from revision')),
3339 ] + walkopts,
3334 ] + walkopts,
3340 _('hg status [OPTION]... [FILE]...')),
3335 _('hg status [OPTION]... [FILE]...')),
3341 "tag":
3336 "tag":
3342 (tag,
3337 (tag,
3343 [('f', 'force', None, _('replace existing tag')),
3338 [('f', 'force', None, _('replace existing tag')),
3344 ('l', 'local', None, _('make the tag local')),
3339 ('l', 'local', None, _('make the tag local')),
3345 ('r', 'rev', '', _('revision to tag')),
3340 ('r', 'rev', '', _('revision to tag')),
3346 ('', 'remove', None, _('remove a tag')),
3341 ('', 'remove', None, _('remove a tag')),
3347 # -l/--local is already there, commitopts cannot be used
3342 # -l/--local is already there, commitopts cannot be used
3348 ('m', 'message', '', _('use <text> as commit message')),
3343 ('m', 'message', '', _('use <text> as commit message')),
3349 ] + commitopts2,
3344 ] + commitopts2,
3350 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3345 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3351 "tags": (tags, [], _('hg tags')),
3346 "tags": (tags, [], _('hg tags')),
3352 "tip":
3347 "tip":
3353 (tip,
3348 (tip,
3354 [('p', 'patch', None, _('show patch')),
3349 [('p', 'patch', None, _('show patch')),
3355 ] + templateopts,
3350 ] + templateopts,
3356 _('hg tip [-p]')),
3351 _('hg tip [-p]')),
3357 "unbundle":
3352 "unbundle":
3358 (unbundle,
3353 (unbundle,
3359 [('u', 'update', None,
3354 [('u', 'update', None,
3360 _('update to new tip if changesets were unbundled'))],
3355 _('update to new tip if changesets were unbundled'))],
3361 _('hg unbundle [-u] FILE...')),
3356 _('hg unbundle [-u] FILE...')),
3362 "^update|up|checkout|co":
3357 "^update|up|checkout|co":
3363 (update,
3358 (update,
3364 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3359 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3365 ('d', 'date', '', _('tipmost revision matching date')),
3360 ('d', 'date', '', _('tipmost revision matching date')),
3366 ('r', 'rev', '', _('revision'))],
3361 ('r', 'rev', '', _('revision'))],
3367 _('hg update [-C] [-d DATE] [[-r] REV]')),
3362 _('hg update [-C] [-d DATE] [[-r] REV]')),
3368 "verify": (verify, [], _('hg verify')),
3363 "verify": (verify, [], _('hg verify')),
3369 "version": (version_, [], _('hg version')),
3364 "version": (version_, [], _('hg version')),
3370 }
3365 }
3371
3366
3372 norepo = ("clone init version help debugcomplete debugdata"
3367 norepo = ("clone init version help debugcomplete debugdata"
3373 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3368 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3374 optionalrepo = ("identify paths serve showconfig debugancestor")
3369 optionalrepo = ("identify paths serve showconfig debugancestor")
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -1,65 +1,65 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat > writelines.py <<EOF
3 cat > writelines.py <<EOF
4 import sys
4 import sys
5 path = sys.argv[1]
5 path = sys.argv[1]
6 args = sys.argv[2:]
6 args = sys.argv[2:]
7 assert (len(args) % 2) == 0
7 assert (len(args) % 2) == 0
8
8
9 f = file(path, 'wb')
9 f = file(path, 'wb')
10 for i in xrange(len(args)/2):
10 for i in xrange(len(args)/2):
11 count, s = args[2*i:2*i+2]
11 count, s = args[2*i:2*i+2]
12 count = int(count)
12 count = int(count)
13 s = s.decode('string_escape')
13 s = s.decode('string_escape')
14 f.write(s*count)
14 f.write(s*count)
15 f.close()
15 f.close()
16
16
17 EOF
17 EOF
18
18
19 echo "[extensions]" >> $HGRCPATH
19 echo "[extensions]" >> $HGRCPATH
20 echo "mq=" >> $HGRCPATH
20 echo "mq=" >> $HGRCPATH
21 echo "[diff]" >> $HGRCPATH
21 echo "[diff]" >> $HGRCPATH
22 echo "git=1" >> $HGRCPATH
22 echo "git=1" >> $HGRCPATH
23
23
24 hg init repo
24 hg init repo
25 cd repo
25 cd repo
26
26
27 echo % qimport non-existing-file
27 echo % qimport non-existing-file
28 hg qimport non-existing-file
28 hg qimport non-existing-file 2>&1 | sed -e 's/\(No such file or directory:\) .*/\1/'
29
29
30 echo % import URL
30 echo % import URL
31 echo foo >> foo
31 echo foo >> foo
32 hg add foo
32 hg add foo
33 hg diff > $HGTMP/url.diff
33 hg diff > $HGTMP/url.diff
34 hg revert --no-backup foo
34 hg revert --no-backup foo
35 rm foo
35 rm foo
36 hg qimport file://$HGTMP/url.diff
36 hg qimport file://$HGTMP/url.diff
37 hg qun
37 hg qun
38
38
39 echo % import patch that already exists
39 echo % import patch that already exists
40 echo foo2 >> foo
40 echo foo2 >> foo
41 hg add foo
41 hg add foo
42 hg diff > ../url.diff
42 hg diff > ../url.diff
43 hg revert --no-backup foo
43 hg revert --no-backup foo
44 rm foo
44 rm foo
45 hg qimport ../url.diff
45 hg qimport ../url.diff
46 hg qpush
46 hg qpush
47 cat foo
47 cat foo
48 hg qpop
48 hg qpop
49 echo % qimport -f
49 echo % qimport -f
50 hg qimport -f ../url.diff
50 hg qimport -f ../url.diff
51 hg qpush
51 hg qpush
52 cat foo
52 cat foo
53 hg qpop
53 hg qpop
54
54
55 echo % build diff with CRLF
55 echo % build diff with CRLF
56 python ../writelines.py b 5 'a\n' 5 'a\r\n'
56 python ../writelines.py b 5 'a\n' 5 'a\r\n'
57 hg ci -Am addb
57 hg ci -Am addb
58 python ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n'
58 python ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n'
59 hg diff > b.diff
59 hg diff > b.diff
60 hg up -C
60 hg up -C
61 echo % qimport CRLF diff
61 echo % qimport CRLF diff
62 hg qimport b.diff
62 hg qimport b.diff
63 hg qpush
63 hg qpush
64
64
65
65
@@ -1,24 +1,24 b''
1 % qimport non-existing-file
1 % qimport non-existing-file
2 abort: unable to read non-existing-file
2 abort: No such file or directory:
3 % import URL
3 % import URL
4 adding url.diff to series file
4 adding url.diff to series file
5 url.diff
5 url.diff
6 % import patch that already exists
6 % import patch that already exists
7 abort: patch "url.diff" already exists
7 abort: patch "url.diff" already exists
8 applying url.diff
8 applying url.diff
9 Now at: url.diff
9 Now at: url.diff
10 foo
10 foo
11 Patch queue now empty
11 Patch queue now empty
12 % qimport -f
12 % qimport -f
13 adding url.diff to series file
13 adding url.diff to series file
14 applying url.diff
14 applying url.diff
15 Now at: url.diff
15 Now at: url.diff
16 foo2
16 foo2
17 Patch queue now empty
17 Patch queue now empty
18 % build diff with CRLF
18 % build diff with CRLF
19 adding b
19 adding b
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 % qimport CRLF diff
21 % qimport CRLF diff
22 adding b.diff to series file
22 adding b.diff to series file
23 applying b.diff
23 applying b.diff
24 Now at: b.diff
24 Now at: b.diff
General Comments 0
You need to be logged in to leave comments. Login now