##// END OF EJS Templates
Move finding/checking the log limit to cmdutil
Thomas Arendsen Hein -
r6190:a79d9408 default
parent child Browse files
Show More
@@ -1,1163 +1,1176 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in 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 *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, bisect, stat
10 import os, sys, bisect, stat
11 import mdiff, bdiff, util, templater, templatefilters, patch, errno
11 import mdiff, bdiff, util, templater, templatefilters, patch, errno
12
12
13 revrangesep = ':'
13 revrangesep = ':'
14
14
15 class UnknownCommand(Exception):
15 class UnknownCommand(Exception):
16 """Exception raised if command is not in the command table."""
16 """Exception raised if command is not in the command table."""
17 class AmbiguousCommand(Exception):
17 class AmbiguousCommand(Exception):
18 """Exception raised if command shortcut matches more than one command."""
18 """Exception raised if command shortcut matches more than one command."""
19
19
20 def findpossible(ui, cmd, table):
20 def findpossible(ui, cmd, table):
21 """
21 """
22 Return cmd -> (aliases, command table entry)
22 Return cmd -> (aliases, command table entry)
23 for each matching command.
23 for each matching command.
24 Return debug commands (or their aliases) only if no normal command matches.
24 Return debug commands (or their aliases) only if no normal command matches.
25 """
25 """
26 choice = {}
26 choice = {}
27 debugchoice = {}
27 debugchoice = {}
28 for e in table.keys():
28 for e in table.keys():
29 aliases = e.lstrip("^").split("|")
29 aliases = e.lstrip("^").split("|")
30 found = None
30 found = None
31 if cmd in aliases:
31 if cmd in aliases:
32 found = cmd
32 found = cmd
33 elif not ui.config("ui", "strict"):
33 elif not ui.config("ui", "strict"):
34 for a in aliases:
34 for a in aliases:
35 if a.startswith(cmd):
35 if a.startswith(cmd):
36 found = a
36 found = a
37 break
37 break
38 if found is not None:
38 if found is not None:
39 if aliases[0].startswith("debug") or found.startswith("debug"):
39 if aliases[0].startswith("debug") or found.startswith("debug"):
40 debugchoice[found] = (aliases, table[e])
40 debugchoice[found] = (aliases, table[e])
41 else:
41 else:
42 choice[found] = (aliases, table[e])
42 choice[found] = (aliases, table[e])
43
43
44 if not choice and debugchoice:
44 if not choice and debugchoice:
45 choice = debugchoice
45 choice = debugchoice
46
46
47 return choice
47 return choice
48
48
49 def findcmd(ui, cmd, table):
49 def findcmd(ui, cmd, table):
50 """Return (aliases, command table entry) for command string."""
50 """Return (aliases, command table entry) for command string."""
51 choice = findpossible(ui, cmd, table)
51 choice = findpossible(ui, cmd, table)
52
52
53 if cmd in choice:
53 if cmd in choice:
54 return choice[cmd]
54 return choice[cmd]
55
55
56 if len(choice) > 1:
56 if len(choice) > 1:
57 clist = choice.keys()
57 clist = choice.keys()
58 clist.sort()
58 clist.sort()
59 raise AmbiguousCommand(cmd, clist)
59 raise AmbiguousCommand(cmd, clist)
60
60
61 if choice:
61 if choice:
62 return choice.values()[0]
62 return choice.values()[0]
63
63
64 raise UnknownCommand(cmd)
64 raise UnknownCommand(cmd)
65
65
66 def bail_if_changed(repo):
66 def bail_if_changed(repo):
67 if repo.dirstate.parents()[1] != nullid:
67 if repo.dirstate.parents()[1] != nullid:
68 raise util.Abort(_('outstanding uncommitted merge'))
68 raise util.Abort(_('outstanding uncommitted merge'))
69 modified, added, removed, deleted = repo.status()[:4]
69 modified, added, removed, deleted = repo.status()[:4]
70 if modified or added or removed or deleted:
70 if modified or added or removed or deleted:
71 raise util.Abort(_("outstanding uncommitted changes"))
71 raise util.Abort(_("outstanding uncommitted changes"))
72
72
73 def logmessage(opts):
73 def logmessage(opts):
74 """ get the log message according to -m and -l option """
74 """ get the log message according to -m and -l option """
75 message = opts['message']
75 message = opts['message']
76 logfile = opts['logfile']
76 logfile = opts['logfile']
77
77
78 if message and logfile:
78 if message and logfile:
79 raise util.Abort(_('options --message and --logfile are mutually '
79 raise util.Abort(_('options --message and --logfile are mutually '
80 'exclusive'))
80 'exclusive'))
81 if not message and logfile:
81 if not message and logfile:
82 try:
82 try:
83 if logfile == '-':
83 if logfile == '-':
84 message = sys.stdin.read()
84 message = sys.stdin.read()
85 else:
85 else:
86 message = open(logfile).read()
86 message = open(logfile).read()
87 except IOError, inst:
87 except IOError, inst:
88 raise util.Abort(_("can't read commit message '%s': %s") %
88 raise util.Abort(_("can't read commit message '%s': %s") %
89 (logfile, inst.strerror))
89 (logfile, inst.strerror))
90 return message
90 return message
91
91
92 def loglimit(opts):
93 """get the log limit according to option -l/--limit"""
94 limit = opts.get('limit')
95 if limit:
96 try:
97 limit = int(limit)
98 except ValueError:
99 raise util.Abort(_('limit must be a positive integer'))
100 if limit <= 0: raise util.Abort(_('limit must be positive'))
101 else:
102 limit = sys.maxint
103 return limit
104
92 def setremoteconfig(ui, opts):
105 def setremoteconfig(ui, opts):
93 "copy remote options to ui tree"
106 "copy remote options to ui tree"
94 if opts.get('ssh'):
107 if opts.get('ssh'):
95 ui.setconfig("ui", "ssh", opts['ssh'])
108 ui.setconfig("ui", "ssh", opts['ssh'])
96 if opts.get('remotecmd'):
109 if opts.get('remotecmd'):
97 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
110 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
98
111
99 def revpair(repo, revs):
112 def revpair(repo, revs):
100 '''return pair of nodes, given list of revisions. second item can
113 '''return pair of nodes, given list of revisions. second item can
101 be None, meaning use working dir.'''
114 be None, meaning use working dir.'''
102
115
103 def revfix(repo, val, defval):
116 def revfix(repo, val, defval):
104 if not val and val != 0 and defval is not None:
117 if not val and val != 0 and defval is not None:
105 val = defval
118 val = defval
106 return repo.lookup(val)
119 return repo.lookup(val)
107
120
108 if not revs:
121 if not revs:
109 return repo.dirstate.parents()[0], None
122 return repo.dirstate.parents()[0], None
110 end = None
123 end = None
111 if len(revs) == 1:
124 if len(revs) == 1:
112 if revrangesep in revs[0]:
125 if revrangesep in revs[0]:
113 start, end = revs[0].split(revrangesep, 1)
126 start, end = revs[0].split(revrangesep, 1)
114 start = revfix(repo, start, 0)
127 start = revfix(repo, start, 0)
115 end = revfix(repo, end, repo.changelog.count() - 1)
128 end = revfix(repo, end, repo.changelog.count() - 1)
116 else:
129 else:
117 start = revfix(repo, revs[0], None)
130 start = revfix(repo, revs[0], None)
118 elif len(revs) == 2:
131 elif len(revs) == 2:
119 if revrangesep in revs[0] or revrangesep in revs[1]:
132 if revrangesep in revs[0] or revrangesep in revs[1]:
120 raise util.Abort(_('too many revisions specified'))
133 raise util.Abort(_('too many revisions specified'))
121 start = revfix(repo, revs[0], None)
134 start = revfix(repo, revs[0], None)
122 end = revfix(repo, revs[1], None)
135 end = revfix(repo, revs[1], None)
123 else:
136 else:
124 raise util.Abort(_('too many revisions specified'))
137 raise util.Abort(_('too many revisions specified'))
125 return start, end
138 return start, end
126
139
127 def revrange(repo, revs):
140 def revrange(repo, revs):
128 """Yield revision as strings from a list of revision specifications."""
141 """Yield revision as strings from a list of revision specifications."""
129
142
130 def revfix(repo, val, defval):
143 def revfix(repo, val, defval):
131 if not val and val != 0 and defval is not None:
144 if not val and val != 0 and defval is not None:
132 return defval
145 return defval
133 return repo.changelog.rev(repo.lookup(val))
146 return repo.changelog.rev(repo.lookup(val))
134
147
135 seen, l = {}, []
148 seen, l = {}, []
136 for spec in revs:
149 for spec in revs:
137 if revrangesep in spec:
150 if revrangesep in spec:
138 start, end = spec.split(revrangesep, 1)
151 start, end = spec.split(revrangesep, 1)
139 start = revfix(repo, start, 0)
152 start = revfix(repo, start, 0)
140 end = revfix(repo, end, repo.changelog.count() - 1)
153 end = revfix(repo, end, repo.changelog.count() - 1)
141 step = start > end and -1 or 1
154 step = start > end and -1 or 1
142 for rev in xrange(start, end+step, step):
155 for rev in xrange(start, end+step, step):
143 if rev in seen:
156 if rev in seen:
144 continue
157 continue
145 seen[rev] = 1
158 seen[rev] = 1
146 l.append(rev)
159 l.append(rev)
147 else:
160 else:
148 rev = revfix(repo, spec, None)
161 rev = revfix(repo, spec, None)
149 if rev in seen:
162 if rev in seen:
150 continue
163 continue
151 seen[rev] = 1
164 seen[rev] = 1
152 l.append(rev)
165 l.append(rev)
153
166
154 return l
167 return l
155
168
156 def make_filename(repo, pat, node,
169 def make_filename(repo, pat, node,
157 total=None, seqno=None, revwidth=None, pathname=None):
170 total=None, seqno=None, revwidth=None, pathname=None):
158 node_expander = {
171 node_expander = {
159 'H': lambda: hex(node),
172 'H': lambda: hex(node),
160 'R': lambda: str(repo.changelog.rev(node)),
173 'R': lambda: str(repo.changelog.rev(node)),
161 'h': lambda: short(node),
174 'h': lambda: short(node),
162 }
175 }
163 expander = {
176 expander = {
164 '%': lambda: '%',
177 '%': lambda: '%',
165 'b': lambda: os.path.basename(repo.root),
178 'b': lambda: os.path.basename(repo.root),
166 }
179 }
167
180
168 try:
181 try:
169 if node:
182 if node:
170 expander.update(node_expander)
183 expander.update(node_expander)
171 if node:
184 if node:
172 expander['r'] = (lambda:
185 expander['r'] = (lambda:
173 str(repo.changelog.rev(node)).zfill(revwidth or 0))
186 str(repo.changelog.rev(node)).zfill(revwidth or 0))
174 if total is not None:
187 if total is not None:
175 expander['N'] = lambda: str(total)
188 expander['N'] = lambda: str(total)
176 if seqno is not None:
189 if seqno is not None:
177 expander['n'] = lambda: str(seqno)
190 expander['n'] = lambda: str(seqno)
178 if total is not None and seqno is not None:
191 if total is not None and seqno is not None:
179 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
192 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
180 if pathname is not None:
193 if pathname is not None:
181 expander['s'] = lambda: os.path.basename(pathname)
194 expander['s'] = lambda: os.path.basename(pathname)
182 expander['d'] = lambda: os.path.dirname(pathname) or '.'
195 expander['d'] = lambda: os.path.dirname(pathname) or '.'
183 expander['p'] = lambda: pathname
196 expander['p'] = lambda: pathname
184
197
185 newname = []
198 newname = []
186 patlen = len(pat)
199 patlen = len(pat)
187 i = 0
200 i = 0
188 while i < patlen:
201 while i < patlen:
189 c = pat[i]
202 c = pat[i]
190 if c == '%':
203 if c == '%':
191 i += 1
204 i += 1
192 c = pat[i]
205 c = pat[i]
193 c = expander[c]()
206 c = expander[c]()
194 newname.append(c)
207 newname.append(c)
195 i += 1
208 i += 1
196 return ''.join(newname)
209 return ''.join(newname)
197 except KeyError, inst:
210 except KeyError, inst:
198 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
211 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
199 inst.args[0])
212 inst.args[0])
200
213
201 def make_file(repo, pat, node=None,
214 def make_file(repo, pat, node=None,
202 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
215 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
203 if not pat or pat == '-':
216 if not pat or pat == '-':
204 return 'w' in mode and sys.stdout or sys.stdin
217 return 'w' in mode and sys.stdout or sys.stdin
205 if hasattr(pat, 'write') and 'w' in mode:
218 if hasattr(pat, 'write') and 'w' in mode:
206 return pat
219 return pat
207 if hasattr(pat, 'read') and 'r' in mode:
220 if hasattr(pat, 'read') and 'r' in mode:
208 return pat
221 return pat
209 return open(make_filename(repo, pat, node, total, seqno, revwidth,
222 return open(make_filename(repo, pat, node, total, seqno, revwidth,
210 pathname),
223 pathname),
211 mode)
224 mode)
212
225
213 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
226 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
214 cwd = repo.getcwd()
227 cwd = repo.getcwd()
215 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
228 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
216 opts.get('exclude'), globbed=globbed,
229 opts.get('exclude'), globbed=globbed,
217 default=default)
230 default=default)
218
231
219 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
232 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
220 default=None):
233 default=None):
221 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
234 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
222 default=default)
235 default=default)
223 exact = dict.fromkeys(files)
236 exact = dict.fromkeys(files)
224 cwd = repo.getcwd()
237 cwd = repo.getcwd()
225 for src, fn in repo.walk(node=node, files=files, match=matchfn,
238 for src, fn in repo.walk(node=node, files=files, match=matchfn,
226 badmatch=badmatch):
239 badmatch=badmatch):
227 yield src, fn, repo.pathto(fn, cwd), fn in exact
240 yield src, fn, repo.pathto(fn, cwd), fn in exact
228
241
229 def findrenames(repo, added=None, removed=None, threshold=0.5):
242 def findrenames(repo, added=None, removed=None, threshold=0.5):
230 '''find renamed files -- yields (before, after, score) tuples'''
243 '''find renamed files -- yields (before, after, score) tuples'''
231 if added is None or removed is None:
244 if added is None or removed is None:
232 added, removed = repo.status()[1:3]
245 added, removed = repo.status()[1:3]
233 ctx = repo.changectx()
246 ctx = repo.changectx()
234 for a in added:
247 for a in added:
235 aa = repo.wread(a)
248 aa = repo.wread(a)
236 bestname, bestscore = None, threshold
249 bestname, bestscore = None, threshold
237 for r in removed:
250 for r in removed:
238 rr = ctx.filectx(r).data()
251 rr = ctx.filectx(r).data()
239
252
240 # bdiff.blocks() returns blocks of matching lines
253 # bdiff.blocks() returns blocks of matching lines
241 # count the number of bytes in each
254 # count the number of bytes in each
242 equal = 0
255 equal = 0
243 alines = mdiff.splitnewlines(aa)
256 alines = mdiff.splitnewlines(aa)
244 matches = bdiff.blocks(aa, rr)
257 matches = bdiff.blocks(aa, rr)
245 for x1,x2,y1,y2 in matches:
258 for x1,x2,y1,y2 in matches:
246 for line in alines[x1:x2]:
259 for line in alines[x1:x2]:
247 equal += len(line)
260 equal += len(line)
248
261
249 lengths = len(aa) + len(rr)
262 lengths = len(aa) + len(rr)
250 if lengths:
263 if lengths:
251 myscore = equal*2.0 / lengths
264 myscore = equal*2.0 / lengths
252 if myscore >= bestscore:
265 if myscore >= bestscore:
253 bestname, bestscore = r, myscore
266 bestname, bestscore = r, myscore
254 if bestname:
267 if bestname:
255 yield bestname, a, bestscore
268 yield bestname, a, bestscore
256
269
257 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
270 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
258 if dry_run is None:
271 if dry_run is None:
259 dry_run = opts.get('dry_run')
272 dry_run = opts.get('dry_run')
260 if similarity is None:
273 if similarity is None:
261 similarity = float(opts.get('similarity') or 0)
274 similarity = float(opts.get('similarity') or 0)
262 add, remove = [], []
275 add, remove = [], []
263 mapping = {}
276 mapping = {}
264 for src, abs, rel, exact in walk(repo, pats, opts):
277 for src, abs, rel, exact in walk(repo, pats, opts):
265 target = repo.wjoin(abs)
278 target = repo.wjoin(abs)
266 if src == 'f' and abs not in repo.dirstate:
279 if src == 'f' and abs not in repo.dirstate:
267 add.append(abs)
280 add.append(abs)
268 mapping[abs] = rel, exact
281 mapping[abs] = rel, exact
269 if repo.ui.verbose or not exact:
282 if repo.ui.verbose or not exact:
270 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
283 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
271 if repo.dirstate[abs] != 'r' and (not util.lexists(target)
284 if repo.dirstate[abs] != 'r' and (not util.lexists(target)
272 or (os.path.isdir(target) and not os.path.islink(target))):
285 or (os.path.isdir(target) and not os.path.islink(target))):
273 remove.append(abs)
286 remove.append(abs)
274 mapping[abs] = rel, exact
287 mapping[abs] = rel, exact
275 if repo.ui.verbose or not exact:
288 if repo.ui.verbose or not exact:
276 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
289 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
277 if not dry_run:
290 if not dry_run:
278 repo.remove(remove)
291 repo.remove(remove)
279 repo.add(add)
292 repo.add(add)
280 if similarity > 0:
293 if similarity > 0:
281 for old, new, score in findrenames(repo, add, remove, similarity):
294 for old, new, score in findrenames(repo, add, remove, similarity):
282 oldrel, oldexact = mapping[old]
295 oldrel, oldexact = mapping[old]
283 newrel, newexact = mapping[new]
296 newrel, newexact = mapping[new]
284 if repo.ui.verbose or not oldexact or not newexact:
297 if repo.ui.verbose or not oldexact or not newexact:
285 repo.ui.status(_('recording removal of %s as rename to %s '
298 repo.ui.status(_('recording removal of %s as rename to %s '
286 '(%d%% similar)\n') %
299 '(%d%% similar)\n') %
287 (oldrel, newrel, score * 100))
300 (oldrel, newrel, score * 100))
288 if not dry_run:
301 if not dry_run:
289 repo.copy(old, new)
302 repo.copy(old, new)
290
303
291 def copy(ui, repo, pats, opts, rename=False):
304 def copy(ui, repo, pats, opts, rename=False):
292 # called with the repo lock held
305 # called with the repo lock held
293 #
306 #
294 # hgsep => pathname that uses "/" to separate directories
307 # hgsep => pathname that uses "/" to separate directories
295 # ossep => pathname that uses os.sep to separate directories
308 # ossep => pathname that uses os.sep to separate directories
296 cwd = repo.getcwd()
309 cwd = repo.getcwd()
297 targets = {}
310 targets = {}
298 after = opts.get("after")
311 after = opts.get("after")
299 dryrun = opts.get("dry_run")
312 dryrun = opts.get("dry_run")
300
313
301 def walkpat(pat):
314 def walkpat(pat):
302 srcs = []
315 srcs = []
303 for tag, abs, rel, exact in walk(repo, [pat], opts, globbed=True):
316 for tag, abs, rel, exact in walk(repo, [pat], opts, globbed=True):
304 state = repo.dirstate[abs]
317 state = repo.dirstate[abs]
305 if state in '?r':
318 if state in '?r':
306 if exact and state == '?':
319 if exact and state == '?':
307 ui.warn(_('%s: not copying - file is not managed\n') % rel)
320 ui.warn(_('%s: not copying - file is not managed\n') % rel)
308 if exact and state == 'r':
321 if exact and state == 'r':
309 ui.warn(_('%s: not copying - file has been marked for'
322 ui.warn(_('%s: not copying - file has been marked for'
310 ' remove\n') % rel)
323 ' remove\n') % rel)
311 continue
324 continue
312 # abs: hgsep
325 # abs: hgsep
313 # rel: ossep
326 # rel: ossep
314 srcs.append((abs, rel, exact))
327 srcs.append((abs, rel, exact))
315 return srcs
328 return srcs
316
329
317 # abssrc: hgsep
330 # abssrc: hgsep
318 # relsrc: ossep
331 # relsrc: ossep
319 # otarget: ossep
332 # otarget: ossep
320 def copyfile(abssrc, relsrc, otarget, exact):
333 def copyfile(abssrc, relsrc, otarget, exact):
321 abstarget = util.canonpath(repo.root, cwd, otarget)
334 abstarget = util.canonpath(repo.root, cwd, otarget)
322 reltarget = repo.pathto(abstarget, cwd)
335 reltarget = repo.pathto(abstarget, cwd)
323 target = repo.wjoin(abstarget)
336 target = repo.wjoin(abstarget)
324 src = repo.wjoin(abssrc)
337 src = repo.wjoin(abssrc)
325 state = repo.dirstate[abstarget]
338 state = repo.dirstate[abstarget]
326
339
327 # check for collisions
340 # check for collisions
328 prevsrc = targets.get(abstarget)
341 prevsrc = targets.get(abstarget)
329 if prevsrc is not None:
342 if prevsrc is not None:
330 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
343 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
331 (reltarget, repo.pathto(abssrc, cwd),
344 (reltarget, repo.pathto(abssrc, cwd),
332 repo.pathto(prevsrc, cwd)))
345 repo.pathto(prevsrc, cwd)))
333 return
346 return
334
347
335 # check for overwrites
348 # check for overwrites
336 exists = os.path.exists(target)
349 exists = os.path.exists(target)
337 if (not after and exists or after and state in 'mn'):
350 if (not after and exists or after and state in 'mn'):
338 if not opts['force']:
351 if not opts['force']:
339 ui.warn(_('%s: not overwriting - file exists\n') %
352 ui.warn(_('%s: not overwriting - file exists\n') %
340 reltarget)
353 reltarget)
341 return
354 return
342
355
343 if after:
356 if after:
344 if not exists:
357 if not exists:
345 return
358 return
346 elif not dryrun:
359 elif not dryrun:
347 try:
360 try:
348 if exists:
361 if exists:
349 os.unlink(target)
362 os.unlink(target)
350 targetdir = os.path.dirname(target) or '.'
363 targetdir = os.path.dirname(target) or '.'
351 if not os.path.isdir(targetdir):
364 if not os.path.isdir(targetdir):
352 os.makedirs(targetdir)
365 os.makedirs(targetdir)
353 util.copyfile(src, target)
366 util.copyfile(src, target)
354 except IOError, inst:
367 except IOError, inst:
355 if inst.errno == errno.ENOENT:
368 if inst.errno == errno.ENOENT:
356 ui.warn(_('%s: deleted in working copy\n') % relsrc)
369 ui.warn(_('%s: deleted in working copy\n') % relsrc)
357 else:
370 else:
358 ui.warn(_('%s: cannot copy - %s\n') %
371 ui.warn(_('%s: cannot copy - %s\n') %
359 (relsrc, inst.strerror))
372 (relsrc, inst.strerror))
360 return True # report a failure
373 return True # report a failure
361
374
362 if ui.verbose or not exact:
375 if ui.verbose or not exact:
363 action = rename and "moving" or "copying"
376 action = rename and "moving" or "copying"
364 ui.status(_('%s %s to %s\n') % (action, relsrc, reltarget))
377 ui.status(_('%s %s to %s\n') % (action, relsrc, reltarget))
365
378
366 targets[abstarget] = abssrc
379 targets[abstarget] = abssrc
367
380
368 # fix up dirstate
381 # fix up dirstate
369 origsrc = repo.dirstate.copied(abssrc) or abssrc
382 origsrc = repo.dirstate.copied(abssrc) or abssrc
370 if abstarget == origsrc: # copying back a copy?
383 if abstarget == origsrc: # copying back a copy?
371 if state not in 'mn' and not dryrun:
384 if state not in 'mn' and not dryrun:
372 repo.dirstate.normallookup(abstarget)
385 repo.dirstate.normallookup(abstarget)
373 else:
386 else:
374 if repo.dirstate[origsrc] == 'a':
387 if repo.dirstate[origsrc] == 'a':
375 if not ui.quiet:
388 if not ui.quiet:
376 ui.warn(_("%s has not been committed yet, so no copy "
389 ui.warn(_("%s has not been committed yet, so no copy "
377 "data will be stored for %s.\n")
390 "data will be stored for %s.\n")
378 % (repo.pathto(origsrc, cwd), reltarget))
391 % (repo.pathto(origsrc, cwd), reltarget))
379 if abstarget not in repo.dirstate and not dryrun:
392 if abstarget not in repo.dirstate and not dryrun:
380 repo.add([abstarget])
393 repo.add([abstarget])
381 elif not dryrun:
394 elif not dryrun:
382 repo.copy(origsrc, abstarget)
395 repo.copy(origsrc, abstarget)
383
396
384 if rename and not dryrun:
397 if rename and not dryrun:
385 repo.remove([abssrc], True)
398 repo.remove([abssrc], True)
386
399
387 # pat: ossep
400 # pat: ossep
388 # dest ossep
401 # dest ossep
389 # srcs: list of (hgsep, hgsep, ossep, bool)
402 # srcs: list of (hgsep, hgsep, ossep, bool)
390 # return: function that takes hgsep and returns ossep
403 # return: function that takes hgsep and returns ossep
391 def targetpathfn(pat, dest, srcs):
404 def targetpathfn(pat, dest, srcs):
392 if os.path.isdir(pat):
405 if os.path.isdir(pat):
393 abspfx = util.canonpath(repo.root, cwd, pat)
406 abspfx = util.canonpath(repo.root, cwd, pat)
394 abspfx = util.localpath(abspfx)
407 abspfx = util.localpath(abspfx)
395 if destdirexists:
408 if destdirexists:
396 striplen = len(os.path.split(abspfx)[0])
409 striplen = len(os.path.split(abspfx)[0])
397 else:
410 else:
398 striplen = len(abspfx)
411 striplen = len(abspfx)
399 if striplen:
412 if striplen:
400 striplen += len(os.sep)
413 striplen += len(os.sep)
401 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
414 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
402 elif destdirexists:
415 elif destdirexists:
403 res = lambda p: os.path.join(dest,
416 res = lambda p: os.path.join(dest,
404 os.path.basename(util.localpath(p)))
417 os.path.basename(util.localpath(p)))
405 else:
418 else:
406 res = lambda p: dest
419 res = lambda p: dest
407 return res
420 return res
408
421
409 # pat: ossep
422 # pat: ossep
410 # dest ossep
423 # dest ossep
411 # srcs: list of (hgsep, hgsep, ossep, bool)
424 # srcs: list of (hgsep, hgsep, ossep, bool)
412 # return: function that takes hgsep and returns ossep
425 # return: function that takes hgsep and returns ossep
413 def targetpathafterfn(pat, dest, srcs):
426 def targetpathafterfn(pat, dest, srcs):
414 if util.patkind(pat, None)[0]:
427 if util.patkind(pat, None)[0]:
415 # a mercurial pattern
428 # a mercurial pattern
416 res = lambda p: os.path.join(dest,
429 res = lambda p: os.path.join(dest,
417 os.path.basename(util.localpath(p)))
430 os.path.basename(util.localpath(p)))
418 else:
431 else:
419 abspfx = util.canonpath(repo.root, cwd, pat)
432 abspfx = util.canonpath(repo.root, cwd, pat)
420 if len(abspfx) < len(srcs[0][0]):
433 if len(abspfx) < len(srcs[0][0]):
421 # A directory. Either the target path contains the last
434 # A directory. Either the target path contains the last
422 # component of the source path or it does not.
435 # component of the source path or it does not.
423 def evalpath(striplen):
436 def evalpath(striplen):
424 score = 0
437 score = 0
425 for s in srcs:
438 for s in srcs:
426 t = os.path.join(dest, util.localpath(s[0])[striplen:])
439 t = os.path.join(dest, util.localpath(s[0])[striplen:])
427 if os.path.exists(t):
440 if os.path.exists(t):
428 score += 1
441 score += 1
429 return score
442 return score
430
443
431 abspfx = util.localpath(abspfx)
444 abspfx = util.localpath(abspfx)
432 striplen = len(abspfx)
445 striplen = len(abspfx)
433 if striplen:
446 if striplen:
434 striplen += len(os.sep)
447 striplen += len(os.sep)
435 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
448 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
436 score = evalpath(striplen)
449 score = evalpath(striplen)
437 striplen1 = len(os.path.split(abspfx)[0])
450 striplen1 = len(os.path.split(abspfx)[0])
438 if striplen1:
451 if striplen1:
439 striplen1 += len(os.sep)
452 striplen1 += len(os.sep)
440 if evalpath(striplen1) > score:
453 if evalpath(striplen1) > score:
441 striplen = striplen1
454 striplen = striplen1
442 res = lambda p: os.path.join(dest,
455 res = lambda p: os.path.join(dest,
443 util.localpath(p)[striplen:])
456 util.localpath(p)[striplen:])
444 else:
457 else:
445 # a file
458 # a file
446 if destdirexists:
459 if destdirexists:
447 res = lambda p: os.path.join(dest,
460 res = lambda p: os.path.join(dest,
448 os.path.basename(util.localpath(p)))
461 os.path.basename(util.localpath(p)))
449 else:
462 else:
450 res = lambda p: dest
463 res = lambda p: dest
451 return res
464 return res
452
465
453
466
454 pats = util.expand_glob(pats)
467 pats = util.expand_glob(pats)
455 if not pats:
468 if not pats:
456 raise util.Abort(_('no source or destination specified'))
469 raise util.Abort(_('no source or destination specified'))
457 if len(pats) == 1:
470 if len(pats) == 1:
458 raise util.Abort(_('no destination specified'))
471 raise util.Abort(_('no destination specified'))
459 dest = pats.pop()
472 dest = pats.pop()
460 destdirexists = os.path.isdir(dest)
473 destdirexists = os.path.isdir(dest)
461 if not destdirexists:
474 if not destdirexists:
462 if len(pats) > 1 or util.patkind(pats[0], None)[0]:
475 if len(pats) > 1 or util.patkind(pats[0], None)[0]:
463 raise util.Abort(_('with multiple sources, destination must be an '
476 raise util.Abort(_('with multiple sources, destination must be an '
464 'existing directory'))
477 'existing directory'))
465 if util.endswithsep(dest):
478 if util.endswithsep(dest):
466 raise util.Abort(_('destination %s is not a directory') % dest)
479 raise util.Abort(_('destination %s is not a directory') % dest)
467
480
468 tfn = targetpathfn
481 tfn = targetpathfn
469 if after:
482 if after:
470 tfn = targetpathafterfn
483 tfn = targetpathafterfn
471 copylist = []
484 copylist = []
472 for pat in pats:
485 for pat in pats:
473 srcs = walkpat(pat)
486 srcs = walkpat(pat)
474 if not srcs:
487 if not srcs:
475 continue
488 continue
476 copylist.append((tfn(pat, dest, srcs), srcs))
489 copylist.append((tfn(pat, dest, srcs), srcs))
477 if not copylist:
490 if not copylist:
478 raise util.Abort(_('no files to copy'))
491 raise util.Abort(_('no files to copy'))
479
492
480 errors = 0
493 errors = 0
481 for targetpath, srcs in copylist:
494 for targetpath, srcs in copylist:
482 for abssrc, relsrc, exact in srcs:
495 for abssrc, relsrc, exact in srcs:
483 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
496 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
484 errors += 1
497 errors += 1
485
498
486 if errors:
499 if errors:
487 ui.warn(_('(consider using --after)\n'))
500 ui.warn(_('(consider using --after)\n'))
488
501
489 return errors
502 return errors
490
503
491 def service(opts, parentfn=None, initfn=None, runfn=None):
504 def service(opts, parentfn=None, initfn=None, runfn=None):
492 '''Run a command as a service.'''
505 '''Run a command as a service.'''
493
506
494 if opts['daemon'] and not opts['daemon_pipefds']:
507 if opts['daemon'] and not opts['daemon_pipefds']:
495 rfd, wfd = os.pipe()
508 rfd, wfd = os.pipe()
496 args = sys.argv[:]
509 args = sys.argv[:]
497 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
510 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
498 # Don't pass --cwd to the child process, because we've already
511 # Don't pass --cwd to the child process, because we've already
499 # changed directory.
512 # changed directory.
500 for i in xrange(1,len(args)):
513 for i in xrange(1,len(args)):
501 if args[i].startswith('--cwd='):
514 if args[i].startswith('--cwd='):
502 del args[i]
515 del args[i]
503 break
516 break
504 elif args[i].startswith('--cwd'):
517 elif args[i].startswith('--cwd'):
505 del args[i:i+2]
518 del args[i:i+2]
506 break
519 break
507 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
520 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
508 args[0], args)
521 args[0], args)
509 os.close(wfd)
522 os.close(wfd)
510 os.read(rfd, 1)
523 os.read(rfd, 1)
511 if parentfn:
524 if parentfn:
512 return parentfn(pid)
525 return parentfn(pid)
513 else:
526 else:
514 os._exit(0)
527 os._exit(0)
515
528
516 if initfn:
529 if initfn:
517 initfn()
530 initfn()
518
531
519 if opts['pid_file']:
532 if opts['pid_file']:
520 fp = open(opts['pid_file'], 'w')
533 fp = open(opts['pid_file'], 'w')
521 fp.write(str(os.getpid()) + '\n')
534 fp.write(str(os.getpid()) + '\n')
522 fp.close()
535 fp.close()
523
536
524 if opts['daemon_pipefds']:
537 if opts['daemon_pipefds']:
525 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
538 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
526 os.close(rfd)
539 os.close(rfd)
527 try:
540 try:
528 os.setsid()
541 os.setsid()
529 except AttributeError:
542 except AttributeError:
530 pass
543 pass
531 os.write(wfd, 'y')
544 os.write(wfd, 'y')
532 os.close(wfd)
545 os.close(wfd)
533 sys.stdout.flush()
546 sys.stdout.flush()
534 sys.stderr.flush()
547 sys.stderr.flush()
535 fd = os.open(util.nulldev, os.O_RDWR)
548 fd = os.open(util.nulldev, os.O_RDWR)
536 if fd != 0: os.dup2(fd, 0)
549 if fd != 0: os.dup2(fd, 0)
537 if fd != 1: os.dup2(fd, 1)
550 if fd != 1: os.dup2(fd, 1)
538 if fd != 2: os.dup2(fd, 2)
551 if fd != 2: os.dup2(fd, 2)
539 if fd not in (0, 1, 2): os.close(fd)
552 if fd not in (0, 1, 2): os.close(fd)
540
553
541 if runfn:
554 if runfn:
542 return runfn()
555 return runfn()
543
556
544 class changeset_printer(object):
557 class changeset_printer(object):
545 '''show changeset information when templating not requested.'''
558 '''show changeset information when templating not requested.'''
546
559
547 def __init__(self, ui, repo, patch, buffered):
560 def __init__(self, ui, repo, patch, buffered):
548 self.ui = ui
561 self.ui = ui
549 self.repo = repo
562 self.repo = repo
550 self.buffered = buffered
563 self.buffered = buffered
551 self.patch = patch
564 self.patch = patch
552 self.header = {}
565 self.header = {}
553 self.hunk = {}
566 self.hunk = {}
554 self.lastheader = None
567 self.lastheader = None
555
568
556 def flush(self, rev):
569 def flush(self, rev):
557 if rev in self.header:
570 if rev in self.header:
558 h = self.header[rev]
571 h = self.header[rev]
559 if h != self.lastheader:
572 if h != self.lastheader:
560 self.lastheader = h
573 self.lastheader = h
561 self.ui.write(h)
574 self.ui.write(h)
562 del self.header[rev]
575 del self.header[rev]
563 if rev in self.hunk:
576 if rev in self.hunk:
564 self.ui.write(self.hunk[rev])
577 self.ui.write(self.hunk[rev])
565 del self.hunk[rev]
578 del self.hunk[rev]
566 return 1
579 return 1
567 return 0
580 return 0
568
581
569 def show(self, rev=0, changenode=None, copies=(), **props):
582 def show(self, rev=0, changenode=None, copies=(), **props):
570 if self.buffered:
583 if self.buffered:
571 self.ui.pushbuffer()
584 self.ui.pushbuffer()
572 self._show(rev, changenode, copies, props)
585 self._show(rev, changenode, copies, props)
573 self.hunk[rev] = self.ui.popbuffer()
586 self.hunk[rev] = self.ui.popbuffer()
574 else:
587 else:
575 self._show(rev, changenode, copies, props)
588 self._show(rev, changenode, copies, props)
576
589
577 def _show(self, rev, changenode, copies, props):
590 def _show(self, rev, changenode, copies, props):
578 '''show a single changeset or file revision'''
591 '''show a single changeset or file revision'''
579 log = self.repo.changelog
592 log = self.repo.changelog
580 if changenode is None:
593 if changenode is None:
581 changenode = log.node(rev)
594 changenode = log.node(rev)
582 elif not rev:
595 elif not rev:
583 rev = log.rev(changenode)
596 rev = log.rev(changenode)
584
597
585 if self.ui.quiet:
598 if self.ui.quiet:
586 self.ui.write("%d:%s\n" % (rev, short(changenode)))
599 self.ui.write("%d:%s\n" % (rev, short(changenode)))
587 return
600 return
588
601
589 changes = log.read(changenode)
602 changes = log.read(changenode)
590 date = util.datestr(changes[2])
603 date = util.datestr(changes[2])
591 extra = changes[5]
604 extra = changes[5]
592 branch = extra.get("branch")
605 branch = extra.get("branch")
593
606
594 hexfunc = self.ui.debugflag and hex or short
607 hexfunc = self.ui.debugflag and hex or short
595
608
596 parents = [(p, hexfunc(log.node(p)))
609 parents = [(p, hexfunc(log.node(p)))
597 for p in self._meaningful_parentrevs(log, rev)]
610 for p in self._meaningful_parentrevs(log, rev)]
598
611
599 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
612 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
600
613
601 # don't show the default branch name
614 # don't show the default branch name
602 if branch != 'default':
615 if branch != 'default':
603 branch = util.tolocal(branch)
616 branch = util.tolocal(branch)
604 self.ui.write(_("branch: %s\n") % branch)
617 self.ui.write(_("branch: %s\n") % branch)
605 for tag in self.repo.nodetags(changenode):
618 for tag in self.repo.nodetags(changenode):
606 self.ui.write(_("tag: %s\n") % tag)
619 self.ui.write(_("tag: %s\n") % tag)
607 for parent in parents:
620 for parent in parents:
608 self.ui.write(_("parent: %d:%s\n") % parent)
621 self.ui.write(_("parent: %d:%s\n") % parent)
609
622
610 if self.ui.debugflag:
623 if self.ui.debugflag:
611 self.ui.write(_("manifest: %d:%s\n") %
624 self.ui.write(_("manifest: %d:%s\n") %
612 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
625 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
613 self.ui.write(_("user: %s\n") % changes[1])
626 self.ui.write(_("user: %s\n") % changes[1])
614 self.ui.write(_("date: %s\n") % date)
627 self.ui.write(_("date: %s\n") % date)
615
628
616 if self.ui.debugflag:
629 if self.ui.debugflag:
617 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
630 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
618 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
631 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
619 files):
632 files):
620 if value:
633 if value:
621 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
634 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
622 elif changes[3] and self.ui.verbose:
635 elif changes[3] and self.ui.verbose:
623 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
636 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
624 if copies and self.ui.verbose:
637 if copies and self.ui.verbose:
625 copies = ['%s (%s)' % c for c in copies]
638 copies = ['%s (%s)' % c for c in copies]
626 self.ui.write(_("copies: %s\n") % ' '.join(copies))
639 self.ui.write(_("copies: %s\n") % ' '.join(copies))
627
640
628 if extra and self.ui.debugflag:
641 if extra and self.ui.debugflag:
629 extraitems = extra.items()
642 extraitems = extra.items()
630 extraitems.sort()
643 extraitems.sort()
631 for key, value in extraitems:
644 for key, value in extraitems:
632 self.ui.write(_("extra: %s=%s\n")
645 self.ui.write(_("extra: %s=%s\n")
633 % (key, value.encode('string_escape')))
646 % (key, value.encode('string_escape')))
634
647
635 description = changes[4].strip()
648 description = changes[4].strip()
636 if description:
649 if description:
637 if self.ui.verbose:
650 if self.ui.verbose:
638 self.ui.write(_("description:\n"))
651 self.ui.write(_("description:\n"))
639 self.ui.write(description)
652 self.ui.write(description)
640 self.ui.write("\n\n")
653 self.ui.write("\n\n")
641 else:
654 else:
642 self.ui.write(_("summary: %s\n") %
655 self.ui.write(_("summary: %s\n") %
643 description.splitlines()[0])
656 description.splitlines()[0])
644 self.ui.write("\n")
657 self.ui.write("\n")
645
658
646 self.showpatch(changenode)
659 self.showpatch(changenode)
647
660
648 def showpatch(self, node):
661 def showpatch(self, node):
649 if self.patch:
662 if self.patch:
650 prev = self.repo.changelog.parents(node)[0]
663 prev = self.repo.changelog.parents(node)[0]
651 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
664 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
652 opts=patch.diffopts(self.ui))
665 opts=patch.diffopts(self.ui))
653 self.ui.write("\n")
666 self.ui.write("\n")
654
667
655 def _meaningful_parentrevs(self, log, rev):
668 def _meaningful_parentrevs(self, log, rev):
656 """Return list of meaningful (or all if debug) parentrevs for rev.
669 """Return list of meaningful (or all if debug) parentrevs for rev.
657
670
658 For merges (two non-nullrev revisions) both parents are meaningful.
671 For merges (two non-nullrev revisions) both parents are meaningful.
659 Otherwise the first parent revision is considered meaningful if it
672 Otherwise the first parent revision is considered meaningful if it
660 is not the preceding revision.
673 is not the preceding revision.
661 """
674 """
662 parents = log.parentrevs(rev)
675 parents = log.parentrevs(rev)
663 if not self.ui.debugflag and parents[1] == nullrev:
676 if not self.ui.debugflag and parents[1] == nullrev:
664 if parents[0] >= rev - 1:
677 if parents[0] >= rev - 1:
665 parents = []
678 parents = []
666 else:
679 else:
667 parents = [parents[0]]
680 parents = [parents[0]]
668 return parents
681 return parents
669
682
670
683
671 class changeset_templater(changeset_printer):
684 class changeset_templater(changeset_printer):
672 '''format changeset information.'''
685 '''format changeset information.'''
673
686
674 def __init__(self, ui, repo, patch, mapfile, buffered):
687 def __init__(self, ui, repo, patch, mapfile, buffered):
675 changeset_printer.__init__(self, ui, repo, patch, buffered)
688 changeset_printer.__init__(self, ui, repo, patch, buffered)
676 filters = templatefilters.filters.copy()
689 filters = templatefilters.filters.copy()
677 filters['formatnode'] = (ui.debugflag and (lambda x: x)
690 filters['formatnode'] = (ui.debugflag and (lambda x: x)
678 or (lambda x: x[:12]))
691 or (lambda x: x[:12]))
679 self.t = templater.templater(mapfile, filters,
692 self.t = templater.templater(mapfile, filters,
680 cache={
693 cache={
681 'parent': '{rev}:{node|formatnode} ',
694 'parent': '{rev}:{node|formatnode} ',
682 'manifest': '{rev}:{node|formatnode}',
695 'manifest': '{rev}:{node|formatnode}',
683 'filecopy': '{name} ({source})'})
696 'filecopy': '{name} ({source})'})
684
697
685 def use_template(self, t):
698 def use_template(self, t):
686 '''set template string to use'''
699 '''set template string to use'''
687 self.t.cache['changeset'] = t
700 self.t.cache['changeset'] = t
688
701
689 def _show(self, rev, changenode, copies, props):
702 def _show(self, rev, changenode, copies, props):
690 '''show a single changeset or file revision'''
703 '''show a single changeset or file revision'''
691 log = self.repo.changelog
704 log = self.repo.changelog
692 if changenode is None:
705 if changenode is None:
693 changenode = log.node(rev)
706 changenode = log.node(rev)
694 elif not rev:
707 elif not rev:
695 rev = log.rev(changenode)
708 rev = log.rev(changenode)
696
709
697 changes = log.read(changenode)
710 changes = log.read(changenode)
698
711
699 def showlist(name, values, plural=None, **args):
712 def showlist(name, values, plural=None, **args):
700 '''expand set of values.
713 '''expand set of values.
701 name is name of key in template map.
714 name is name of key in template map.
702 values is list of strings or dicts.
715 values is list of strings or dicts.
703 plural is plural of name, if not simply name + 's'.
716 plural is plural of name, if not simply name + 's'.
704
717
705 expansion works like this, given name 'foo'.
718 expansion works like this, given name 'foo'.
706
719
707 if values is empty, expand 'no_foos'.
720 if values is empty, expand 'no_foos'.
708
721
709 if 'foo' not in template map, return values as a string,
722 if 'foo' not in template map, return values as a string,
710 joined by space.
723 joined by space.
711
724
712 expand 'start_foos'.
725 expand 'start_foos'.
713
726
714 for each value, expand 'foo'. if 'last_foo' in template
727 for each value, expand 'foo'. if 'last_foo' in template
715 map, expand it instead of 'foo' for last key.
728 map, expand it instead of 'foo' for last key.
716
729
717 expand 'end_foos'.
730 expand 'end_foos'.
718 '''
731 '''
719 if plural: names = plural
732 if plural: names = plural
720 else: names = name + 's'
733 else: names = name + 's'
721 if not values:
734 if not values:
722 noname = 'no_' + names
735 noname = 'no_' + names
723 if noname in self.t:
736 if noname in self.t:
724 yield self.t(noname, **args)
737 yield self.t(noname, **args)
725 return
738 return
726 if name not in self.t:
739 if name not in self.t:
727 if isinstance(values[0], str):
740 if isinstance(values[0], str):
728 yield ' '.join(values)
741 yield ' '.join(values)
729 else:
742 else:
730 for v in values:
743 for v in values:
731 yield dict(v, **args)
744 yield dict(v, **args)
732 return
745 return
733 startname = 'start_' + names
746 startname = 'start_' + names
734 if startname in self.t:
747 if startname in self.t:
735 yield self.t(startname, **args)
748 yield self.t(startname, **args)
736 vargs = args.copy()
749 vargs = args.copy()
737 def one(v, tag=name):
750 def one(v, tag=name):
738 try:
751 try:
739 vargs.update(v)
752 vargs.update(v)
740 except (AttributeError, ValueError):
753 except (AttributeError, ValueError):
741 try:
754 try:
742 for a, b in v:
755 for a, b in v:
743 vargs[a] = b
756 vargs[a] = b
744 except ValueError:
757 except ValueError:
745 vargs[name] = v
758 vargs[name] = v
746 return self.t(tag, **vargs)
759 return self.t(tag, **vargs)
747 lastname = 'last_' + name
760 lastname = 'last_' + name
748 if lastname in self.t:
761 if lastname in self.t:
749 last = values.pop()
762 last = values.pop()
750 else:
763 else:
751 last = None
764 last = None
752 for v in values:
765 for v in values:
753 yield one(v)
766 yield one(v)
754 if last is not None:
767 if last is not None:
755 yield one(last, tag=lastname)
768 yield one(last, tag=lastname)
756 endname = 'end_' + names
769 endname = 'end_' + names
757 if endname in self.t:
770 if endname in self.t:
758 yield self.t(endname, **args)
771 yield self.t(endname, **args)
759
772
760 def showbranches(**args):
773 def showbranches(**args):
761 branch = changes[5].get("branch")
774 branch = changes[5].get("branch")
762 if branch != 'default':
775 if branch != 'default':
763 branch = util.tolocal(branch)
776 branch = util.tolocal(branch)
764 return showlist('branch', [branch], plural='branches', **args)
777 return showlist('branch', [branch], plural='branches', **args)
765
778
766 def showparents(**args):
779 def showparents(**args):
767 parents = [[('rev', p), ('node', hex(log.node(p)))]
780 parents = [[('rev', p), ('node', hex(log.node(p)))]
768 for p in self._meaningful_parentrevs(log, rev)]
781 for p in self._meaningful_parentrevs(log, rev)]
769 return showlist('parent', parents, **args)
782 return showlist('parent', parents, **args)
770
783
771 def showtags(**args):
784 def showtags(**args):
772 return showlist('tag', self.repo.nodetags(changenode), **args)
785 return showlist('tag', self.repo.nodetags(changenode), **args)
773
786
774 def showextras(**args):
787 def showextras(**args):
775 extras = changes[5].items()
788 extras = changes[5].items()
776 extras.sort()
789 extras.sort()
777 for key, value in extras:
790 for key, value in extras:
778 args = args.copy()
791 args = args.copy()
779 args.update(dict(key=key, value=value))
792 args.update(dict(key=key, value=value))
780 yield self.t('extra', **args)
793 yield self.t('extra', **args)
781
794
782 def showcopies(**args):
795 def showcopies(**args):
783 c = [{'name': x[0], 'source': x[1]} for x in copies]
796 c = [{'name': x[0], 'source': x[1]} for x in copies]
784 return showlist('file_copy', c, plural='file_copies', **args)
797 return showlist('file_copy', c, plural='file_copies', **args)
785
798
786 files = []
799 files = []
787 def getfiles():
800 def getfiles():
788 if not files:
801 if not files:
789 files[:] = self.repo.status(
802 files[:] = self.repo.status(
790 log.parents(changenode)[0], changenode)[:3]
803 log.parents(changenode)[0], changenode)[:3]
791 return files
804 return files
792 def showfiles(**args):
805 def showfiles(**args):
793 return showlist('file', changes[3], **args)
806 return showlist('file', changes[3], **args)
794 def showmods(**args):
807 def showmods(**args):
795 return showlist('file_mod', getfiles()[0], **args)
808 return showlist('file_mod', getfiles()[0], **args)
796 def showadds(**args):
809 def showadds(**args):
797 return showlist('file_add', getfiles()[1], **args)
810 return showlist('file_add', getfiles()[1], **args)
798 def showdels(**args):
811 def showdels(**args):
799 return showlist('file_del', getfiles()[2], **args)
812 return showlist('file_del', getfiles()[2], **args)
800 def showmanifest(**args):
813 def showmanifest(**args):
801 args = args.copy()
814 args = args.copy()
802 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
815 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
803 node=hex(changes[0])))
816 node=hex(changes[0])))
804 return self.t('manifest', **args)
817 return self.t('manifest', **args)
805
818
806 defprops = {
819 defprops = {
807 'author': changes[1],
820 'author': changes[1],
808 'branches': showbranches,
821 'branches': showbranches,
809 'date': changes[2],
822 'date': changes[2],
810 'desc': changes[4].strip(),
823 'desc': changes[4].strip(),
811 'file_adds': showadds,
824 'file_adds': showadds,
812 'file_dels': showdels,
825 'file_dels': showdels,
813 'file_mods': showmods,
826 'file_mods': showmods,
814 'files': showfiles,
827 'files': showfiles,
815 'file_copies': showcopies,
828 'file_copies': showcopies,
816 'manifest': showmanifest,
829 'manifest': showmanifest,
817 'node': hex(changenode),
830 'node': hex(changenode),
818 'parents': showparents,
831 'parents': showparents,
819 'rev': rev,
832 'rev': rev,
820 'tags': showtags,
833 'tags': showtags,
821 'extras': showextras,
834 'extras': showextras,
822 }
835 }
823 props = props.copy()
836 props = props.copy()
824 props.update(defprops)
837 props.update(defprops)
825
838
826 try:
839 try:
827 if self.ui.debugflag and 'header_debug' in self.t:
840 if self.ui.debugflag and 'header_debug' in self.t:
828 key = 'header_debug'
841 key = 'header_debug'
829 elif self.ui.quiet and 'header_quiet' in self.t:
842 elif self.ui.quiet and 'header_quiet' in self.t:
830 key = 'header_quiet'
843 key = 'header_quiet'
831 elif self.ui.verbose and 'header_verbose' in self.t:
844 elif self.ui.verbose and 'header_verbose' in self.t:
832 key = 'header_verbose'
845 key = 'header_verbose'
833 elif 'header' in self.t:
846 elif 'header' in self.t:
834 key = 'header'
847 key = 'header'
835 else:
848 else:
836 key = ''
849 key = ''
837 if key:
850 if key:
838 h = templater.stringify(self.t(key, **props))
851 h = templater.stringify(self.t(key, **props))
839 if self.buffered:
852 if self.buffered:
840 self.header[rev] = h
853 self.header[rev] = h
841 else:
854 else:
842 self.ui.write(h)
855 self.ui.write(h)
843 if self.ui.debugflag and 'changeset_debug' in self.t:
856 if self.ui.debugflag and 'changeset_debug' in self.t:
844 key = 'changeset_debug'
857 key = 'changeset_debug'
845 elif self.ui.quiet and 'changeset_quiet' in self.t:
858 elif self.ui.quiet and 'changeset_quiet' in self.t:
846 key = 'changeset_quiet'
859 key = 'changeset_quiet'
847 elif self.ui.verbose and 'changeset_verbose' in self.t:
860 elif self.ui.verbose and 'changeset_verbose' in self.t:
848 key = 'changeset_verbose'
861 key = 'changeset_verbose'
849 else:
862 else:
850 key = 'changeset'
863 key = 'changeset'
851 self.ui.write(templater.stringify(self.t(key, **props)))
864 self.ui.write(templater.stringify(self.t(key, **props)))
852 self.showpatch(changenode)
865 self.showpatch(changenode)
853 except KeyError, inst:
866 except KeyError, inst:
854 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
867 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
855 inst.args[0]))
868 inst.args[0]))
856 except SyntaxError, inst:
869 except SyntaxError, inst:
857 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
870 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
858
871
859 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
872 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
860 """show one changeset using template or regular display.
873 """show one changeset using template or regular display.
861
874
862 Display format will be the first non-empty hit of:
875 Display format will be the first non-empty hit of:
863 1. option 'template'
876 1. option 'template'
864 2. option 'style'
877 2. option 'style'
865 3. [ui] setting 'logtemplate'
878 3. [ui] setting 'logtemplate'
866 4. [ui] setting 'style'
879 4. [ui] setting 'style'
867 If all of these values are either the unset or the empty string,
880 If all of these values are either the unset or the empty string,
868 regular display via changeset_printer() is done.
881 regular display via changeset_printer() is done.
869 """
882 """
870 # options
883 # options
871 patch = False
884 patch = False
872 if opts.get('patch'):
885 if opts.get('patch'):
873 patch = matchfn or util.always
886 patch = matchfn or util.always
874
887
875 tmpl = opts.get('template')
888 tmpl = opts.get('template')
876 mapfile = None
889 mapfile = None
877 if tmpl:
890 if tmpl:
878 tmpl = templater.parsestring(tmpl, quoted=False)
891 tmpl = templater.parsestring(tmpl, quoted=False)
879 else:
892 else:
880 mapfile = opts.get('style')
893 mapfile = opts.get('style')
881 # ui settings
894 # ui settings
882 if not mapfile:
895 if not mapfile:
883 tmpl = ui.config('ui', 'logtemplate')
896 tmpl = ui.config('ui', 'logtemplate')
884 if tmpl:
897 if tmpl:
885 tmpl = templater.parsestring(tmpl)
898 tmpl = templater.parsestring(tmpl)
886 else:
899 else:
887 mapfile = ui.config('ui', 'style')
900 mapfile = ui.config('ui', 'style')
888
901
889 if tmpl or mapfile:
902 if tmpl or mapfile:
890 if mapfile:
903 if mapfile:
891 if not os.path.split(mapfile)[0]:
904 if not os.path.split(mapfile)[0]:
892 mapname = (templater.templatepath('map-cmdline.' + mapfile)
905 mapname = (templater.templatepath('map-cmdline.' + mapfile)
893 or templater.templatepath(mapfile))
906 or templater.templatepath(mapfile))
894 if mapname: mapfile = mapname
907 if mapname: mapfile = mapname
895 try:
908 try:
896 t = changeset_templater(ui, repo, patch, mapfile, buffered)
909 t = changeset_templater(ui, repo, patch, mapfile, buffered)
897 except SyntaxError, inst:
910 except SyntaxError, inst:
898 raise util.Abort(inst.args[0])
911 raise util.Abort(inst.args[0])
899 if tmpl: t.use_template(tmpl)
912 if tmpl: t.use_template(tmpl)
900 return t
913 return t
901 return changeset_printer(ui, repo, patch, buffered)
914 return changeset_printer(ui, repo, patch, buffered)
902
915
903 def finddate(ui, repo, date):
916 def finddate(ui, repo, date):
904 """Find the tipmost changeset that matches the given date spec"""
917 """Find the tipmost changeset that matches the given date spec"""
905 df = util.matchdate(date)
918 df = util.matchdate(date)
906 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
919 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
907 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
920 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
908 results = {}
921 results = {}
909 for st, rev, fns in changeiter:
922 for st, rev, fns in changeiter:
910 if st == 'add':
923 if st == 'add':
911 d = get(rev)[2]
924 d = get(rev)[2]
912 if df(d[0]):
925 if df(d[0]):
913 results[rev] = d
926 results[rev] = d
914 elif st == 'iter':
927 elif st == 'iter':
915 if rev in results:
928 if rev in results:
916 ui.status("Found revision %s from %s\n" %
929 ui.status("Found revision %s from %s\n" %
917 (rev, util.datestr(results[rev])))
930 (rev, util.datestr(results[rev])))
918 return str(rev)
931 return str(rev)
919
932
920 raise util.Abort(_("revision matching date not found"))
933 raise util.Abort(_("revision matching date not found"))
921
934
922 def walkchangerevs(ui, repo, pats, change, opts):
935 def walkchangerevs(ui, repo, pats, change, opts):
923 '''Iterate over files and the revs they changed in.
936 '''Iterate over files and the revs they changed in.
924
937
925 Callers most commonly need to iterate backwards over the history
938 Callers most commonly need to iterate backwards over the history
926 it is interested in. Doing so has awful (quadratic-looking)
939 it is interested in. Doing so has awful (quadratic-looking)
927 performance, so we use iterators in a "windowed" way.
940 performance, so we use iterators in a "windowed" way.
928
941
929 We walk a window of revisions in the desired order. Within the
942 We walk a window of revisions in the desired order. Within the
930 window, we first walk forwards to gather data, then in the desired
943 window, we first walk forwards to gather data, then in the desired
931 order (usually backwards) to display it.
944 order (usually backwards) to display it.
932
945
933 This function returns an (iterator, matchfn) tuple. The iterator
946 This function returns an (iterator, matchfn) tuple. The iterator
934 yields 3-tuples. They will be of one of the following forms:
947 yields 3-tuples. They will be of one of the following forms:
935
948
936 "window", incrementing, lastrev: stepping through a window,
949 "window", incrementing, lastrev: stepping through a window,
937 positive if walking forwards through revs, last rev in the
950 positive if walking forwards through revs, last rev in the
938 sequence iterated over - use to reset state for the current window
951 sequence iterated over - use to reset state for the current window
939
952
940 "add", rev, fns: out-of-order traversal of the given file names
953 "add", rev, fns: out-of-order traversal of the given file names
941 fns, which changed during revision rev - use to gather data for
954 fns, which changed during revision rev - use to gather data for
942 possible display
955 possible display
943
956
944 "iter", rev, None: in-order traversal of the revs earlier iterated
957 "iter", rev, None: in-order traversal of the revs earlier iterated
945 over with "add" - use to display data'''
958 over with "add" - use to display data'''
946
959
947 def increasing_windows(start, end, windowsize=8, sizelimit=512):
960 def increasing_windows(start, end, windowsize=8, sizelimit=512):
948 if start < end:
961 if start < end:
949 while start < end:
962 while start < end:
950 yield start, min(windowsize, end-start)
963 yield start, min(windowsize, end-start)
951 start += windowsize
964 start += windowsize
952 if windowsize < sizelimit:
965 if windowsize < sizelimit:
953 windowsize *= 2
966 windowsize *= 2
954 else:
967 else:
955 while start > end:
968 while start > end:
956 yield start, min(windowsize, start-end-1)
969 yield start, min(windowsize, start-end-1)
957 start -= windowsize
970 start -= windowsize
958 if windowsize < sizelimit:
971 if windowsize < sizelimit:
959 windowsize *= 2
972 windowsize *= 2
960
973
961 files, matchfn, anypats = matchpats(repo, pats, opts)
974 files, matchfn, anypats = matchpats(repo, pats, opts)
962 follow = opts.get('follow') or opts.get('follow_first')
975 follow = opts.get('follow') or opts.get('follow_first')
963
976
964 if repo.changelog.count() == 0:
977 if repo.changelog.count() == 0:
965 return [], matchfn
978 return [], matchfn
966
979
967 if follow:
980 if follow:
968 defrange = '%s:0' % repo.changectx().rev()
981 defrange = '%s:0' % repo.changectx().rev()
969 else:
982 else:
970 defrange = '-1:0'
983 defrange = '-1:0'
971 revs = revrange(repo, opts['rev'] or [defrange])
984 revs = revrange(repo, opts['rev'] or [defrange])
972 wanted = {}
985 wanted = {}
973 slowpath = anypats or opts.get('removed')
986 slowpath = anypats or opts.get('removed')
974 fncache = {}
987 fncache = {}
975
988
976 if not slowpath and not files:
989 if not slowpath and not files:
977 # No files, no patterns. Display all revs.
990 # No files, no patterns. Display all revs.
978 wanted = dict.fromkeys(revs)
991 wanted = dict.fromkeys(revs)
979 copies = []
992 copies = []
980 if not slowpath:
993 if not slowpath:
981 # Only files, no patterns. Check the history of each file.
994 # Only files, no patterns. Check the history of each file.
982 def filerevgen(filelog, node):
995 def filerevgen(filelog, node):
983 cl_count = repo.changelog.count()
996 cl_count = repo.changelog.count()
984 if node is None:
997 if node is None:
985 last = filelog.count() - 1
998 last = filelog.count() - 1
986 else:
999 else:
987 last = filelog.rev(node)
1000 last = filelog.rev(node)
988 for i, window in increasing_windows(last, nullrev):
1001 for i, window in increasing_windows(last, nullrev):
989 revs = []
1002 revs = []
990 for j in xrange(i - window, i + 1):
1003 for j in xrange(i - window, i + 1):
991 n = filelog.node(j)
1004 n = filelog.node(j)
992 revs.append((filelog.linkrev(n),
1005 revs.append((filelog.linkrev(n),
993 follow and filelog.renamed(n)))
1006 follow and filelog.renamed(n)))
994 revs.reverse()
1007 revs.reverse()
995 for rev in revs:
1008 for rev in revs:
996 # only yield rev for which we have the changelog, it can
1009 # only yield rev for which we have the changelog, it can
997 # happen while doing "hg log" during a pull or commit
1010 # happen while doing "hg log" during a pull or commit
998 if rev[0] < cl_count:
1011 if rev[0] < cl_count:
999 yield rev
1012 yield rev
1000 def iterfiles():
1013 def iterfiles():
1001 for filename in files:
1014 for filename in files:
1002 yield filename, None
1015 yield filename, None
1003 for filename_node in copies:
1016 for filename_node in copies:
1004 yield filename_node
1017 yield filename_node
1005 minrev, maxrev = min(revs), max(revs)
1018 minrev, maxrev = min(revs), max(revs)
1006 for file_, node in iterfiles():
1019 for file_, node in iterfiles():
1007 filelog = repo.file(file_)
1020 filelog = repo.file(file_)
1008 # A zero count may be a directory or deleted file, so
1021 # A zero count may be a directory or deleted file, so
1009 # try to find matching entries on the slow path.
1022 # try to find matching entries on the slow path.
1010 if filelog.count() == 0:
1023 if filelog.count() == 0:
1011 slowpath = True
1024 slowpath = True
1012 break
1025 break
1013 for rev, copied in filerevgen(filelog, node):
1026 for rev, copied in filerevgen(filelog, node):
1014 if rev <= maxrev:
1027 if rev <= maxrev:
1015 if rev < minrev:
1028 if rev < minrev:
1016 break
1029 break
1017 fncache.setdefault(rev, [])
1030 fncache.setdefault(rev, [])
1018 fncache[rev].append(file_)
1031 fncache[rev].append(file_)
1019 wanted[rev] = 1
1032 wanted[rev] = 1
1020 if follow and copied:
1033 if follow and copied:
1021 copies.append(copied)
1034 copies.append(copied)
1022 if slowpath:
1035 if slowpath:
1023 if follow:
1036 if follow:
1024 raise util.Abort(_('can only follow copies/renames for explicit '
1037 raise util.Abort(_('can only follow copies/renames for explicit '
1025 'file names'))
1038 'file names'))
1026
1039
1027 # The slow path checks files modified in every changeset.
1040 # The slow path checks files modified in every changeset.
1028 def changerevgen():
1041 def changerevgen():
1029 for i, window in increasing_windows(repo.changelog.count()-1,
1042 for i, window in increasing_windows(repo.changelog.count()-1,
1030 nullrev):
1043 nullrev):
1031 for j in xrange(i - window, i + 1):
1044 for j in xrange(i - window, i + 1):
1032 yield j, change(j)[3]
1045 yield j, change(j)[3]
1033
1046
1034 for rev, changefiles in changerevgen():
1047 for rev, changefiles in changerevgen():
1035 matches = filter(matchfn, changefiles)
1048 matches = filter(matchfn, changefiles)
1036 if matches:
1049 if matches:
1037 fncache[rev] = matches
1050 fncache[rev] = matches
1038 wanted[rev] = 1
1051 wanted[rev] = 1
1039
1052
1040 class followfilter:
1053 class followfilter:
1041 def __init__(self, onlyfirst=False):
1054 def __init__(self, onlyfirst=False):
1042 self.startrev = nullrev
1055 self.startrev = nullrev
1043 self.roots = []
1056 self.roots = []
1044 self.onlyfirst = onlyfirst
1057 self.onlyfirst = onlyfirst
1045
1058
1046 def match(self, rev):
1059 def match(self, rev):
1047 def realparents(rev):
1060 def realparents(rev):
1048 if self.onlyfirst:
1061 if self.onlyfirst:
1049 return repo.changelog.parentrevs(rev)[0:1]
1062 return repo.changelog.parentrevs(rev)[0:1]
1050 else:
1063 else:
1051 return filter(lambda x: x != nullrev,
1064 return filter(lambda x: x != nullrev,
1052 repo.changelog.parentrevs(rev))
1065 repo.changelog.parentrevs(rev))
1053
1066
1054 if self.startrev == nullrev:
1067 if self.startrev == nullrev:
1055 self.startrev = rev
1068 self.startrev = rev
1056 return True
1069 return True
1057
1070
1058 if rev > self.startrev:
1071 if rev > self.startrev:
1059 # forward: all descendants
1072 # forward: all descendants
1060 if not self.roots:
1073 if not self.roots:
1061 self.roots.append(self.startrev)
1074 self.roots.append(self.startrev)
1062 for parent in realparents(rev):
1075 for parent in realparents(rev):
1063 if parent in self.roots:
1076 if parent in self.roots:
1064 self.roots.append(rev)
1077 self.roots.append(rev)
1065 return True
1078 return True
1066 else:
1079 else:
1067 # backwards: all parents
1080 # backwards: all parents
1068 if not self.roots:
1081 if not self.roots:
1069 self.roots.extend(realparents(self.startrev))
1082 self.roots.extend(realparents(self.startrev))
1070 if rev in self.roots:
1083 if rev in self.roots:
1071 self.roots.remove(rev)
1084 self.roots.remove(rev)
1072 self.roots.extend(realparents(rev))
1085 self.roots.extend(realparents(rev))
1073 return True
1086 return True
1074
1087
1075 return False
1088 return False
1076
1089
1077 # it might be worthwhile to do this in the iterator if the rev range
1090 # it might be worthwhile to do this in the iterator if the rev range
1078 # is descending and the prune args are all within that range
1091 # is descending and the prune args are all within that range
1079 for rev in opts.get('prune', ()):
1092 for rev in opts.get('prune', ()):
1080 rev = repo.changelog.rev(repo.lookup(rev))
1093 rev = repo.changelog.rev(repo.lookup(rev))
1081 ff = followfilter()
1094 ff = followfilter()
1082 stop = min(revs[0], revs[-1])
1095 stop = min(revs[0], revs[-1])
1083 for x in xrange(rev, stop-1, -1):
1096 for x in xrange(rev, stop-1, -1):
1084 if ff.match(x) and x in wanted:
1097 if ff.match(x) and x in wanted:
1085 del wanted[x]
1098 del wanted[x]
1086
1099
1087 def iterate():
1100 def iterate():
1088 if follow and not files:
1101 if follow and not files:
1089 ff = followfilter(onlyfirst=opts.get('follow_first'))
1102 ff = followfilter(onlyfirst=opts.get('follow_first'))
1090 def want(rev):
1103 def want(rev):
1091 if ff.match(rev) and rev in wanted:
1104 if ff.match(rev) and rev in wanted:
1092 return True
1105 return True
1093 return False
1106 return False
1094 else:
1107 else:
1095 def want(rev):
1108 def want(rev):
1096 return rev in wanted
1109 return rev in wanted
1097
1110
1098 for i, window in increasing_windows(0, len(revs)):
1111 for i, window in increasing_windows(0, len(revs)):
1099 yield 'window', revs[0] < revs[-1], revs[-1]
1112 yield 'window', revs[0] < revs[-1], revs[-1]
1100 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1113 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1101 srevs = list(nrevs)
1114 srevs = list(nrevs)
1102 srevs.sort()
1115 srevs.sort()
1103 for rev in srevs:
1116 for rev in srevs:
1104 fns = fncache.get(rev)
1117 fns = fncache.get(rev)
1105 if not fns:
1118 if not fns:
1106 def fns_generator():
1119 def fns_generator():
1107 for f in change(rev)[3]:
1120 for f in change(rev)[3]:
1108 if matchfn(f):
1121 if matchfn(f):
1109 yield f
1122 yield f
1110 fns = fns_generator()
1123 fns = fns_generator()
1111 yield 'add', rev, fns
1124 yield 'add', rev, fns
1112 for rev in nrevs:
1125 for rev in nrevs:
1113 yield 'iter', rev, None
1126 yield 'iter', rev, None
1114 return iterate(), matchfn
1127 return iterate(), matchfn
1115
1128
1116 def commit(ui, repo, commitfunc, pats, opts):
1129 def commit(ui, repo, commitfunc, pats, opts):
1117 '''commit the specified files or all outstanding changes'''
1130 '''commit the specified files or all outstanding changes'''
1118 date = opts.get('date')
1131 date = opts.get('date')
1119 if date:
1132 if date:
1120 opts['date'] = util.parsedate(date)
1133 opts['date'] = util.parsedate(date)
1121 message = logmessage(opts)
1134 message = logmessage(opts)
1122
1135
1123 # extract addremove carefully -- this function can be called from a command
1136 # extract addremove carefully -- this function can be called from a command
1124 # that doesn't support addremove
1137 # that doesn't support addremove
1125 if opts.get('addremove'):
1138 if opts.get('addremove'):
1126 addremove(repo, pats, opts)
1139 addremove(repo, pats, opts)
1127
1140
1128 fns, match, anypats = matchpats(repo, pats, opts)
1141 fns, match, anypats = matchpats(repo, pats, opts)
1129 if pats:
1142 if pats:
1130 status = repo.status(files=fns, match=match)
1143 status = repo.status(files=fns, match=match)
1131 modified, added, removed, deleted, unknown = status[:5]
1144 modified, added, removed, deleted, unknown = status[:5]
1132 files = modified + added + removed
1145 files = modified + added + removed
1133 slist = None
1146 slist = None
1134 for f in fns:
1147 for f in fns:
1135 if f == '.':
1148 if f == '.':
1136 continue
1149 continue
1137 if f not in files:
1150 if f not in files:
1138 rf = repo.wjoin(f)
1151 rf = repo.wjoin(f)
1139 rel = repo.pathto(f)
1152 rel = repo.pathto(f)
1140 try:
1153 try:
1141 mode = os.lstat(rf)[stat.ST_MODE]
1154 mode = os.lstat(rf)[stat.ST_MODE]
1142 except OSError:
1155 except OSError:
1143 raise util.Abort(_("file %s not found!") % rel)
1156 raise util.Abort(_("file %s not found!") % rel)
1144 if stat.S_ISDIR(mode):
1157 if stat.S_ISDIR(mode):
1145 name = f + '/'
1158 name = f + '/'
1146 if slist is None:
1159 if slist is None:
1147 slist = list(files)
1160 slist = list(files)
1148 slist.sort()
1161 slist.sort()
1149 i = bisect.bisect(slist, name)
1162 i = bisect.bisect(slist, name)
1150 if i >= len(slist) or not slist[i].startswith(name):
1163 if i >= len(slist) or not slist[i].startswith(name):
1151 raise util.Abort(_("no match under directory %s!")
1164 raise util.Abort(_("no match under directory %s!")
1152 % rel)
1165 % rel)
1153 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
1166 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
1154 raise util.Abort(_("can't commit %s: "
1167 raise util.Abort(_("can't commit %s: "
1155 "unsupported file type!") % rel)
1168 "unsupported file type!") % rel)
1156 elif f not in repo.dirstate:
1169 elif f not in repo.dirstate:
1157 raise util.Abort(_("file %s not tracked!") % rel)
1170 raise util.Abort(_("file %s not tracked!") % rel)
1158 else:
1171 else:
1159 files = []
1172 files = []
1160 try:
1173 try:
1161 return commitfunc(ui, repo, files, message, match, opts)
1174 return commitfunc(ui, repo, files, message, match, opts)
1162 except ValueError, inst:
1175 except ValueError, inst:
1163 raise util.Abort(str(inst))
1176 raise util.Abort(str(inst))
@@ -1,3169 +1,3162 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 *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, re, sys, urllib
10 import os, re, sys, urllib
11 import hg, util, revlog, bundlerepo, extensions
11 import hg, util, revlog, bundlerepo, extensions
12 import difflib, patch, time, help, mdiff, tempfile
12 import difflib, patch, time, help, mdiff, tempfile
13 import errno, version, socket
13 import errno, version, socket
14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15
15
16 # Commands start here, listed alphabetically
16 # Commands start here, listed alphabetically
17
17
18 def add(ui, repo, *pats, **opts):
18 def add(ui, repo, *pats, **opts):
19 """add the specified files on the next commit
19 """add the specified files on the next commit
20
20
21 Schedule files to be version controlled and added to the repository.
21 Schedule files to be version controlled and added to the repository.
22
22
23 The files will be added to the repository at the next commit. To
23 The files will be added to the repository at the next commit. To
24 undo an add before that, see hg revert.
24 undo an add before that, see hg revert.
25
25
26 If no names are given, add all files in the repository.
26 If no names are given, add all files in the repository.
27 """
27 """
28
28
29 rejected = None
29 rejected = None
30 exacts = {}
30 exacts = {}
31 names = []
31 names = []
32 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
32 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
33 badmatch=util.always):
33 badmatch=util.always):
34 if exact:
34 if exact:
35 if ui.verbose:
35 if ui.verbose:
36 ui.status(_('adding %s\n') % rel)
36 ui.status(_('adding %s\n') % rel)
37 names.append(abs)
37 names.append(abs)
38 exacts[abs] = 1
38 exacts[abs] = 1
39 elif abs not in repo.dirstate:
39 elif abs not in repo.dirstate:
40 ui.status(_('adding %s\n') % rel)
40 ui.status(_('adding %s\n') % rel)
41 names.append(abs)
41 names.append(abs)
42 if not opts.get('dry_run'):
42 if not opts.get('dry_run'):
43 rejected = repo.add(names)
43 rejected = repo.add(names)
44 rejected = [p for p in rejected if p in exacts]
44 rejected = [p for p in rejected if p in exacts]
45 return rejected and 1 or 0
45 return rejected and 1 or 0
46
46
47 def addremove(ui, repo, *pats, **opts):
47 def addremove(ui, repo, *pats, **opts):
48 """add all new files, delete all missing files
48 """add all new files, delete all missing files
49
49
50 Add all new files and remove all missing files from the repository.
50 Add all new files and remove all missing files from the repository.
51
51
52 New files are ignored if they match any of the patterns in .hgignore. As
52 New files are ignored if they match any of the patterns in .hgignore. As
53 with add, these changes take effect at the next commit.
53 with add, these changes take effect at the next commit.
54
54
55 Use the -s option to detect renamed files. With a parameter > 0,
55 Use the -s option to detect renamed files. With a parameter > 0,
56 this compares every removed file with every added file and records
56 this compares every removed file with every added file and records
57 those similar enough as renames. This option takes a percentage
57 those similar enough as renames. This option takes a percentage
58 between 0 (disabled) and 100 (files must be identical) as its
58 between 0 (disabled) and 100 (files must be identical) as its
59 parameter. Detecting renamed files this way can be expensive.
59 parameter. Detecting renamed files this way can be expensive.
60 """
60 """
61 try:
61 try:
62 sim = float(opts.get('similarity') or 0)
62 sim = float(opts.get('similarity') or 0)
63 except ValueError:
63 except ValueError:
64 raise util.Abort(_('similarity must be a number'))
64 raise util.Abort(_('similarity must be a number'))
65 if sim < 0 or sim > 100:
65 if sim < 0 or sim > 100:
66 raise util.Abort(_('similarity must be between 0 and 100'))
66 raise util.Abort(_('similarity must be between 0 and 100'))
67 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
67 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
68
68
69 def annotate(ui, repo, *pats, **opts):
69 def annotate(ui, repo, *pats, **opts):
70 """show changeset information per file line
70 """show changeset information per file line
71
71
72 List changes in files, showing the revision id responsible for each line
72 List changes in files, showing the revision id responsible for each line
73
73
74 This command is useful to discover who did a change or when a change took
74 This command is useful to discover who did a change or when a change took
75 place.
75 place.
76
76
77 Without the -a option, annotate will avoid processing files it
77 Without the -a option, annotate will avoid processing files it
78 detects as binary. With -a, annotate will generate an annotation
78 detects as binary. With -a, annotate will generate an annotation
79 anyway, probably with undesirable results.
79 anyway, probably with undesirable results.
80 """
80 """
81 datefunc = ui.quiet and util.shortdate or util.datestr
81 datefunc = ui.quiet and util.shortdate or util.datestr
82 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
82 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
83
83
84 if not pats:
84 if not pats:
85 raise util.Abort(_('at least one file name or pattern required'))
85 raise util.Abort(_('at least one file name or pattern required'))
86
86
87 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
87 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
88 ('number', lambda x: str(x[0].rev())),
88 ('number', lambda x: str(x[0].rev())),
89 ('changeset', lambda x: short(x[0].node())),
89 ('changeset', lambda x: short(x[0].node())),
90 ('date', getdate),
90 ('date', getdate),
91 ('follow', lambda x: x[0].path()),
91 ('follow', lambda x: x[0].path()),
92 ]
92 ]
93
93
94 if (not opts['user'] and not opts['changeset'] and not opts['date']
94 if (not opts['user'] and not opts['changeset'] and not opts['date']
95 and not opts['follow']):
95 and not opts['follow']):
96 opts['number'] = 1
96 opts['number'] = 1
97
97
98 linenumber = opts.get('line_number') is not None
98 linenumber = opts.get('line_number') is not None
99 if (linenumber and (not opts['changeset']) and (not opts['number'])):
99 if (linenumber and (not opts['changeset']) and (not opts['number'])):
100 raise util.Abort(_('at least one of -n/-c is required for -l'))
100 raise util.Abort(_('at least one of -n/-c is required for -l'))
101
101
102 funcmap = [func for op, func in opmap if opts.get(op)]
102 funcmap = [func for op, func in opmap if opts.get(op)]
103 if linenumber:
103 if linenumber:
104 lastfunc = funcmap[-1]
104 lastfunc = funcmap[-1]
105 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
105 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
106
106
107 ctx = repo.changectx(opts['rev'])
107 ctx = repo.changectx(opts['rev'])
108
108
109 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
109 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
110 node=ctx.node()):
110 node=ctx.node()):
111 fctx = ctx.filectx(abs)
111 fctx = ctx.filectx(abs)
112 if not opts['text'] and util.binary(fctx.data()):
112 if not opts['text'] and util.binary(fctx.data()):
113 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
113 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
114 continue
114 continue
115
115
116 lines = fctx.annotate(follow=opts.get('follow'),
116 lines = fctx.annotate(follow=opts.get('follow'),
117 linenumber=linenumber)
117 linenumber=linenumber)
118 pieces = []
118 pieces = []
119
119
120 for f in funcmap:
120 for f in funcmap:
121 l = [f(n) for n, dummy in lines]
121 l = [f(n) for n, dummy in lines]
122 if l:
122 if l:
123 m = max(map(len, l))
123 m = max(map(len, l))
124 pieces.append(["%*s" % (m, x) for x in l])
124 pieces.append(["%*s" % (m, x) for x in l])
125
125
126 if pieces:
126 if pieces:
127 for p, l in zip(zip(*pieces), lines):
127 for p, l in zip(zip(*pieces), lines):
128 ui.write("%s: %s" % (" ".join(p), l[1]))
128 ui.write("%s: %s" % (" ".join(p), l[1]))
129
129
130 def archive(ui, repo, dest, **opts):
130 def archive(ui, repo, dest, **opts):
131 '''create unversioned archive of a repository revision
131 '''create unversioned archive of a repository revision
132
132
133 By default, the revision used is the parent of the working
133 By default, the revision used is the parent of the working
134 directory; use "-r" to specify a different revision.
134 directory; use "-r" to specify a different revision.
135
135
136 To specify the type of archive to create, use "-t". Valid
136 To specify the type of archive to create, use "-t". Valid
137 types are:
137 types are:
138
138
139 "files" (default): a directory full of files
139 "files" (default): a directory full of files
140 "tar": tar archive, uncompressed
140 "tar": tar archive, uncompressed
141 "tbz2": tar archive, compressed using bzip2
141 "tbz2": tar archive, compressed using bzip2
142 "tgz": tar archive, compressed using gzip
142 "tgz": tar archive, compressed using gzip
143 "uzip": zip archive, uncompressed
143 "uzip": zip archive, uncompressed
144 "zip": zip archive, compressed using deflate
144 "zip": zip archive, compressed using deflate
145
145
146 The exact name of the destination archive or directory is given
146 The exact name of the destination archive or directory is given
147 using a format string; see "hg help export" for details.
147 using a format string; see "hg help export" for details.
148
148
149 Each member added to an archive file has a directory prefix
149 Each member added to an archive file has a directory prefix
150 prepended. Use "-p" to specify a format string for the prefix.
150 prepended. Use "-p" to specify a format string for the prefix.
151 The default is the basename of the archive, with suffixes removed.
151 The default is the basename of the archive, with suffixes removed.
152 '''
152 '''
153
153
154 ctx = repo.changectx(opts['rev'])
154 ctx = repo.changectx(opts['rev'])
155 if not ctx:
155 if not ctx:
156 raise util.Abort(_('repository has no revisions'))
156 raise util.Abort(_('repository has no revisions'))
157 node = ctx.node()
157 node = ctx.node()
158 dest = cmdutil.make_filename(repo, dest, node)
158 dest = cmdutil.make_filename(repo, dest, node)
159 if os.path.realpath(dest) == repo.root:
159 if os.path.realpath(dest) == repo.root:
160 raise util.Abort(_('repository root cannot be destination'))
160 raise util.Abort(_('repository root cannot be destination'))
161 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
161 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
162 kind = opts.get('type') or 'files'
162 kind = opts.get('type') or 'files'
163 prefix = opts['prefix']
163 prefix = opts['prefix']
164 if dest == '-':
164 if dest == '-':
165 if kind == 'files':
165 if kind == 'files':
166 raise util.Abort(_('cannot archive plain files to stdout'))
166 raise util.Abort(_('cannot archive plain files to stdout'))
167 dest = sys.stdout
167 dest = sys.stdout
168 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
168 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
169 prefix = cmdutil.make_filename(repo, prefix, node)
169 prefix = cmdutil.make_filename(repo, prefix, node)
170 archival.archive(repo, dest, node, kind, not opts['no_decode'],
170 archival.archive(repo, dest, node, kind, not opts['no_decode'],
171 matchfn, prefix)
171 matchfn, prefix)
172
172
173 def backout(ui, repo, node=None, rev=None, **opts):
173 def backout(ui, repo, node=None, rev=None, **opts):
174 '''reverse effect of earlier changeset
174 '''reverse effect of earlier changeset
175
175
176 Commit the backed out changes as a new changeset. The new
176 Commit the backed out changes as a new changeset. The new
177 changeset is a child of the backed out changeset.
177 changeset is a child of the backed out changeset.
178
178
179 If you back out a changeset other than the tip, a new head is
179 If you back out a changeset other than the tip, a new head is
180 created. This head will be the new tip and you should merge this
180 created. This head will be the new tip and you should merge this
181 backout changeset with another head (current one by default).
181 backout changeset with another head (current one by default).
182
182
183 The --merge option remembers the parent of the working directory
183 The --merge option remembers the parent of the working directory
184 before starting the backout, then merges the new head with that
184 before starting the backout, then merges the new head with that
185 changeset afterwards. This saves you from doing the merge by
185 changeset afterwards. This saves you from doing the merge by
186 hand. The result of this merge is not committed, as for a normal
186 hand. The result of this merge is not committed, as for a normal
187 merge.
187 merge.
188
188
189 See 'hg help dates' for a list of formats valid for -d/--date.
189 See 'hg help dates' for a list of formats valid for -d/--date.
190 '''
190 '''
191 if rev and node:
191 if rev and node:
192 raise util.Abort(_("please specify just one revision"))
192 raise util.Abort(_("please specify just one revision"))
193
193
194 if not rev:
194 if not rev:
195 rev = node
195 rev = node
196
196
197 if not rev:
197 if not rev:
198 raise util.Abort(_("please specify a revision to backout"))
198 raise util.Abort(_("please specify a revision to backout"))
199
199
200 date = opts.get('date')
200 date = opts.get('date')
201 if date:
201 if date:
202 opts['date'] = util.parsedate(date)
202 opts['date'] = util.parsedate(date)
203
203
204 cmdutil.bail_if_changed(repo)
204 cmdutil.bail_if_changed(repo)
205 node = repo.lookup(rev)
205 node = repo.lookup(rev)
206
206
207 op1, op2 = repo.dirstate.parents()
207 op1, op2 = repo.dirstate.parents()
208 a = repo.changelog.ancestor(op1, node)
208 a = repo.changelog.ancestor(op1, node)
209 if a != node:
209 if a != node:
210 raise util.Abort(_('cannot back out change on a different branch'))
210 raise util.Abort(_('cannot back out change on a different branch'))
211
211
212 p1, p2 = repo.changelog.parents(node)
212 p1, p2 = repo.changelog.parents(node)
213 if p1 == nullid:
213 if p1 == nullid:
214 raise util.Abort(_('cannot back out a change with no parents'))
214 raise util.Abort(_('cannot back out a change with no parents'))
215 if p2 != nullid:
215 if p2 != nullid:
216 if not opts['parent']:
216 if not opts['parent']:
217 raise util.Abort(_('cannot back out a merge changeset without '
217 raise util.Abort(_('cannot back out a merge changeset without '
218 '--parent'))
218 '--parent'))
219 p = repo.lookup(opts['parent'])
219 p = repo.lookup(opts['parent'])
220 if p not in (p1, p2):
220 if p not in (p1, p2):
221 raise util.Abort(_('%s is not a parent of %s') %
221 raise util.Abort(_('%s is not a parent of %s') %
222 (short(p), short(node)))
222 (short(p), short(node)))
223 parent = p
223 parent = p
224 else:
224 else:
225 if opts['parent']:
225 if opts['parent']:
226 raise util.Abort(_('cannot use --parent on non-merge changeset'))
226 raise util.Abort(_('cannot use --parent on non-merge changeset'))
227 parent = p1
227 parent = p1
228
228
229 hg.clean(repo, node, show_stats=False)
229 hg.clean(repo, node, show_stats=False)
230 revert_opts = opts.copy()
230 revert_opts = opts.copy()
231 revert_opts['date'] = None
231 revert_opts['date'] = None
232 revert_opts['all'] = True
232 revert_opts['all'] = True
233 revert_opts['rev'] = hex(parent)
233 revert_opts['rev'] = hex(parent)
234 revert_opts['no_backup'] = None
234 revert_opts['no_backup'] = None
235 revert(ui, repo, **revert_opts)
235 revert(ui, repo, **revert_opts)
236 commit_opts = opts.copy()
236 commit_opts = opts.copy()
237 commit_opts['addremove'] = False
237 commit_opts['addremove'] = False
238 if not commit_opts['message'] and not commit_opts['logfile']:
238 if not commit_opts['message'] and not commit_opts['logfile']:
239 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
239 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
240 commit_opts['force_editor'] = True
240 commit_opts['force_editor'] = True
241 commit(ui, repo, **commit_opts)
241 commit(ui, repo, **commit_opts)
242 def nice(node):
242 def nice(node):
243 return '%d:%s' % (repo.changelog.rev(node), short(node))
243 return '%d:%s' % (repo.changelog.rev(node), short(node))
244 ui.status(_('changeset %s backs out changeset %s\n') %
244 ui.status(_('changeset %s backs out changeset %s\n') %
245 (nice(repo.changelog.tip()), nice(node)))
245 (nice(repo.changelog.tip()), nice(node)))
246 if op1 != node:
246 if op1 != node:
247 hg.clean(repo, op1, show_stats=False)
247 hg.clean(repo, op1, show_stats=False)
248 if opts['merge']:
248 if opts['merge']:
249 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
249 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
250 hg.merge(repo, hex(repo.changelog.tip()))
250 hg.merge(repo, hex(repo.changelog.tip()))
251 else:
251 else:
252 ui.status(_('the backout changeset is a new head - '
252 ui.status(_('the backout changeset is a new head - '
253 'do not forget to merge\n'))
253 'do not forget to merge\n'))
254 ui.status(_('(use "backout --merge" '
254 ui.status(_('(use "backout --merge" '
255 'if you want to auto-merge)\n'))
255 'if you want to auto-merge)\n'))
256
256
257 def bisect(ui, repo, rev=None, extra=None,
257 def bisect(ui, repo, rev=None, extra=None,
258 reset=None, good=None, bad=None, skip=None, noupdate=None):
258 reset=None, good=None, bad=None, skip=None, noupdate=None):
259 """subdivision search of changesets
259 """subdivision search of changesets
260
260
261 This command helps to find changesets which introduce problems.
261 This command helps to find changesets which introduce problems.
262 To use, mark the earliest changeset you know exhibits the problem
262 To use, mark the earliest changeset you know exhibits the problem
263 as bad, then mark the latest changeset which is free from the
263 as bad, then mark the latest changeset which is free from the
264 problem as good. Bisect will update your working directory to a
264 problem as good. Bisect will update your working directory to a
265 revision for testing. Once you have performed tests, mark the
265 revision for testing. Once you have performed tests, mark the
266 working directory as bad or good and bisect will either update to
266 working directory as bad or good and bisect will either update to
267 another candidate changeset or announce that it has found the bad
267 another candidate changeset or announce that it has found the bad
268 revision.
268 revision.
269 """
269 """
270 # backward compatibility
270 # backward compatibility
271 if rev in "good bad reset init".split():
271 if rev in "good bad reset init".split():
272 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
272 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
273 cmd, rev, extra = rev, extra, None
273 cmd, rev, extra = rev, extra, None
274 if cmd == "good":
274 if cmd == "good":
275 good = True
275 good = True
276 elif cmd == "bad":
276 elif cmd == "bad":
277 bad = True
277 bad = True
278 else:
278 else:
279 reset = True
279 reset = True
280 elif extra or good + bad + skip + reset > 1:
280 elif extra or good + bad + skip + reset > 1:
281 raise util.Abort("Incompatible arguments")
281 raise util.Abort("Incompatible arguments")
282
282
283 if reset:
283 if reset:
284 p = repo.join("bisect.state")
284 p = repo.join("bisect.state")
285 if os.path.exists(p):
285 if os.path.exists(p):
286 os.unlink(p)
286 os.unlink(p)
287 return
287 return
288
288
289 # load state
289 # load state
290 state = {'good': [], 'bad': [], 'skip': []}
290 state = {'good': [], 'bad': [], 'skip': []}
291 if os.path.exists(repo.join("bisect.state")):
291 if os.path.exists(repo.join("bisect.state")):
292 for l in repo.opener("bisect.state"):
292 for l in repo.opener("bisect.state"):
293 kind, node = l[:-1].split()
293 kind, node = l[:-1].split()
294 node = repo.lookup(node)
294 node = repo.lookup(node)
295 if kind not in state:
295 if kind not in state:
296 raise util.Abort(_("unknown bisect kind %s") % kind)
296 raise util.Abort(_("unknown bisect kind %s") % kind)
297 state[kind].append(node)
297 state[kind].append(node)
298
298
299 # update state
299 # update state
300 node = repo.lookup(rev or '.')
300 node = repo.lookup(rev or '.')
301 if good:
301 if good:
302 state['good'].append(node)
302 state['good'].append(node)
303 elif bad:
303 elif bad:
304 state['bad'].append(node)
304 state['bad'].append(node)
305 elif skip:
305 elif skip:
306 state['skip'].append(node)
306 state['skip'].append(node)
307
307
308 # save state
308 # save state
309 f = repo.opener("bisect.state", "w", atomictemp=True)
309 f = repo.opener("bisect.state", "w", atomictemp=True)
310 wlock = repo.wlock()
310 wlock = repo.wlock()
311 try:
311 try:
312 for kind in state:
312 for kind in state:
313 for node in state[kind]:
313 for node in state[kind]:
314 f.write("%s %s\n" % (kind, hg.hex(node)))
314 f.write("%s %s\n" % (kind, hg.hex(node)))
315 f.rename()
315 f.rename()
316 finally:
316 finally:
317 del wlock
317 del wlock
318
318
319 if not state['good'] or not state['bad']:
319 if not state['good'] or not state['bad']:
320 return
320 return
321
321
322 # actually bisect
322 # actually bisect
323 node, changesets, good = hbisect.bisect(repo.changelog, state)
323 node, changesets, good = hbisect.bisect(repo.changelog, state)
324 if changesets == 0:
324 if changesets == 0:
325 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
325 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
326 displayer = cmdutil.show_changeset(ui, repo, {})
326 displayer = cmdutil.show_changeset(ui, repo, {})
327 displayer.show(changenode=node)
327 displayer.show(changenode=node)
328 elif node is not None:
328 elif node is not None:
329 # compute the approximate number of remaining tests
329 # compute the approximate number of remaining tests
330 tests, size = 0, 2
330 tests, size = 0, 2
331 while size <= changesets:
331 while size <= changesets:
332 tests, size = tests + 1, size * 2
332 tests, size = tests + 1, size * 2
333 rev = repo.changelog.rev(node)
333 rev = repo.changelog.rev(node)
334 ui.write(_("Testing changeset %s:%s "
334 ui.write(_("Testing changeset %s:%s "
335 "(%s changesets remaining, ~%s tests)\n")
335 "(%s changesets remaining, ~%s tests)\n")
336 % (rev, hg.short(node), changesets, tests))
336 % (rev, hg.short(node), changesets, tests))
337 if not noupdate:
337 if not noupdate:
338 cmdutil.bail_if_changed(repo)
338 cmdutil.bail_if_changed(repo)
339 return hg.clean(repo, node)
339 return hg.clean(repo, node)
340
340
341 def branch(ui, repo, label=None, **opts):
341 def branch(ui, repo, label=None, **opts):
342 """set or show the current branch name
342 """set or show the current branch name
343
343
344 With no argument, show the current branch name. With one argument,
344 With no argument, show the current branch name. With one argument,
345 set the working directory branch name (the branch does not exist in
345 set the working directory branch name (the branch does not exist in
346 the repository until the next commit).
346 the repository until the next commit).
347
347
348 Unless --force is specified, branch will not let you set a
348 Unless --force is specified, branch will not let you set a
349 branch name that shadows an existing branch.
349 branch name that shadows an existing branch.
350
350
351 Use the command 'hg update' to switch to an existing branch.
351 Use the command 'hg update' to switch to an existing branch.
352 """
352 """
353
353
354 if label:
354 if label:
355 if not opts.get('force') and label in repo.branchtags():
355 if not opts.get('force') and label in repo.branchtags():
356 if label not in [p.branch() for p in repo.workingctx().parents()]:
356 if label not in [p.branch() for p in repo.workingctx().parents()]:
357 raise util.Abort(_('a branch of the same name already exists'
357 raise util.Abort(_('a branch of the same name already exists'
358 ' (use --force to override)'))
358 ' (use --force to override)'))
359 repo.dirstate.setbranch(util.fromlocal(label))
359 repo.dirstate.setbranch(util.fromlocal(label))
360 ui.status(_('marked working directory as branch %s\n') % label)
360 ui.status(_('marked working directory as branch %s\n') % label)
361 else:
361 else:
362 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
362 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
363
363
364 def branches(ui, repo, active=False):
364 def branches(ui, repo, active=False):
365 """list repository named branches
365 """list repository named branches
366
366
367 List the repository's named branches, indicating which ones are
367 List the repository's named branches, indicating which ones are
368 inactive. If active is specified, only show active branches.
368 inactive. If active is specified, only show active branches.
369
369
370 A branch is considered active if it contains unmerged heads.
370 A branch is considered active if it contains unmerged heads.
371
371
372 Use the command 'hg update' to switch to an existing branch.
372 Use the command 'hg update' to switch to an existing branch.
373 """
373 """
374 b = repo.branchtags()
374 b = repo.branchtags()
375 heads = dict.fromkeys(repo.heads(), 1)
375 heads = dict.fromkeys(repo.heads(), 1)
376 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
376 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
377 l.sort()
377 l.sort()
378 l.reverse()
378 l.reverse()
379 for ishead, r, n, t in l:
379 for ishead, r, n, t in l:
380 if active and not ishead:
380 if active and not ishead:
381 # If we're only displaying active branches, abort the loop on
381 # If we're only displaying active branches, abort the loop on
382 # encountering the first inactive head
382 # encountering the first inactive head
383 break
383 break
384 else:
384 else:
385 hexfunc = ui.debugflag and hex or short
385 hexfunc = ui.debugflag and hex or short
386 if ui.quiet:
386 if ui.quiet:
387 ui.write("%s\n" % t)
387 ui.write("%s\n" % t)
388 else:
388 else:
389 spaces = " " * (30 - util.locallen(t))
389 spaces = " " * (30 - util.locallen(t))
390 # The code only gets here if inactive branches are being
390 # The code only gets here if inactive branches are being
391 # displayed or the branch is active.
391 # displayed or the branch is active.
392 isinactive = ((not ishead) and " (inactive)") or ''
392 isinactive = ((not ishead) and " (inactive)") or ''
393 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
393 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
394
394
395 def bundle(ui, repo, fname, dest=None, **opts):
395 def bundle(ui, repo, fname, dest=None, **opts):
396 """create a changegroup file
396 """create a changegroup file
397
397
398 Generate a compressed changegroup file collecting changesets not
398 Generate a compressed changegroup file collecting changesets not
399 found in the other repository.
399 found in the other repository.
400
400
401 If no destination repository is specified the destination is
401 If no destination repository is specified the destination is
402 assumed to have all the nodes specified by one or more --base
402 assumed to have all the nodes specified by one or more --base
403 parameters. To create a bundle containing all changesets, use
403 parameters. To create a bundle containing all changesets, use
404 --all (or --base null).
404 --all (or --base null).
405
405
406 The bundle file can then be transferred using conventional means and
406 The bundle file can then be transferred using conventional means and
407 applied to another repository with the unbundle or pull command.
407 applied to another repository with the unbundle or pull command.
408 This is useful when direct push and pull are not available or when
408 This is useful when direct push and pull are not available or when
409 exporting an entire repository is undesirable.
409 exporting an entire repository is undesirable.
410
410
411 Applying bundles preserves all changeset contents including
411 Applying bundles preserves all changeset contents including
412 permissions, copy/rename information, and revision history.
412 permissions, copy/rename information, and revision history.
413 """
413 """
414 revs = opts.get('rev') or None
414 revs = opts.get('rev') or None
415 if revs:
415 if revs:
416 revs = [repo.lookup(rev) for rev in revs]
416 revs = [repo.lookup(rev) for rev in revs]
417 if opts.get('all'):
417 if opts.get('all'):
418 base = ['null']
418 base = ['null']
419 else:
419 else:
420 base = opts.get('base')
420 base = opts.get('base')
421 if base:
421 if base:
422 if dest:
422 if dest:
423 raise util.Abort(_("--base is incompatible with specifiying "
423 raise util.Abort(_("--base is incompatible with specifiying "
424 "a destination"))
424 "a destination"))
425 base = [repo.lookup(rev) for rev in base]
425 base = [repo.lookup(rev) for rev in base]
426 # create the right base
426 # create the right base
427 # XXX: nodesbetween / changegroup* should be "fixed" instead
427 # XXX: nodesbetween / changegroup* should be "fixed" instead
428 o = []
428 o = []
429 has = {nullid: None}
429 has = {nullid: None}
430 for n in base:
430 for n in base:
431 has.update(repo.changelog.reachable(n))
431 has.update(repo.changelog.reachable(n))
432 if revs:
432 if revs:
433 visit = list(revs)
433 visit = list(revs)
434 else:
434 else:
435 visit = repo.changelog.heads()
435 visit = repo.changelog.heads()
436 seen = {}
436 seen = {}
437 while visit:
437 while visit:
438 n = visit.pop(0)
438 n = visit.pop(0)
439 parents = [p for p in repo.changelog.parents(n) if p not in has]
439 parents = [p for p in repo.changelog.parents(n) if p not in has]
440 if len(parents) == 0:
440 if len(parents) == 0:
441 o.insert(0, n)
441 o.insert(0, n)
442 else:
442 else:
443 for p in parents:
443 for p in parents:
444 if p not in seen:
444 if p not in seen:
445 seen[p] = 1
445 seen[p] = 1
446 visit.append(p)
446 visit.append(p)
447 else:
447 else:
448 cmdutil.setremoteconfig(ui, opts)
448 cmdutil.setremoteconfig(ui, opts)
449 dest, revs, checkout = hg.parseurl(
449 dest, revs, checkout = hg.parseurl(
450 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
450 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
451 other = hg.repository(ui, dest)
451 other = hg.repository(ui, dest)
452 o = repo.findoutgoing(other, force=opts['force'])
452 o = repo.findoutgoing(other, force=opts['force'])
453
453
454 if revs:
454 if revs:
455 cg = repo.changegroupsubset(o, revs, 'bundle')
455 cg = repo.changegroupsubset(o, revs, 'bundle')
456 else:
456 else:
457 cg = repo.changegroup(o, 'bundle')
457 cg = repo.changegroup(o, 'bundle')
458 changegroup.writebundle(cg, fname, "HG10BZ")
458 changegroup.writebundle(cg, fname, "HG10BZ")
459
459
460 def cat(ui, repo, file1, *pats, **opts):
460 def cat(ui, repo, file1, *pats, **opts):
461 """output the current or given revision of files
461 """output the current or given revision of files
462
462
463 Print the specified files as they were at the given revision.
463 Print the specified files as they were at the given revision.
464 If no revision is given, the parent of the working directory is used,
464 If no revision is given, the parent of the working directory is used,
465 or tip if no revision is checked out.
465 or tip if no revision is checked out.
466
466
467 Output may be to a file, in which case the name of the file is
467 Output may be to a file, in which case the name of the file is
468 given using a format string. The formatting rules are the same as
468 given using a format string. The formatting rules are the same as
469 for the export command, with the following additions:
469 for the export command, with the following additions:
470
470
471 %s basename of file being printed
471 %s basename of file being printed
472 %d dirname of file being printed, or '.' if in repo root
472 %d dirname of file being printed, or '.' if in repo root
473 %p root-relative path name of file being printed
473 %p root-relative path name of file being printed
474 """
474 """
475 ctx = repo.changectx(opts['rev'])
475 ctx = repo.changectx(opts['rev'])
476 err = 1
476 err = 1
477 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
477 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
478 ctx.node()):
478 ctx.node()):
479 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
479 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
480 data = ctx.filectx(abs).data()
480 data = ctx.filectx(abs).data()
481 if opts.get('decode'):
481 if opts.get('decode'):
482 data = repo.wwritedata(abs, data)
482 data = repo.wwritedata(abs, data)
483 fp.write(data)
483 fp.write(data)
484 err = 0
484 err = 0
485 return err
485 return err
486
486
487 def clone(ui, source, dest=None, **opts):
487 def clone(ui, source, dest=None, **opts):
488 """make a copy of an existing repository
488 """make a copy of an existing repository
489
489
490 Create a copy of an existing repository in a new directory.
490 Create a copy of an existing repository in a new directory.
491
491
492 If no destination directory name is specified, it defaults to the
492 If no destination directory name is specified, it defaults to the
493 basename of the source.
493 basename of the source.
494
494
495 The location of the source is added to the new repository's
495 The location of the source is added to the new repository's
496 .hg/hgrc file, as the default to be used for future pulls.
496 .hg/hgrc file, as the default to be used for future pulls.
497
497
498 For efficiency, hardlinks are used for cloning whenever the source
498 For efficiency, hardlinks are used for cloning whenever the source
499 and destination are on the same filesystem (note this applies only
499 and destination are on the same filesystem (note this applies only
500 to the repository data, not to the checked out files). Some
500 to the repository data, not to the checked out files). Some
501 filesystems, such as AFS, implement hardlinking incorrectly, but
501 filesystems, such as AFS, implement hardlinking incorrectly, but
502 do not report errors. In these cases, use the --pull option to
502 do not report errors. In these cases, use the --pull option to
503 avoid hardlinking.
503 avoid hardlinking.
504
504
505 You can safely clone repositories and checked out files using full
505 You can safely clone repositories and checked out files using full
506 hardlinks with
506 hardlinks with
507
507
508 $ cp -al REPO REPOCLONE
508 $ cp -al REPO REPOCLONE
509
509
510 which is the fastest way to clone. However, the operation is not
510 which is the fastest way to clone. However, the operation is not
511 atomic (making sure REPO is not modified during the operation is
511 atomic (making sure REPO is not modified during the operation is
512 up to you) and you have to make sure your editor breaks hardlinks
512 up to you) and you have to make sure your editor breaks hardlinks
513 (Emacs and most Linux Kernel tools do so).
513 (Emacs and most Linux Kernel tools do so).
514
514
515 If you use the -r option to clone up to a specific revision, no
515 If you use the -r option to clone up to a specific revision, no
516 subsequent revisions will be present in the cloned repository.
516 subsequent revisions will be present in the cloned repository.
517 This option implies --pull, even on local repositories.
517 This option implies --pull, even on local repositories.
518
518
519 See pull for valid source format details.
519 See pull for valid source format details.
520
520
521 It is possible to specify an ssh:// URL as the destination, but no
521 It is possible to specify an ssh:// URL as the destination, but no
522 .hg/hgrc and working directory will be created on the remote side.
522 .hg/hgrc and working directory will be created on the remote side.
523 Look at the help text for the pull command for important details
523 Look at the help text for the pull command for important details
524 about ssh:// URLs.
524 about ssh:// URLs.
525 """
525 """
526 cmdutil.setremoteconfig(ui, opts)
526 cmdutil.setremoteconfig(ui, opts)
527 hg.clone(ui, source, dest,
527 hg.clone(ui, source, dest,
528 pull=opts['pull'],
528 pull=opts['pull'],
529 stream=opts['uncompressed'],
529 stream=opts['uncompressed'],
530 rev=opts['rev'],
530 rev=opts['rev'],
531 update=not opts['noupdate'])
531 update=not opts['noupdate'])
532
532
533 def commit(ui, repo, *pats, **opts):
533 def commit(ui, repo, *pats, **opts):
534 """commit the specified files or all outstanding changes
534 """commit the specified files or all outstanding changes
535
535
536 Commit changes to the given files into the repository.
536 Commit changes to the given files into the repository.
537
537
538 If a list of files is omitted, all changes reported by "hg status"
538 If a list of files is omitted, all changes reported by "hg status"
539 will be committed.
539 will be committed.
540
540
541 If no commit message is specified, the configured editor is started to
541 If no commit message is specified, the configured editor is started to
542 enter a message.
542 enter a message.
543
543
544 See 'hg help dates' for a list of formats valid for -d/--date.
544 See 'hg help dates' for a list of formats valid for -d/--date.
545 """
545 """
546 def commitfunc(ui, repo, files, message, match, opts):
546 def commitfunc(ui, repo, files, message, match, opts):
547 return repo.commit(files, message, opts['user'], opts['date'], match,
547 return repo.commit(files, message, opts['user'], opts['date'], match,
548 force_editor=opts.get('force_editor'))
548 force_editor=opts.get('force_editor'))
549 cmdutil.commit(ui, repo, commitfunc, pats, opts)
549 cmdutil.commit(ui, repo, commitfunc, pats, opts)
550
550
551 def copy(ui, repo, *pats, **opts):
551 def copy(ui, repo, *pats, **opts):
552 """mark files as copied for the next commit
552 """mark files as copied for the next commit
553
553
554 Mark dest as having copies of source files. If dest is a
554 Mark dest as having copies of source files. If dest is a
555 directory, copies are put in that directory. If dest is a file,
555 directory, copies are put in that directory. If dest is a file,
556 there can only be one source.
556 there can only be one source.
557
557
558 By default, this command copies the contents of files as they
558 By default, this command copies the contents of files as they
559 stand in the working directory. If invoked with --after, the
559 stand in the working directory. If invoked with --after, the
560 operation is recorded, but no copying is performed.
560 operation is recorded, but no copying is performed.
561
561
562 This command takes effect in the next commit. To undo a copy
562 This command takes effect in the next commit. To undo a copy
563 before that, see hg revert.
563 before that, see hg revert.
564 """
564 """
565 wlock = repo.wlock(False)
565 wlock = repo.wlock(False)
566 try:
566 try:
567 return cmdutil.copy(ui, repo, pats, opts)
567 return cmdutil.copy(ui, repo, pats, opts)
568 finally:
568 finally:
569 del wlock
569 del wlock
570
570
571 def debugancestor(ui, repo, *args):
571 def debugancestor(ui, repo, *args):
572 """find the ancestor revision of two revisions in a given index"""
572 """find the ancestor revision of two revisions in a given index"""
573 if len(args) == 3:
573 if len(args) == 3:
574 index, rev1, rev2 = args
574 index, rev1, rev2 = args
575 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
575 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
576 elif len(args) == 2:
576 elif len(args) == 2:
577 if not repo:
577 if not repo:
578 raise util.Abort(_("There is no Mercurial repository here "
578 raise util.Abort(_("There is no Mercurial repository here "
579 "(.hg not found)"))
579 "(.hg not found)"))
580 rev1, rev2 = args
580 rev1, rev2 = args
581 r = repo.changelog
581 r = repo.changelog
582 else:
582 else:
583 raise util.Abort(_('either two or three arguments required'))
583 raise util.Abort(_('either two or three arguments required'))
584 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
584 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
585 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
585 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
586
586
587 def debugcomplete(ui, cmd='', **opts):
587 def debugcomplete(ui, cmd='', **opts):
588 """returns the completion list associated with the given command"""
588 """returns the completion list associated with the given command"""
589
589
590 if opts['options']:
590 if opts['options']:
591 options = []
591 options = []
592 otables = [globalopts]
592 otables = [globalopts]
593 if cmd:
593 if cmd:
594 aliases, entry = cmdutil.findcmd(ui, cmd, table)
594 aliases, entry = cmdutil.findcmd(ui, cmd, table)
595 otables.append(entry[1])
595 otables.append(entry[1])
596 for t in otables:
596 for t in otables:
597 for o in t:
597 for o in t:
598 if o[0]:
598 if o[0]:
599 options.append('-%s' % o[0])
599 options.append('-%s' % o[0])
600 options.append('--%s' % o[1])
600 options.append('--%s' % o[1])
601 ui.write("%s\n" % "\n".join(options))
601 ui.write("%s\n" % "\n".join(options))
602 return
602 return
603
603
604 clist = cmdutil.findpossible(ui, cmd, table).keys()
604 clist = cmdutil.findpossible(ui, cmd, table).keys()
605 clist.sort()
605 clist.sort()
606 ui.write("%s\n" % "\n".join(clist))
606 ui.write("%s\n" % "\n".join(clist))
607
607
608 def debugfsinfo(ui, path = "."):
608 def debugfsinfo(ui, path = "."):
609 file('.debugfsinfo', 'w').write('')
609 file('.debugfsinfo', 'w').write('')
610 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
610 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
611 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
611 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
612 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
612 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
613 and 'yes' or 'no'))
613 and 'yes' or 'no'))
614 os.unlink('.debugfsinfo')
614 os.unlink('.debugfsinfo')
615
615
616 def debugrebuildstate(ui, repo, rev=""):
616 def debugrebuildstate(ui, repo, rev=""):
617 """rebuild the dirstate as it would look like for the given revision"""
617 """rebuild the dirstate as it would look like for the given revision"""
618 if rev == "":
618 if rev == "":
619 rev = repo.changelog.tip()
619 rev = repo.changelog.tip()
620 ctx = repo.changectx(rev)
620 ctx = repo.changectx(rev)
621 files = ctx.manifest()
621 files = ctx.manifest()
622 wlock = repo.wlock()
622 wlock = repo.wlock()
623 try:
623 try:
624 repo.dirstate.rebuild(rev, files)
624 repo.dirstate.rebuild(rev, files)
625 finally:
625 finally:
626 del wlock
626 del wlock
627
627
628 def debugcheckstate(ui, repo):
628 def debugcheckstate(ui, repo):
629 """validate the correctness of the current dirstate"""
629 """validate the correctness of the current dirstate"""
630 parent1, parent2 = repo.dirstate.parents()
630 parent1, parent2 = repo.dirstate.parents()
631 m1 = repo.changectx(parent1).manifest()
631 m1 = repo.changectx(parent1).manifest()
632 m2 = repo.changectx(parent2).manifest()
632 m2 = repo.changectx(parent2).manifest()
633 errors = 0
633 errors = 0
634 for f in repo.dirstate:
634 for f in repo.dirstate:
635 state = repo.dirstate[f]
635 state = repo.dirstate[f]
636 if state in "nr" and f not in m1:
636 if state in "nr" and f not in m1:
637 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
637 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
638 errors += 1
638 errors += 1
639 if state in "a" and f in m1:
639 if state in "a" and f in m1:
640 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
640 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
641 errors += 1
641 errors += 1
642 if state in "m" and f not in m1 and f not in m2:
642 if state in "m" and f not in m1 and f not in m2:
643 ui.warn(_("%s in state %s, but not in either manifest\n") %
643 ui.warn(_("%s in state %s, but not in either manifest\n") %
644 (f, state))
644 (f, state))
645 errors += 1
645 errors += 1
646 for f in m1:
646 for f in m1:
647 state = repo.dirstate[f]
647 state = repo.dirstate[f]
648 if state not in "nrm":
648 if state not in "nrm":
649 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
649 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
650 errors += 1
650 errors += 1
651 if errors:
651 if errors:
652 error = _(".hg/dirstate inconsistent with current parent's manifest")
652 error = _(".hg/dirstate inconsistent with current parent's manifest")
653 raise util.Abort(error)
653 raise util.Abort(error)
654
654
655 def showconfig(ui, repo, *values, **opts):
655 def showconfig(ui, repo, *values, **opts):
656 """show combined config settings from all hgrc files
656 """show combined config settings from all hgrc files
657
657
658 With no args, print names and values of all config items.
658 With no args, print names and values of all config items.
659
659
660 With one arg of the form section.name, print just the value of
660 With one arg of the form section.name, print just the value of
661 that config item.
661 that config item.
662
662
663 With multiple args, print names and values of all config items
663 With multiple args, print names and values of all config items
664 with matching section names."""
664 with matching section names."""
665
665
666 untrusted = bool(opts.get('untrusted'))
666 untrusted = bool(opts.get('untrusted'))
667 if values:
667 if values:
668 if len([v for v in values if '.' in v]) > 1:
668 if len([v for v in values if '.' in v]) > 1:
669 raise util.Abort(_('only one config item permitted'))
669 raise util.Abort(_('only one config item permitted'))
670 for section, name, value in ui.walkconfig(untrusted=untrusted):
670 for section, name, value in ui.walkconfig(untrusted=untrusted):
671 sectname = section + '.' + name
671 sectname = section + '.' + name
672 if values:
672 if values:
673 for v in values:
673 for v in values:
674 if v == section:
674 if v == section:
675 ui.write('%s=%s\n' % (sectname, value))
675 ui.write('%s=%s\n' % (sectname, value))
676 elif v == sectname:
676 elif v == sectname:
677 ui.write(value, '\n')
677 ui.write(value, '\n')
678 else:
678 else:
679 ui.write('%s=%s\n' % (sectname, value))
679 ui.write('%s=%s\n' % (sectname, value))
680
680
681 def debugsetparents(ui, repo, rev1, rev2=None):
681 def debugsetparents(ui, repo, rev1, rev2=None):
682 """manually set the parents of the current working directory
682 """manually set the parents of the current working directory
683
683
684 This is useful for writing repository conversion tools, but should
684 This is useful for writing repository conversion tools, but should
685 be used with care.
685 be used with care.
686 """
686 """
687
687
688 if not rev2:
688 if not rev2:
689 rev2 = hex(nullid)
689 rev2 = hex(nullid)
690
690
691 wlock = repo.wlock()
691 wlock = repo.wlock()
692 try:
692 try:
693 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
693 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
694 finally:
694 finally:
695 del wlock
695 del wlock
696
696
697 def debugstate(ui, repo):
697 def debugstate(ui, repo):
698 """show the contents of the current dirstate"""
698 """show the contents of the current dirstate"""
699 k = repo.dirstate._map.items()
699 k = repo.dirstate._map.items()
700 k.sort()
700 k.sort()
701 for file_, ent in k:
701 for file_, ent in k:
702 if ent[3] == -1:
702 if ent[3] == -1:
703 # Pad or slice to locale representation
703 # Pad or slice to locale representation
704 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0)))
704 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0)))
705 timestr = 'unset'
705 timestr = 'unset'
706 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
706 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
707 else:
707 else:
708 timestr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ent[3]))
708 timestr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ent[3]))
709 if ent[1] & 020000:
709 if ent[1] & 020000:
710 mode = 'lnk'
710 mode = 'lnk'
711 else:
711 else:
712 mode = '%3o' % (ent[1] & 0777)
712 mode = '%3o' % (ent[1] & 0777)
713 ui.write("%c %s %10d %s %s\n" % (ent[0], mode, ent[2], timestr, file_))
713 ui.write("%c %s %10d %s %s\n" % (ent[0], mode, ent[2], timestr, file_))
714 for f in repo.dirstate.copies():
714 for f in repo.dirstate.copies():
715 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
715 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
716
716
717 def debugdata(ui, file_, rev):
717 def debugdata(ui, file_, rev):
718 """dump the contents of a data file revision"""
718 """dump the contents of a data file revision"""
719 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
719 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
720 try:
720 try:
721 ui.write(r.revision(r.lookup(rev)))
721 ui.write(r.revision(r.lookup(rev)))
722 except KeyError:
722 except KeyError:
723 raise util.Abort(_('invalid revision identifier %s') % rev)
723 raise util.Abort(_('invalid revision identifier %s') % rev)
724
724
725 def debugdate(ui, date, range=None, **opts):
725 def debugdate(ui, date, range=None, **opts):
726 """parse and display a date"""
726 """parse and display a date"""
727 if opts["extended"]:
727 if opts["extended"]:
728 d = util.parsedate(date, util.extendeddateformats)
728 d = util.parsedate(date, util.extendeddateformats)
729 else:
729 else:
730 d = util.parsedate(date)
730 d = util.parsedate(date)
731 ui.write("internal: %s %s\n" % d)
731 ui.write("internal: %s %s\n" % d)
732 ui.write("standard: %s\n" % util.datestr(d))
732 ui.write("standard: %s\n" % util.datestr(d))
733 if range:
733 if range:
734 m = util.matchdate(range)
734 m = util.matchdate(range)
735 ui.write("match: %s\n" % m(d[0]))
735 ui.write("match: %s\n" % m(d[0]))
736
736
737 def debugindex(ui, file_):
737 def debugindex(ui, file_):
738 """dump the contents of an index file"""
738 """dump the contents of an index file"""
739 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
739 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
740 ui.write(" rev offset length base linkrev" +
740 ui.write(" rev offset length base linkrev" +
741 " nodeid p1 p2\n")
741 " nodeid p1 p2\n")
742 for i in xrange(r.count()):
742 for i in xrange(r.count()):
743 node = r.node(i)
743 node = r.node(i)
744 try:
744 try:
745 pp = r.parents(node)
745 pp = r.parents(node)
746 except:
746 except:
747 pp = [nullid, nullid]
747 pp = [nullid, nullid]
748 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
748 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
749 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
749 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
750 short(node), short(pp[0]), short(pp[1])))
750 short(node), short(pp[0]), short(pp[1])))
751
751
752 def debugindexdot(ui, file_):
752 def debugindexdot(ui, file_):
753 """dump an index DAG as a .dot file"""
753 """dump an index DAG as a .dot file"""
754 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
754 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
755 ui.write("digraph G {\n")
755 ui.write("digraph G {\n")
756 for i in xrange(r.count()):
756 for i in xrange(r.count()):
757 node = r.node(i)
757 node = r.node(i)
758 pp = r.parents(node)
758 pp = r.parents(node)
759 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
759 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
760 if pp[1] != nullid:
760 if pp[1] != nullid:
761 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
761 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
762 ui.write("}\n")
762 ui.write("}\n")
763
763
764 def debuginstall(ui):
764 def debuginstall(ui):
765 '''test Mercurial installation'''
765 '''test Mercurial installation'''
766
766
767 def writetemp(contents):
767 def writetemp(contents):
768 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
768 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
769 f = os.fdopen(fd, "wb")
769 f = os.fdopen(fd, "wb")
770 f.write(contents)
770 f.write(contents)
771 f.close()
771 f.close()
772 return name
772 return name
773
773
774 problems = 0
774 problems = 0
775
775
776 # encoding
776 # encoding
777 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
777 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
778 try:
778 try:
779 util.fromlocal("test")
779 util.fromlocal("test")
780 except util.Abort, inst:
780 except util.Abort, inst:
781 ui.write(" %s\n" % inst)
781 ui.write(" %s\n" % inst)
782 ui.write(_(" (check that your locale is properly set)\n"))
782 ui.write(_(" (check that your locale is properly set)\n"))
783 problems += 1
783 problems += 1
784
784
785 # compiled modules
785 # compiled modules
786 ui.status(_("Checking extensions...\n"))
786 ui.status(_("Checking extensions...\n"))
787 try:
787 try:
788 import bdiff, mpatch, base85
788 import bdiff, mpatch, base85
789 except Exception, inst:
789 except Exception, inst:
790 ui.write(" %s\n" % inst)
790 ui.write(" %s\n" % inst)
791 ui.write(_(" One or more extensions could not be found"))
791 ui.write(_(" One or more extensions could not be found"))
792 ui.write(_(" (check that you compiled the extensions)\n"))
792 ui.write(_(" (check that you compiled the extensions)\n"))
793 problems += 1
793 problems += 1
794
794
795 # templates
795 # templates
796 ui.status(_("Checking templates...\n"))
796 ui.status(_("Checking templates...\n"))
797 try:
797 try:
798 import templater
798 import templater
799 t = templater.templater(templater.templatepath("map-cmdline.default"))
799 t = templater.templater(templater.templatepath("map-cmdline.default"))
800 except Exception, inst:
800 except Exception, inst:
801 ui.write(" %s\n" % inst)
801 ui.write(" %s\n" % inst)
802 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
802 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
803 problems += 1
803 problems += 1
804
804
805 # patch
805 # patch
806 ui.status(_("Checking patch...\n"))
806 ui.status(_("Checking patch...\n"))
807 patchproblems = 0
807 patchproblems = 0
808 a = "1\n2\n3\n4\n"
808 a = "1\n2\n3\n4\n"
809 b = "1\n2\n3\ninsert\n4\n"
809 b = "1\n2\n3\ninsert\n4\n"
810 fa = writetemp(a)
810 fa = writetemp(a)
811 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
811 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
812 os.path.basename(fa))
812 os.path.basename(fa))
813 fd = writetemp(d)
813 fd = writetemp(d)
814
814
815 files = {}
815 files = {}
816 try:
816 try:
817 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
817 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
818 except util.Abort, e:
818 except util.Abort, e:
819 ui.write(_(" patch call failed:\n"))
819 ui.write(_(" patch call failed:\n"))
820 ui.write(" " + str(e) + "\n")
820 ui.write(" " + str(e) + "\n")
821 patchproblems += 1
821 patchproblems += 1
822 else:
822 else:
823 if list(files) != [os.path.basename(fa)]:
823 if list(files) != [os.path.basename(fa)]:
824 ui.write(_(" unexpected patch output!\n"))
824 ui.write(_(" unexpected patch output!\n"))
825 patchproblems += 1
825 patchproblems += 1
826 a = file(fa).read()
826 a = file(fa).read()
827 if a != b:
827 if a != b:
828 ui.write(_(" patch test failed!\n"))
828 ui.write(_(" patch test failed!\n"))
829 patchproblems += 1
829 patchproblems += 1
830
830
831 if patchproblems:
831 if patchproblems:
832 if ui.config('ui', 'patch'):
832 if ui.config('ui', 'patch'):
833 ui.write(_(" (Current patch tool may be incompatible with patch,"
833 ui.write(_(" (Current patch tool may be incompatible with patch,"
834 " or misconfigured. Please check your .hgrc file)\n"))
834 " or misconfigured. Please check your .hgrc file)\n"))
835 else:
835 else:
836 ui.write(_(" Internal patcher failure, please report this error"
836 ui.write(_(" Internal patcher failure, please report this error"
837 " to http://www.selenic.com/mercurial/bts\n"))
837 " to http://www.selenic.com/mercurial/bts\n"))
838 problems += patchproblems
838 problems += patchproblems
839
839
840 os.unlink(fa)
840 os.unlink(fa)
841 os.unlink(fd)
841 os.unlink(fd)
842
842
843 # editor
843 # editor
844 ui.status(_("Checking commit editor...\n"))
844 ui.status(_("Checking commit editor...\n"))
845 editor = ui.geteditor()
845 editor = ui.geteditor()
846 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
846 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
847 if not cmdpath:
847 if not cmdpath:
848 if editor == 'vi':
848 if editor == 'vi':
849 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
849 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
850 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
850 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
851 else:
851 else:
852 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
852 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
853 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
853 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
854 problems += 1
854 problems += 1
855
855
856 # check username
856 # check username
857 ui.status(_("Checking username...\n"))
857 ui.status(_("Checking username...\n"))
858 user = os.environ.get("HGUSER")
858 user = os.environ.get("HGUSER")
859 if user is None:
859 if user is None:
860 user = ui.config("ui", "username")
860 user = ui.config("ui", "username")
861 if user is None:
861 if user is None:
862 user = os.environ.get("EMAIL")
862 user = os.environ.get("EMAIL")
863 if not user:
863 if not user:
864 ui.warn(" ")
864 ui.warn(" ")
865 ui.username()
865 ui.username()
866 ui.write(_(" (specify a username in your .hgrc file)\n"))
866 ui.write(_(" (specify a username in your .hgrc file)\n"))
867
867
868 if not problems:
868 if not problems:
869 ui.status(_("No problems detected\n"))
869 ui.status(_("No problems detected\n"))
870 else:
870 else:
871 ui.write(_("%s problems detected,"
871 ui.write(_("%s problems detected,"
872 " please check your install!\n") % problems)
872 " please check your install!\n") % problems)
873
873
874 return problems
874 return problems
875
875
876 def debugrename(ui, repo, file1, *pats, **opts):
876 def debugrename(ui, repo, file1, *pats, **opts):
877 """dump rename information"""
877 """dump rename information"""
878
878
879 ctx = repo.changectx(opts.get('rev', 'tip'))
879 ctx = repo.changectx(opts.get('rev', 'tip'))
880 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
880 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
881 ctx.node()):
881 ctx.node()):
882 fctx = ctx.filectx(abs)
882 fctx = ctx.filectx(abs)
883 m = fctx.filelog().renamed(fctx.filenode())
883 m = fctx.filelog().renamed(fctx.filenode())
884 if m:
884 if m:
885 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
885 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
886 else:
886 else:
887 ui.write(_("%s not renamed\n") % rel)
887 ui.write(_("%s not renamed\n") % rel)
888
888
889 def debugwalk(ui, repo, *pats, **opts):
889 def debugwalk(ui, repo, *pats, **opts):
890 """show how files match on given patterns"""
890 """show how files match on given patterns"""
891 items = list(cmdutil.walk(repo, pats, opts))
891 items = list(cmdutil.walk(repo, pats, opts))
892 if not items:
892 if not items:
893 return
893 return
894 fmt = '%%s %%-%ds %%-%ds %%s' % (
894 fmt = '%%s %%-%ds %%-%ds %%s' % (
895 max([len(abs) for (src, abs, rel, exact) in items]),
895 max([len(abs) for (src, abs, rel, exact) in items]),
896 max([len(rel) for (src, abs, rel, exact) in items]))
896 max([len(rel) for (src, abs, rel, exact) in items]))
897 for src, abs, rel, exact in items:
897 for src, abs, rel, exact in items:
898 line = fmt % (src, abs, rel, exact and 'exact' or '')
898 line = fmt % (src, abs, rel, exact and 'exact' or '')
899 ui.write("%s\n" % line.rstrip())
899 ui.write("%s\n" % line.rstrip())
900
900
901 def diff(ui, repo, *pats, **opts):
901 def diff(ui, repo, *pats, **opts):
902 """diff repository (or selected files)
902 """diff repository (or selected files)
903
903
904 Show differences between revisions for the specified files.
904 Show differences between revisions for the specified files.
905
905
906 Differences between files are shown using the unified diff format.
906 Differences between files are shown using the unified diff format.
907
907
908 NOTE: diff may generate unexpected results for merges, as it will
908 NOTE: diff may generate unexpected results for merges, as it will
909 default to comparing against the working directory's first parent
909 default to comparing against the working directory's first parent
910 changeset if no revisions are specified.
910 changeset if no revisions are specified.
911
911
912 When two revision arguments are given, then changes are shown
912 When two revision arguments are given, then changes are shown
913 between those revisions. If only one revision is specified then
913 between those revisions. If only one revision is specified then
914 that revision is compared to the working directory, and, when no
914 that revision is compared to the working directory, and, when no
915 revisions are specified, the working directory files are compared
915 revisions are specified, the working directory files are compared
916 to its parent.
916 to its parent.
917
917
918 Without the -a option, diff will avoid generating diffs of files
918 Without the -a option, diff will avoid generating diffs of files
919 it detects as binary. With -a, diff will generate a diff anyway,
919 it detects as binary. With -a, diff will generate a diff anyway,
920 probably with undesirable results.
920 probably with undesirable results.
921 """
921 """
922 node1, node2 = cmdutil.revpair(repo, opts['rev'])
922 node1, node2 = cmdutil.revpair(repo, opts['rev'])
923
923
924 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
924 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
925
925
926 patch.diff(repo, node1, node2, fns, match=matchfn,
926 patch.diff(repo, node1, node2, fns, match=matchfn,
927 opts=patch.diffopts(ui, opts))
927 opts=patch.diffopts(ui, opts))
928
928
929 def export(ui, repo, *changesets, **opts):
929 def export(ui, repo, *changesets, **opts):
930 """dump the header and diffs for one or more changesets
930 """dump the header and diffs for one or more changesets
931
931
932 Print the changeset header and diffs for one or more revisions.
932 Print the changeset header and diffs for one or more revisions.
933
933
934 The information shown in the changeset header is: author,
934 The information shown in the changeset header is: author,
935 changeset hash, parent(s) and commit comment.
935 changeset hash, parent(s) and commit comment.
936
936
937 NOTE: export may generate unexpected diff output for merge changesets,
937 NOTE: export may generate unexpected diff output for merge changesets,
938 as it will compare the merge changeset against its first parent only.
938 as it will compare the merge changeset against its first parent only.
939
939
940 Output may be to a file, in which case the name of the file is
940 Output may be to a file, in which case the name of the file is
941 given using a format string. The formatting rules are as follows:
941 given using a format string. The formatting rules are as follows:
942
942
943 %% literal "%" character
943 %% literal "%" character
944 %H changeset hash (40 bytes of hexadecimal)
944 %H changeset hash (40 bytes of hexadecimal)
945 %N number of patches being generated
945 %N number of patches being generated
946 %R changeset revision number
946 %R changeset revision number
947 %b basename of the exporting repository
947 %b basename of the exporting repository
948 %h short-form changeset hash (12 bytes of hexadecimal)
948 %h short-form changeset hash (12 bytes of hexadecimal)
949 %n zero-padded sequence number, starting at 1
949 %n zero-padded sequence number, starting at 1
950 %r zero-padded changeset revision number
950 %r zero-padded changeset revision number
951
951
952 Without the -a option, export will avoid generating diffs of files
952 Without the -a option, export will avoid generating diffs of files
953 it detects as binary. With -a, export will generate a diff anyway,
953 it detects as binary. With -a, export will generate a diff anyway,
954 probably with undesirable results.
954 probably with undesirable results.
955
955
956 With the --switch-parent option, the diff will be against the second
956 With the --switch-parent option, the diff will be against the second
957 parent. It can be useful to review a merge.
957 parent. It can be useful to review a merge.
958 """
958 """
959 if not changesets:
959 if not changesets:
960 raise util.Abort(_("export requires at least one changeset"))
960 raise util.Abort(_("export requires at least one changeset"))
961 revs = cmdutil.revrange(repo, changesets)
961 revs = cmdutil.revrange(repo, changesets)
962 if len(revs) > 1:
962 if len(revs) > 1:
963 ui.note(_('exporting patches:\n'))
963 ui.note(_('exporting patches:\n'))
964 else:
964 else:
965 ui.note(_('exporting patch:\n'))
965 ui.note(_('exporting patch:\n'))
966 patch.export(repo, revs, template=opts['output'],
966 patch.export(repo, revs, template=opts['output'],
967 switch_parent=opts['switch_parent'],
967 switch_parent=opts['switch_parent'],
968 opts=patch.diffopts(ui, opts))
968 opts=patch.diffopts(ui, opts))
969
969
970 def grep(ui, repo, pattern, *pats, **opts):
970 def grep(ui, repo, pattern, *pats, **opts):
971 """search for a pattern in specified files and revisions
971 """search for a pattern in specified files and revisions
972
972
973 Search revisions of files for a regular expression.
973 Search revisions of files for a regular expression.
974
974
975 This command behaves differently than Unix grep. It only accepts
975 This command behaves differently than Unix grep. It only accepts
976 Python/Perl regexps. It searches repository history, not the
976 Python/Perl regexps. It searches repository history, not the
977 working directory. It always prints the revision number in which
977 working directory. It always prints the revision number in which
978 a match appears.
978 a match appears.
979
979
980 By default, grep only prints output for the first revision of a
980 By default, grep only prints output for the first revision of a
981 file in which it finds a match. To get it to print every revision
981 file in which it finds a match. To get it to print every revision
982 that contains a change in match status ("-" for a match that
982 that contains a change in match status ("-" for a match that
983 becomes a non-match, or "+" for a non-match that becomes a match),
983 becomes a non-match, or "+" for a non-match that becomes a match),
984 use the --all flag.
984 use the --all flag.
985 """
985 """
986 reflags = 0
986 reflags = 0
987 if opts['ignore_case']:
987 if opts['ignore_case']:
988 reflags |= re.I
988 reflags |= re.I
989 try:
989 try:
990 regexp = re.compile(pattern, reflags)
990 regexp = re.compile(pattern, reflags)
991 except Exception, inst:
991 except Exception, inst:
992 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
992 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
993 return None
993 return None
994 sep, eol = ':', '\n'
994 sep, eol = ':', '\n'
995 if opts['print0']:
995 if opts['print0']:
996 sep = eol = '\0'
996 sep = eol = '\0'
997
997
998 fcache = {}
998 fcache = {}
999 def getfile(fn):
999 def getfile(fn):
1000 if fn not in fcache:
1000 if fn not in fcache:
1001 fcache[fn] = repo.file(fn)
1001 fcache[fn] = repo.file(fn)
1002 return fcache[fn]
1002 return fcache[fn]
1003
1003
1004 def matchlines(body):
1004 def matchlines(body):
1005 begin = 0
1005 begin = 0
1006 linenum = 0
1006 linenum = 0
1007 while True:
1007 while True:
1008 match = regexp.search(body, begin)
1008 match = regexp.search(body, begin)
1009 if not match:
1009 if not match:
1010 break
1010 break
1011 mstart, mend = match.span()
1011 mstart, mend = match.span()
1012 linenum += body.count('\n', begin, mstart) + 1
1012 linenum += body.count('\n', begin, mstart) + 1
1013 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1013 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1014 lend = body.find('\n', mend)
1014 lend = body.find('\n', mend)
1015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1016 begin = lend + 1
1016 begin = lend + 1
1017
1017
1018 class linestate(object):
1018 class linestate(object):
1019 def __init__(self, line, linenum, colstart, colend):
1019 def __init__(self, line, linenum, colstart, colend):
1020 self.line = line
1020 self.line = line
1021 self.linenum = linenum
1021 self.linenum = linenum
1022 self.colstart = colstart
1022 self.colstart = colstart
1023 self.colend = colend
1023 self.colend = colend
1024
1024
1025 def __eq__(self, other):
1025 def __eq__(self, other):
1026 return self.line == other.line
1026 return self.line == other.line
1027
1027
1028 matches = {}
1028 matches = {}
1029 copies = {}
1029 copies = {}
1030 def grepbody(fn, rev, body):
1030 def grepbody(fn, rev, body):
1031 matches[rev].setdefault(fn, [])
1031 matches[rev].setdefault(fn, [])
1032 m = matches[rev][fn]
1032 m = matches[rev][fn]
1033 for lnum, cstart, cend, line in matchlines(body):
1033 for lnum, cstart, cend, line in matchlines(body):
1034 s = linestate(line, lnum, cstart, cend)
1034 s = linestate(line, lnum, cstart, cend)
1035 m.append(s)
1035 m.append(s)
1036
1036
1037 def difflinestates(a, b):
1037 def difflinestates(a, b):
1038 sm = difflib.SequenceMatcher(None, a, b)
1038 sm = difflib.SequenceMatcher(None, a, b)
1039 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1039 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1040 if tag == 'insert':
1040 if tag == 'insert':
1041 for i in xrange(blo, bhi):
1041 for i in xrange(blo, bhi):
1042 yield ('+', b[i])
1042 yield ('+', b[i])
1043 elif tag == 'delete':
1043 elif tag == 'delete':
1044 for i in xrange(alo, ahi):
1044 for i in xrange(alo, ahi):
1045 yield ('-', a[i])
1045 yield ('-', a[i])
1046 elif tag == 'replace':
1046 elif tag == 'replace':
1047 for i in xrange(alo, ahi):
1047 for i in xrange(alo, ahi):
1048 yield ('-', a[i])
1048 yield ('-', a[i])
1049 for i in xrange(blo, bhi):
1049 for i in xrange(blo, bhi):
1050 yield ('+', b[i])
1050 yield ('+', b[i])
1051
1051
1052 prev = {}
1052 prev = {}
1053 def display(fn, rev, states, prevstates):
1053 def display(fn, rev, states, prevstates):
1054 datefunc = ui.quiet and util.shortdate or util.datestr
1054 datefunc = ui.quiet and util.shortdate or util.datestr
1055 found = False
1055 found = False
1056 filerevmatches = {}
1056 filerevmatches = {}
1057 r = prev.get(fn, -1)
1057 r = prev.get(fn, -1)
1058 if opts['all']:
1058 if opts['all']:
1059 iter = difflinestates(states, prevstates)
1059 iter = difflinestates(states, prevstates)
1060 else:
1060 else:
1061 iter = [('', l) for l in prevstates]
1061 iter = [('', l) for l in prevstates]
1062 for change, l in iter:
1062 for change, l in iter:
1063 cols = [fn, str(r)]
1063 cols = [fn, str(r)]
1064 if opts['line_number']:
1064 if opts['line_number']:
1065 cols.append(str(l.linenum))
1065 cols.append(str(l.linenum))
1066 if opts['all']:
1066 if opts['all']:
1067 cols.append(change)
1067 cols.append(change)
1068 if opts['user']:
1068 if opts['user']:
1069 cols.append(ui.shortuser(get(r)[1]))
1069 cols.append(ui.shortuser(get(r)[1]))
1070 if opts.get('date'):
1070 if opts.get('date'):
1071 cols.append(datefunc(get(r)[2]))
1071 cols.append(datefunc(get(r)[2]))
1072 if opts['files_with_matches']:
1072 if opts['files_with_matches']:
1073 c = (fn, r)
1073 c = (fn, r)
1074 if c in filerevmatches:
1074 if c in filerevmatches:
1075 continue
1075 continue
1076 filerevmatches[c] = 1
1076 filerevmatches[c] = 1
1077 else:
1077 else:
1078 cols.append(l.line)
1078 cols.append(l.line)
1079 ui.write(sep.join(cols), eol)
1079 ui.write(sep.join(cols), eol)
1080 found = True
1080 found = True
1081 return found
1081 return found
1082
1082
1083 fstate = {}
1083 fstate = {}
1084 skip = {}
1084 skip = {}
1085 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1085 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1086 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1086 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1087 found = False
1087 found = False
1088 follow = opts.get('follow')
1088 follow = opts.get('follow')
1089 for st, rev, fns in changeiter:
1089 for st, rev, fns in changeiter:
1090 if st == 'window':
1090 if st == 'window':
1091 matches.clear()
1091 matches.clear()
1092 elif st == 'add':
1092 elif st == 'add':
1093 ctx = repo.changectx(rev)
1093 ctx = repo.changectx(rev)
1094 matches[rev] = {}
1094 matches[rev] = {}
1095 for fn in fns:
1095 for fn in fns:
1096 if fn in skip:
1096 if fn in skip:
1097 continue
1097 continue
1098 try:
1098 try:
1099 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1099 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1100 fstate.setdefault(fn, [])
1100 fstate.setdefault(fn, [])
1101 if follow:
1101 if follow:
1102 copied = getfile(fn).renamed(ctx.filenode(fn))
1102 copied = getfile(fn).renamed(ctx.filenode(fn))
1103 if copied:
1103 if copied:
1104 copies.setdefault(rev, {})[fn] = copied[0]
1104 copies.setdefault(rev, {})[fn] = copied[0]
1105 except revlog.LookupError:
1105 except revlog.LookupError:
1106 pass
1106 pass
1107 elif st == 'iter':
1107 elif st == 'iter':
1108 states = matches[rev].items()
1108 states = matches[rev].items()
1109 states.sort()
1109 states.sort()
1110 for fn, m in states:
1110 for fn, m in states:
1111 copy = copies.get(rev, {}).get(fn)
1111 copy = copies.get(rev, {}).get(fn)
1112 if fn in skip:
1112 if fn in skip:
1113 if copy:
1113 if copy:
1114 skip[copy] = True
1114 skip[copy] = True
1115 continue
1115 continue
1116 if fn in prev or fstate[fn]:
1116 if fn in prev or fstate[fn]:
1117 r = display(fn, rev, m, fstate[fn])
1117 r = display(fn, rev, m, fstate[fn])
1118 found = found or r
1118 found = found or r
1119 if r and not opts['all']:
1119 if r and not opts['all']:
1120 skip[fn] = True
1120 skip[fn] = True
1121 if copy:
1121 if copy:
1122 skip[copy] = True
1122 skip[copy] = True
1123 fstate[fn] = m
1123 fstate[fn] = m
1124 if copy:
1124 if copy:
1125 fstate[copy] = m
1125 fstate[copy] = m
1126 prev[fn] = rev
1126 prev[fn] = rev
1127
1127
1128 fstate = fstate.items()
1128 fstate = fstate.items()
1129 fstate.sort()
1129 fstate.sort()
1130 for fn, state in fstate:
1130 for fn, state in fstate:
1131 if fn in skip:
1131 if fn in skip:
1132 continue
1132 continue
1133 if fn not in copies.get(prev[fn], {}):
1133 if fn not in copies.get(prev[fn], {}):
1134 found = display(fn, rev, {}, state) or found
1134 found = display(fn, rev, {}, state) or found
1135 return (not found and 1) or 0
1135 return (not found and 1) or 0
1136
1136
1137 def heads(ui, repo, *branchrevs, **opts):
1137 def heads(ui, repo, *branchrevs, **opts):
1138 """show current repository heads or show branch heads
1138 """show current repository heads or show branch heads
1139
1139
1140 With no arguments, show all repository head changesets.
1140 With no arguments, show all repository head changesets.
1141
1141
1142 If branch or revisions names are given this will show the heads of
1142 If branch or revisions names are given this will show the heads of
1143 the specified branches or the branches those revisions are tagged
1143 the specified branches or the branches those revisions are tagged
1144 with.
1144 with.
1145
1145
1146 Repository "heads" are changesets that don't have child
1146 Repository "heads" are changesets that don't have child
1147 changesets. They are where development generally takes place and
1147 changesets. They are where development generally takes place and
1148 are the usual targets for update and merge operations.
1148 are the usual targets for update and merge operations.
1149
1149
1150 Branch heads are changesets that have a given branch tag, but have
1150 Branch heads are changesets that have a given branch tag, but have
1151 no child changesets with that tag. They are usually where
1151 no child changesets with that tag. They are usually where
1152 development on the given branch takes place.
1152 development on the given branch takes place.
1153 """
1153 """
1154 if opts['rev']:
1154 if opts['rev']:
1155 start = repo.lookup(opts['rev'])
1155 start = repo.lookup(opts['rev'])
1156 else:
1156 else:
1157 start = None
1157 start = None
1158 if not branchrevs:
1158 if not branchrevs:
1159 # Assume we're looking repo-wide heads if no revs were specified.
1159 # Assume we're looking repo-wide heads if no revs were specified.
1160 heads = repo.heads(start)
1160 heads = repo.heads(start)
1161 else:
1161 else:
1162 heads = []
1162 heads = []
1163 visitedset = util.set()
1163 visitedset = util.set()
1164 for branchrev in branchrevs:
1164 for branchrev in branchrevs:
1165 branch = repo.changectx(branchrev).branch()
1165 branch = repo.changectx(branchrev).branch()
1166 if branch in visitedset:
1166 if branch in visitedset:
1167 continue
1167 continue
1168 visitedset.add(branch)
1168 visitedset.add(branch)
1169 bheads = repo.branchheads(branch, start)
1169 bheads = repo.branchheads(branch, start)
1170 if not bheads:
1170 if not bheads:
1171 if branch != branchrev:
1171 if branch != branchrev:
1172 ui.warn(_("no changes on branch %s containing %s are "
1172 ui.warn(_("no changes on branch %s containing %s are "
1173 "reachable from %s\n")
1173 "reachable from %s\n")
1174 % (branch, branchrev, opts['rev']))
1174 % (branch, branchrev, opts['rev']))
1175 else:
1175 else:
1176 ui.warn(_("no changes on branch %s are reachable from %s\n")
1176 ui.warn(_("no changes on branch %s are reachable from %s\n")
1177 % (branch, opts['rev']))
1177 % (branch, opts['rev']))
1178 heads.extend(bheads)
1178 heads.extend(bheads)
1179 if not heads:
1179 if not heads:
1180 return 1
1180 return 1
1181 displayer = cmdutil.show_changeset(ui, repo, opts)
1181 displayer = cmdutil.show_changeset(ui, repo, opts)
1182 for n in heads:
1182 for n in heads:
1183 displayer.show(changenode=n)
1183 displayer.show(changenode=n)
1184
1184
1185 def help_(ui, name=None, with_version=False):
1185 def help_(ui, name=None, with_version=False):
1186 """show help for a command, extension, or list of commands
1186 """show help for a command, extension, or list of commands
1187
1187
1188 With no arguments, print a list of commands and short help.
1188 With no arguments, print a list of commands and short help.
1189
1189
1190 Given a command name, print help for that command.
1190 Given a command name, print help for that command.
1191
1191
1192 Given an extension name, print help for that extension, and the
1192 Given an extension name, print help for that extension, and the
1193 commands it provides."""
1193 commands it provides."""
1194 option_lists = []
1194 option_lists = []
1195
1195
1196 def addglobalopts(aliases):
1196 def addglobalopts(aliases):
1197 if ui.verbose:
1197 if ui.verbose:
1198 option_lists.append((_("global options:"), globalopts))
1198 option_lists.append((_("global options:"), globalopts))
1199 if name == 'shortlist':
1199 if name == 'shortlist':
1200 option_lists.append((_('use "hg help" for the full list '
1200 option_lists.append((_('use "hg help" for the full list '
1201 'of commands'), ()))
1201 'of commands'), ()))
1202 else:
1202 else:
1203 if name == 'shortlist':
1203 if name == 'shortlist':
1204 msg = _('use "hg help" for the full list of commands '
1204 msg = _('use "hg help" for the full list of commands '
1205 'or "hg -v" for details')
1205 'or "hg -v" for details')
1206 elif aliases:
1206 elif aliases:
1207 msg = _('use "hg -v help%s" to show aliases and '
1207 msg = _('use "hg -v help%s" to show aliases and '
1208 'global options') % (name and " " + name or "")
1208 'global options') % (name and " " + name or "")
1209 else:
1209 else:
1210 msg = _('use "hg -v help %s" to show global options') % name
1210 msg = _('use "hg -v help %s" to show global options') % name
1211 option_lists.append((msg, ()))
1211 option_lists.append((msg, ()))
1212
1212
1213 def helpcmd(name):
1213 def helpcmd(name):
1214 if with_version:
1214 if with_version:
1215 version_(ui)
1215 version_(ui)
1216 ui.write('\n')
1216 ui.write('\n')
1217 aliases, i = cmdutil.findcmd(ui, name, table)
1217 aliases, i = cmdutil.findcmd(ui, name, table)
1218 # synopsis
1218 # synopsis
1219 ui.write("%s\n" % i[2])
1219 ui.write("%s\n" % i[2])
1220
1220
1221 # aliases
1221 # aliases
1222 if not ui.quiet and len(aliases) > 1:
1222 if not ui.quiet and len(aliases) > 1:
1223 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1223 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1224
1224
1225 # description
1225 # description
1226 doc = i[0].__doc__
1226 doc = i[0].__doc__
1227 if not doc:
1227 if not doc:
1228 doc = _("(No help text available)")
1228 doc = _("(No help text available)")
1229 if ui.quiet:
1229 if ui.quiet:
1230 doc = doc.splitlines(0)[0]
1230 doc = doc.splitlines(0)[0]
1231 ui.write("\n%s\n" % doc.rstrip())
1231 ui.write("\n%s\n" % doc.rstrip())
1232
1232
1233 if not ui.quiet:
1233 if not ui.quiet:
1234 # options
1234 # options
1235 if i[1]:
1235 if i[1]:
1236 option_lists.append((_("options:\n"), i[1]))
1236 option_lists.append((_("options:\n"), i[1]))
1237
1237
1238 addglobalopts(False)
1238 addglobalopts(False)
1239
1239
1240 def helplist(header, select=None):
1240 def helplist(header, select=None):
1241 h = {}
1241 h = {}
1242 cmds = {}
1242 cmds = {}
1243 for c, e in table.items():
1243 for c, e in table.items():
1244 f = c.split("|", 1)[0]
1244 f = c.split("|", 1)[0]
1245 if select and not select(f):
1245 if select and not select(f):
1246 continue
1246 continue
1247 if name == "shortlist" and not f.startswith("^"):
1247 if name == "shortlist" and not f.startswith("^"):
1248 continue
1248 continue
1249 f = f.lstrip("^")
1249 f = f.lstrip("^")
1250 if not ui.debugflag and f.startswith("debug"):
1250 if not ui.debugflag and f.startswith("debug"):
1251 continue
1251 continue
1252 doc = e[0].__doc__
1252 doc = e[0].__doc__
1253 if not doc:
1253 if not doc:
1254 doc = _("(No help text available)")
1254 doc = _("(No help text available)")
1255 h[f] = doc.splitlines(0)[0].rstrip()
1255 h[f] = doc.splitlines(0)[0].rstrip()
1256 cmds[f] = c.lstrip("^")
1256 cmds[f] = c.lstrip("^")
1257
1257
1258 if not h:
1258 if not h:
1259 ui.status(_('no commands defined\n'))
1259 ui.status(_('no commands defined\n'))
1260 return
1260 return
1261
1261
1262 ui.status(header)
1262 ui.status(header)
1263 fns = h.keys()
1263 fns = h.keys()
1264 fns.sort()
1264 fns.sort()
1265 m = max(map(len, fns))
1265 m = max(map(len, fns))
1266 for f in fns:
1266 for f in fns:
1267 if ui.verbose:
1267 if ui.verbose:
1268 commands = cmds[f].replace("|",", ")
1268 commands = cmds[f].replace("|",", ")
1269 ui.write(" %s:\n %s\n"%(commands, h[f]))
1269 ui.write(" %s:\n %s\n"%(commands, h[f]))
1270 else:
1270 else:
1271 ui.write(' %-*s %s\n' % (m, f, h[f]))
1271 ui.write(' %-*s %s\n' % (m, f, h[f]))
1272
1272
1273 if not ui.quiet:
1273 if not ui.quiet:
1274 addglobalopts(True)
1274 addglobalopts(True)
1275
1275
1276 def helptopic(name):
1276 def helptopic(name):
1277 v = None
1277 v = None
1278 for i in help.helptable:
1278 for i in help.helptable:
1279 l = i.split('|')
1279 l = i.split('|')
1280 if name in l:
1280 if name in l:
1281 v = i
1281 v = i
1282 header = l[-1]
1282 header = l[-1]
1283 if not v:
1283 if not v:
1284 raise cmdutil.UnknownCommand(name)
1284 raise cmdutil.UnknownCommand(name)
1285
1285
1286 # description
1286 # description
1287 doc = help.helptable[v]
1287 doc = help.helptable[v]
1288 if not doc:
1288 if not doc:
1289 doc = _("(No help text available)")
1289 doc = _("(No help text available)")
1290 if callable(doc):
1290 if callable(doc):
1291 doc = doc()
1291 doc = doc()
1292
1292
1293 ui.write("%s\n" % header)
1293 ui.write("%s\n" % header)
1294 ui.write("%s\n" % doc.rstrip())
1294 ui.write("%s\n" % doc.rstrip())
1295
1295
1296 def helpext(name):
1296 def helpext(name):
1297 try:
1297 try:
1298 mod = extensions.find(name)
1298 mod = extensions.find(name)
1299 except KeyError:
1299 except KeyError:
1300 raise cmdutil.UnknownCommand(name)
1300 raise cmdutil.UnknownCommand(name)
1301
1301
1302 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1302 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1303 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1303 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1304 for d in doc[1:]:
1304 for d in doc[1:]:
1305 ui.write(d, '\n')
1305 ui.write(d, '\n')
1306
1306
1307 ui.status('\n')
1307 ui.status('\n')
1308
1308
1309 try:
1309 try:
1310 ct = mod.cmdtable
1310 ct = mod.cmdtable
1311 except AttributeError:
1311 except AttributeError:
1312 ct = {}
1312 ct = {}
1313
1313
1314 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1314 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1315 helplist(_('list of commands:\n\n'), modcmds.has_key)
1315 helplist(_('list of commands:\n\n'), modcmds.has_key)
1316
1316
1317 if name and name != 'shortlist':
1317 if name and name != 'shortlist':
1318 i = None
1318 i = None
1319 for f in (helpcmd, helptopic, helpext):
1319 for f in (helpcmd, helptopic, helpext):
1320 try:
1320 try:
1321 f(name)
1321 f(name)
1322 i = None
1322 i = None
1323 break
1323 break
1324 except cmdutil.UnknownCommand, inst:
1324 except cmdutil.UnknownCommand, inst:
1325 i = inst
1325 i = inst
1326 if i:
1326 if i:
1327 raise i
1327 raise i
1328
1328
1329 else:
1329 else:
1330 # program name
1330 # program name
1331 if ui.verbose or with_version:
1331 if ui.verbose or with_version:
1332 version_(ui)
1332 version_(ui)
1333 else:
1333 else:
1334 ui.status(_("Mercurial Distributed SCM\n"))
1334 ui.status(_("Mercurial Distributed SCM\n"))
1335 ui.status('\n')
1335 ui.status('\n')
1336
1336
1337 # list of commands
1337 # list of commands
1338 if name == "shortlist":
1338 if name == "shortlist":
1339 header = _('basic commands:\n\n')
1339 header = _('basic commands:\n\n')
1340 else:
1340 else:
1341 header = _('list of commands:\n\n')
1341 header = _('list of commands:\n\n')
1342
1342
1343 helplist(header)
1343 helplist(header)
1344
1344
1345 # list all option lists
1345 # list all option lists
1346 opt_output = []
1346 opt_output = []
1347 for title, options in option_lists:
1347 for title, options in option_lists:
1348 opt_output.append(("\n%s" % title, None))
1348 opt_output.append(("\n%s" % title, None))
1349 for shortopt, longopt, default, desc in options:
1349 for shortopt, longopt, default, desc in options:
1350 if "DEPRECATED" in desc and not ui.verbose: continue
1350 if "DEPRECATED" in desc and not ui.verbose: continue
1351 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1351 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1352 longopt and " --%s" % longopt),
1352 longopt and " --%s" % longopt),
1353 "%s%s" % (desc,
1353 "%s%s" % (desc,
1354 default
1354 default
1355 and _(" (default: %s)") % default
1355 and _(" (default: %s)") % default
1356 or "")))
1356 or "")))
1357
1357
1358 if opt_output:
1358 if opt_output:
1359 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1359 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1360 for first, second in opt_output:
1360 for first, second in opt_output:
1361 if second:
1361 if second:
1362 ui.write(" %-*s %s\n" % (opts_len, first, second))
1362 ui.write(" %-*s %s\n" % (opts_len, first, second))
1363 else:
1363 else:
1364 ui.write("%s\n" % first)
1364 ui.write("%s\n" % first)
1365
1365
1366 def identify(ui, repo, source=None,
1366 def identify(ui, repo, source=None,
1367 rev=None, num=None, id=None, branch=None, tags=None):
1367 rev=None, num=None, id=None, branch=None, tags=None):
1368 """identify the working copy or specified revision
1368 """identify the working copy or specified revision
1369
1369
1370 With no revision, print a summary of the current state of the repo.
1370 With no revision, print a summary of the current state of the repo.
1371
1371
1372 With a path, do a lookup in another repository.
1372 With a path, do a lookup in another repository.
1373
1373
1374 This summary identifies the repository state using one or two parent
1374 This summary identifies the repository state using one or two parent
1375 hash identifiers, followed by a "+" if there are uncommitted changes
1375 hash identifiers, followed by a "+" if there are uncommitted changes
1376 in the working directory, a list of tags for this revision and a branch
1376 in the working directory, a list of tags for this revision and a branch
1377 name for non-default branches.
1377 name for non-default branches.
1378 """
1378 """
1379
1379
1380 if not repo and not source:
1380 if not repo and not source:
1381 raise util.Abort(_("There is no Mercurial repository here "
1381 raise util.Abort(_("There is no Mercurial repository here "
1382 "(.hg not found)"))
1382 "(.hg not found)"))
1383
1383
1384 hexfunc = ui.debugflag and hex or short
1384 hexfunc = ui.debugflag and hex or short
1385 default = not (num or id or branch or tags)
1385 default = not (num or id or branch or tags)
1386 output = []
1386 output = []
1387
1387
1388 if source:
1388 if source:
1389 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1389 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1390 srepo = hg.repository(ui, source)
1390 srepo = hg.repository(ui, source)
1391 if not rev and revs:
1391 if not rev and revs:
1392 rev = revs[0]
1392 rev = revs[0]
1393 if not rev:
1393 if not rev:
1394 rev = "tip"
1394 rev = "tip"
1395 if num or branch or tags:
1395 if num or branch or tags:
1396 raise util.Abort(
1396 raise util.Abort(
1397 "can't query remote revision number, branch, or tags")
1397 "can't query remote revision number, branch, or tags")
1398 output = [hexfunc(srepo.lookup(rev))]
1398 output = [hexfunc(srepo.lookup(rev))]
1399 elif not rev:
1399 elif not rev:
1400 ctx = repo.workingctx()
1400 ctx = repo.workingctx()
1401 parents = ctx.parents()
1401 parents = ctx.parents()
1402 changed = False
1402 changed = False
1403 if default or id or num:
1403 if default or id or num:
1404 changed = ctx.files() + ctx.deleted()
1404 changed = ctx.files() + ctx.deleted()
1405 if default or id:
1405 if default or id:
1406 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1406 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1407 (changed) and "+" or "")]
1407 (changed) and "+" or "")]
1408 if num:
1408 if num:
1409 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1409 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1410 (changed) and "+" or ""))
1410 (changed) and "+" or ""))
1411 else:
1411 else:
1412 ctx = repo.changectx(rev)
1412 ctx = repo.changectx(rev)
1413 if default or id:
1413 if default or id:
1414 output = [hexfunc(ctx.node())]
1414 output = [hexfunc(ctx.node())]
1415 if num:
1415 if num:
1416 output.append(str(ctx.rev()))
1416 output.append(str(ctx.rev()))
1417
1417
1418 if not source and default and not ui.quiet:
1418 if not source and default and not ui.quiet:
1419 b = util.tolocal(ctx.branch())
1419 b = util.tolocal(ctx.branch())
1420 if b != 'default':
1420 if b != 'default':
1421 output.append("(%s)" % b)
1421 output.append("(%s)" % b)
1422
1422
1423 # multiple tags for a single parent separated by '/'
1423 # multiple tags for a single parent separated by '/'
1424 t = "/".join(ctx.tags())
1424 t = "/".join(ctx.tags())
1425 if t:
1425 if t:
1426 output.append(t)
1426 output.append(t)
1427
1427
1428 if branch:
1428 if branch:
1429 output.append(util.tolocal(ctx.branch()))
1429 output.append(util.tolocal(ctx.branch()))
1430
1430
1431 if tags:
1431 if tags:
1432 output.extend(ctx.tags())
1432 output.extend(ctx.tags())
1433
1433
1434 ui.write("%s\n" % ' '.join(output))
1434 ui.write("%s\n" % ' '.join(output))
1435
1435
1436 def import_(ui, repo, patch1, *patches, **opts):
1436 def import_(ui, repo, patch1, *patches, **opts):
1437 """import an ordered set of patches
1437 """import an ordered set of patches
1438
1438
1439 Import a list of patches and commit them individually.
1439 Import a list of patches and commit them individually.
1440
1440
1441 If there are outstanding changes in the working directory, import
1441 If there are outstanding changes in the working directory, import
1442 will abort unless given the -f flag.
1442 will abort unless given the -f flag.
1443
1443
1444 You can import a patch straight from a mail message. Even patches
1444 You can import a patch straight from a mail message. Even patches
1445 as attachments work (body part must be type text/plain or
1445 as attachments work (body part must be type text/plain or
1446 text/x-patch to be used). From and Subject headers of email
1446 text/x-patch to be used). From and Subject headers of email
1447 message are used as default committer and commit message. All
1447 message are used as default committer and commit message. All
1448 text/plain body parts before first diff are added to commit
1448 text/plain body parts before first diff are added to commit
1449 message.
1449 message.
1450
1450
1451 If the imported patch was generated by hg export, user and description
1451 If the imported patch was generated by hg export, user and description
1452 from patch override values from message headers and body. Values
1452 from patch override values from message headers and body. Values
1453 given on command line with -m and -u override these.
1453 given on command line with -m and -u override these.
1454
1454
1455 If --exact is specified, import will set the working directory
1455 If --exact is specified, import will set the working directory
1456 to the parent of each patch before applying it, and will abort
1456 to the parent of each patch before applying it, and will abort
1457 if the resulting changeset has a different ID than the one
1457 if the resulting changeset has a different ID than the one
1458 recorded in the patch. This may happen due to character set
1458 recorded in the patch. This may happen due to character set
1459 problems or other deficiencies in the text patch format.
1459 problems or other deficiencies in the text patch format.
1460
1460
1461 To read a patch from standard input, use patch name "-".
1461 To read a patch from standard input, use patch name "-".
1462 See 'hg help dates' for a list of formats valid for -d/--date.
1462 See 'hg help dates' for a list of formats valid for -d/--date.
1463 """
1463 """
1464 patches = (patch1,) + patches
1464 patches = (patch1,) + patches
1465
1465
1466 date = opts.get('date')
1466 date = opts.get('date')
1467 if date:
1467 if date:
1468 opts['date'] = util.parsedate(date)
1468 opts['date'] = util.parsedate(date)
1469
1469
1470 if opts.get('exact') or not opts['force']:
1470 if opts.get('exact') or not opts['force']:
1471 cmdutil.bail_if_changed(repo)
1471 cmdutil.bail_if_changed(repo)
1472
1472
1473 d = opts["base"]
1473 d = opts["base"]
1474 strip = opts["strip"]
1474 strip = opts["strip"]
1475 wlock = lock = None
1475 wlock = lock = None
1476 try:
1476 try:
1477 wlock = repo.wlock()
1477 wlock = repo.wlock()
1478 lock = repo.lock()
1478 lock = repo.lock()
1479 for p in patches:
1479 for p in patches:
1480 pf = os.path.join(d, p)
1480 pf = os.path.join(d, p)
1481
1481
1482 if pf == '-':
1482 if pf == '-':
1483 ui.status(_("applying patch from stdin\n"))
1483 ui.status(_("applying patch from stdin\n"))
1484 data = patch.extract(ui, sys.stdin)
1484 data = patch.extract(ui, sys.stdin)
1485 else:
1485 else:
1486 ui.status(_("applying %s\n") % p)
1486 ui.status(_("applying %s\n") % p)
1487 if os.path.exists(pf):
1487 if os.path.exists(pf):
1488 data = patch.extract(ui, file(pf, 'rb'))
1488 data = patch.extract(ui, file(pf, 'rb'))
1489 else:
1489 else:
1490 data = patch.extract(ui, urllib.urlopen(pf))
1490 data = patch.extract(ui, urllib.urlopen(pf))
1491 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1491 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1492
1492
1493 if tmpname is None:
1493 if tmpname is None:
1494 raise util.Abort(_('no diffs found'))
1494 raise util.Abort(_('no diffs found'))
1495
1495
1496 try:
1496 try:
1497 cmdline_message = cmdutil.logmessage(opts)
1497 cmdline_message = cmdutil.logmessage(opts)
1498 if cmdline_message:
1498 if cmdline_message:
1499 # pickup the cmdline msg
1499 # pickup the cmdline msg
1500 message = cmdline_message
1500 message = cmdline_message
1501 elif message:
1501 elif message:
1502 # pickup the patch msg
1502 # pickup the patch msg
1503 message = message.strip()
1503 message = message.strip()
1504 else:
1504 else:
1505 # launch the editor
1505 # launch the editor
1506 message = None
1506 message = None
1507 ui.debug(_('message:\n%s\n') % message)
1507 ui.debug(_('message:\n%s\n') % message)
1508
1508
1509 wp = repo.workingctx().parents()
1509 wp = repo.workingctx().parents()
1510 if opts.get('exact'):
1510 if opts.get('exact'):
1511 if not nodeid or not p1:
1511 if not nodeid or not p1:
1512 raise util.Abort(_('not a mercurial patch'))
1512 raise util.Abort(_('not a mercurial patch'))
1513 p1 = repo.lookup(p1)
1513 p1 = repo.lookup(p1)
1514 p2 = repo.lookup(p2 or hex(nullid))
1514 p2 = repo.lookup(p2 or hex(nullid))
1515
1515
1516 if p1 != wp[0].node():
1516 if p1 != wp[0].node():
1517 hg.clean(repo, p1)
1517 hg.clean(repo, p1)
1518 repo.dirstate.setparents(p1, p2)
1518 repo.dirstate.setparents(p1, p2)
1519 elif p2:
1519 elif p2:
1520 try:
1520 try:
1521 p1 = repo.lookup(p1)
1521 p1 = repo.lookup(p1)
1522 p2 = repo.lookup(p2)
1522 p2 = repo.lookup(p2)
1523 if p1 == wp[0].node():
1523 if p1 == wp[0].node():
1524 repo.dirstate.setparents(p1, p2)
1524 repo.dirstate.setparents(p1, p2)
1525 except hg.RepoError:
1525 except hg.RepoError:
1526 pass
1526 pass
1527 if opts.get('exact') or opts.get('import_branch'):
1527 if opts.get('exact') or opts.get('import_branch'):
1528 repo.dirstate.setbranch(branch or 'default')
1528 repo.dirstate.setbranch(branch or 'default')
1529
1529
1530 files = {}
1530 files = {}
1531 try:
1531 try:
1532 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1532 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1533 files=files)
1533 files=files)
1534 finally:
1534 finally:
1535 files = patch.updatedir(ui, repo, files)
1535 files = patch.updatedir(ui, repo, files)
1536 if not opts.get('no_commit'):
1536 if not opts.get('no_commit'):
1537 n = repo.commit(files, message, opts.get('user') or user,
1537 n = repo.commit(files, message, opts.get('user') or user,
1538 opts.get('date') or date)
1538 opts.get('date') or date)
1539 if opts.get('exact'):
1539 if opts.get('exact'):
1540 if hex(n) != nodeid:
1540 if hex(n) != nodeid:
1541 repo.rollback()
1541 repo.rollback()
1542 raise util.Abort(_('patch is damaged'
1542 raise util.Abort(_('patch is damaged'
1543 ' or loses information'))
1543 ' or loses information'))
1544 # Force a dirstate write so that the next transaction
1544 # Force a dirstate write so that the next transaction
1545 # backups an up-do-date file.
1545 # backups an up-do-date file.
1546 repo.dirstate.write()
1546 repo.dirstate.write()
1547 finally:
1547 finally:
1548 os.unlink(tmpname)
1548 os.unlink(tmpname)
1549 finally:
1549 finally:
1550 del lock, wlock
1550 del lock, wlock
1551
1551
1552 def incoming(ui, repo, source="default", **opts):
1552 def incoming(ui, repo, source="default", **opts):
1553 """show new changesets found in source
1553 """show new changesets found in source
1554
1554
1555 Show new changesets found in the specified path/URL or the default
1555 Show new changesets found in the specified path/URL or the default
1556 pull location. These are the changesets that would be pulled if a pull
1556 pull location. These are the changesets that would be pulled if a pull
1557 was requested.
1557 was requested.
1558
1558
1559 For remote repository, using --bundle avoids downloading the changesets
1559 For remote repository, using --bundle avoids downloading the changesets
1560 twice if the incoming is followed by a pull.
1560 twice if the incoming is followed by a pull.
1561
1561
1562 See pull for valid source format details.
1562 See pull for valid source format details.
1563 """
1563 """
1564 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1564 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1565 cmdutil.setremoteconfig(ui, opts)
1565 cmdutil.setremoteconfig(ui, opts)
1566
1566
1567 other = hg.repository(ui, source)
1567 other = hg.repository(ui, source)
1568 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1568 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1569 if revs:
1569 if revs:
1570 revs = [other.lookup(rev) for rev in revs]
1570 revs = [other.lookup(rev) for rev in revs]
1571 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1571 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1572 if not incoming:
1572 if not incoming:
1573 try:
1573 try:
1574 os.unlink(opts["bundle"])
1574 os.unlink(opts["bundle"])
1575 except:
1575 except:
1576 pass
1576 pass
1577 ui.status(_("no changes found\n"))
1577 ui.status(_("no changes found\n"))
1578 return 1
1578 return 1
1579
1579
1580 cleanup = None
1580 cleanup = None
1581 try:
1581 try:
1582 fname = opts["bundle"]
1582 fname = opts["bundle"]
1583 if fname or not other.local():
1583 if fname or not other.local():
1584 # create a bundle (uncompressed if other repo is not local)
1584 # create a bundle (uncompressed if other repo is not local)
1585 if revs is None:
1585 if revs is None:
1586 cg = other.changegroup(incoming, "incoming")
1586 cg = other.changegroup(incoming, "incoming")
1587 else:
1587 else:
1588 cg = other.changegroupsubset(incoming, revs, 'incoming')
1588 cg = other.changegroupsubset(incoming, revs, 'incoming')
1589 bundletype = other.local() and "HG10BZ" or "HG10UN"
1589 bundletype = other.local() and "HG10BZ" or "HG10UN"
1590 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1590 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1591 # keep written bundle?
1591 # keep written bundle?
1592 if opts["bundle"]:
1592 if opts["bundle"]:
1593 cleanup = None
1593 cleanup = None
1594 if not other.local():
1594 if not other.local():
1595 # use the created uncompressed bundlerepo
1595 # use the created uncompressed bundlerepo
1596 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1596 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1597
1597
1598 o = other.changelog.nodesbetween(incoming, revs)[0]
1598 o = other.changelog.nodesbetween(incoming, revs)[0]
1599 if opts['newest_first']:
1599 if opts['newest_first']:
1600 o.reverse()
1600 o.reverse()
1601 displayer = cmdutil.show_changeset(ui, other, opts)
1601 displayer = cmdutil.show_changeset(ui, other, opts)
1602 for n in o:
1602 for n in o:
1603 parents = [p for p in other.changelog.parents(n) if p != nullid]
1603 parents = [p for p in other.changelog.parents(n) if p != nullid]
1604 if opts['no_merges'] and len(parents) == 2:
1604 if opts['no_merges'] and len(parents) == 2:
1605 continue
1605 continue
1606 displayer.show(changenode=n)
1606 displayer.show(changenode=n)
1607 finally:
1607 finally:
1608 if hasattr(other, 'close'):
1608 if hasattr(other, 'close'):
1609 other.close()
1609 other.close()
1610 if cleanup:
1610 if cleanup:
1611 os.unlink(cleanup)
1611 os.unlink(cleanup)
1612
1612
1613 def init(ui, dest=".", **opts):
1613 def init(ui, dest=".", **opts):
1614 """create a new repository in the given directory
1614 """create a new repository in the given directory
1615
1615
1616 Initialize a new repository in the given directory. If the given
1616 Initialize a new repository in the given directory. If the given
1617 directory does not exist, it is created.
1617 directory does not exist, it is created.
1618
1618
1619 If no directory is given, the current directory is used.
1619 If no directory is given, the current directory is used.
1620
1620
1621 It is possible to specify an ssh:// URL as the destination.
1621 It is possible to specify an ssh:// URL as the destination.
1622 Look at the help text for the pull command for important details
1622 Look at the help text for the pull command for important details
1623 about ssh:// URLs.
1623 about ssh:// URLs.
1624 """
1624 """
1625 cmdutil.setremoteconfig(ui, opts)
1625 cmdutil.setremoteconfig(ui, opts)
1626 hg.repository(ui, dest, create=1)
1626 hg.repository(ui, dest, create=1)
1627
1627
1628 def locate(ui, repo, *pats, **opts):
1628 def locate(ui, repo, *pats, **opts):
1629 """locate files matching specific patterns
1629 """locate files matching specific patterns
1630
1630
1631 Print all files under Mercurial control whose names match the
1631 Print all files under Mercurial control whose names match the
1632 given patterns.
1632 given patterns.
1633
1633
1634 This command searches the entire repository by default. To search
1634 This command searches the entire repository by default. To search
1635 just the current directory and its subdirectories, use
1635 just the current directory and its subdirectories, use
1636 "--include .".
1636 "--include .".
1637
1637
1638 If no patterns are given to match, this command prints all file
1638 If no patterns are given to match, this command prints all file
1639 names.
1639 names.
1640
1640
1641 If you want to feed the output of this command into the "xargs"
1641 If you want to feed the output of this command into the "xargs"
1642 command, use the "-0" option to both this command and "xargs".
1642 command, use the "-0" option to both this command and "xargs".
1643 This will avoid the problem of "xargs" treating single filenames
1643 This will avoid the problem of "xargs" treating single filenames
1644 that contain white space as multiple filenames.
1644 that contain white space as multiple filenames.
1645 """
1645 """
1646 end = opts['print0'] and '\0' or '\n'
1646 end = opts['print0'] and '\0' or '\n'
1647 rev = opts['rev']
1647 rev = opts['rev']
1648 if rev:
1648 if rev:
1649 node = repo.lookup(rev)
1649 node = repo.lookup(rev)
1650 else:
1650 else:
1651 node = None
1651 node = None
1652
1652
1653 ret = 1
1653 ret = 1
1654 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1654 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1655 badmatch=util.always,
1655 badmatch=util.always,
1656 default='relglob'):
1656 default='relglob'):
1657 if src == 'b':
1657 if src == 'b':
1658 continue
1658 continue
1659 if not node and abs not in repo.dirstate:
1659 if not node and abs not in repo.dirstate:
1660 continue
1660 continue
1661 if opts['fullpath']:
1661 if opts['fullpath']:
1662 ui.write(os.path.join(repo.root, abs), end)
1662 ui.write(os.path.join(repo.root, abs), end)
1663 else:
1663 else:
1664 ui.write(((pats and rel) or abs), end)
1664 ui.write(((pats and rel) or abs), end)
1665 ret = 0
1665 ret = 0
1666
1666
1667 return ret
1667 return ret
1668
1668
1669 def log(ui, repo, *pats, **opts):
1669 def log(ui, repo, *pats, **opts):
1670 """show revision history of entire repository or files
1670 """show revision history of entire repository or files
1671
1671
1672 Print the revision history of the specified files or the entire
1672 Print the revision history of the specified files or the entire
1673 project.
1673 project.
1674
1674
1675 File history is shown without following rename or copy history of
1675 File history is shown without following rename or copy history of
1676 files. Use -f/--follow with a file name to follow history across
1676 files. Use -f/--follow with a file name to follow history across
1677 renames and copies. --follow without a file name will only show
1677 renames and copies. --follow without a file name will only show
1678 ancestors or descendants of the starting revision. --follow-first
1678 ancestors or descendants of the starting revision. --follow-first
1679 only follows the first parent of merge revisions.
1679 only follows the first parent of merge revisions.
1680
1680
1681 If no revision range is specified, the default is tip:0 unless
1681 If no revision range is specified, the default is tip:0 unless
1682 --follow is set, in which case the working directory parent is
1682 --follow is set, in which case the working directory parent is
1683 used as the starting revision.
1683 used as the starting revision.
1684
1684
1685 See 'hg help dates' for a list of formats valid for -d/--date.
1685 See 'hg help dates' for a list of formats valid for -d/--date.
1686
1686
1687 By default this command outputs: changeset id and hash, tags,
1687 By default this command outputs: changeset id and hash, tags,
1688 non-trivial parents, user, date and time, and a summary for each
1688 non-trivial parents, user, date and time, and a summary for each
1689 commit. When the -v/--verbose switch is used, the list of changed
1689 commit. When the -v/--verbose switch is used, the list of changed
1690 files and full commit message is shown.
1690 files and full commit message is shown.
1691
1691
1692 NOTE: log -p may generate unexpected diff output for merge
1692 NOTE: log -p may generate unexpected diff output for merge
1693 changesets, as it will compare the merge changeset against its
1693 changesets, as it will compare the merge changeset against its
1694 first parent only. Also, the files: list will only reflect files
1694 first parent only. Also, the files: list will only reflect files
1695 that are different from BOTH parents.
1695 that are different from BOTH parents.
1696
1696
1697 """
1697 """
1698
1698
1699 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1699 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1700 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1700 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1701
1701
1702 if opts['limit']:
1702 limit = cmdutil.loglimit(opts)
1703 try:
1704 limit = int(opts['limit'])
1705 except ValueError:
1706 raise util.Abort(_('limit must be a positive integer'))
1707 if limit <= 0: raise util.Abort(_('limit must be positive'))
1708 else:
1709 limit = sys.maxint
1710 count = 0
1703 count = 0
1711
1704
1712 if opts['copies'] and opts['rev']:
1705 if opts['copies'] and opts['rev']:
1713 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1706 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1714 else:
1707 else:
1715 endrev = repo.changelog.count()
1708 endrev = repo.changelog.count()
1716 rcache = {}
1709 rcache = {}
1717 ncache = {}
1710 ncache = {}
1718 def getrenamed(fn, rev):
1711 def getrenamed(fn, rev):
1719 '''looks up all renames for a file (up to endrev) the first
1712 '''looks up all renames for a file (up to endrev) the first
1720 time the file is given. It indexes on the changerev and only
1713 time the file is given. It indexes on the changerev and only
1721 parses the manifest if linkrev != changerev.
1714 parses the manifest if linkrev != changerev.
1722 Returns rename info for fn at changerev rev.'''
1715 Returns rename info for fn at changerev rev.'''
1723 if fn not in rcache:
1716 if fn not in rcache:
1724 rcache[fn] = {}
1717 rcache[fn] = {}
1725 ncache[fn] = {}
1718 ncache[fn] = {}
1726 fl = repo.file(fn)
1719 fl = repo.file(fn)
1727 for i in xrange(fl.count()):
1720 for i in xrange(fl.count()):
1728 node = fl.node(i)
1721 node = fl.node(i)
1729 lr = fl.linkrev(node)
1722 lr = fl.linkrev(node)
1730 renamed = fl.renamed(node)
1723 renamed = fl.renamed(node)
1731 rcache[fn][lr] = renamed
1724 rcache[fn][lr] = renamed
1732 if renamed:
1725 if renamed:
1733 ncache[fn][node] = renamed
1726 ncache[fn][node] = renamed
1734 if lr >= endrev:
1727 if lr >= endrev:
1735 break
1728 break
1736 if rev in rcache[fn]:
1729 if rev in rcache[fn]:
1737 return rcache[fn][rev]
1730 return rcache[fn][rev]
1738
1731
1739 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1732 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1740 # filectx logic.
1733 # filectx logic.
1741
1734
1742 try:
1735 try:
1743 return repo.changectx(rev).filectx(fn).renamed()
1736 return repo.changectx(rev).filectx(fn).renamed()
1744 except revlog.LookupError:
1737 except revlog.LookupError:
1745 pass
1738 pass
1746 return None
1739 return None
1747
1740
1748 df = False
1741 df = False
1749 if opts["date"]:
1742 if opts["date"]:
1750 df = util.matchdate(opts["date"])
1743 df = util.matchdate(opts["date"])
1751
1744
1752 only_branches = opts['only_branch']
1745 only_branches = opts['only_branch']
1753
1746
1754 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1747 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1755 for st, rev, fns in changeiter:
1748 for st, rev, fns in changeiter:
1756 if st == 'add':
1749 if st == 'add':
1757 changenode = repo.changelog.node(rev)
1750 changenode = repo.changelog.node(rev)
1758 parents = [p for p in repo.changelog.parentrevs(rev)
1751 parents = [p for p in repo.changelog.parentrevs(rev)
1759 if p != nullrev]
1752 if p != nullrev]
1760 if opts['no_merges'] and len(parents) == 2:
1753 if opts['no_merges'] and len(parents) == 2:
1761 continue
1754 continue
1762 if opts['only_merges'] and len(parents) != 2:
1755 if opts['only_merges'] and len(parents) != 2:
1763 continue
1756 continue
1764
1757
1765 if only_branches:
1758 if only_branches:
1766 revbranch = get(rev)[5]['branch']
1759 revbranch = get(rev)[5]['branch']
1767 if revbranch not in only_branches:
1760 if revbranch not in only_branches:
1768 continue
1761 continue
1769
1762
1770 if df:
1763 if df:
1771 changes = get(rev)
1764 changes = get(rev)
1772 if not df(changes[2][0]):
1765 if not df(changes[2][0]):
1773 continue
1766 continue
1774
1767
1775 if opts['keyword']:
1768 if opts['keyword']:
1776 changes = get(rev)
1769 changes = get(rev)
1777 miss = 0
1770 miss = 0
1778 for k in [kw.lower() for kw in opts['keyword']]:
1771 for k in [kw.lower() for kw in opts['keyword']]:
1779 if not (k in changes[1].lower() or
1772 if not (k in changes[1].lower() or
1780 k in changes[4].lower() or
1773 k in changes[4].lower() or
1781 k in " ".join(changes[3]).lower()):
1774 k in " ".join(changes[3]).lower()):
1782 miss = 1
1775 miss = 1
1783 break
1776 break
1784 if miss:
1777 if miss:
1785 continue
1778 continue
1786
1779
1787 copies = []
1780 copies = []
1788 if opts.get('copies') and rev:
1781 if opts.get('copies') and rev:
1789 for fn in get(rev)[3]:
1782 for fn in get(rev)[3]:
1790 rename = getrenamed(fn, rev)
1783 rename = getrenamed(fn, rev)
1791 if rename:
1784 if rename:
1792 copies.append((fn, rename[0]))
1785 copies.append((fn, rename[0]))
1793 displayer.show(rev, changenode, copies=copies)
1786 displayer.show(rev, changenode, copies=copies)
1794 elif st == 'iter':
1787 elif st == 'iter':
1795 if count == limit: break
1788 if count == limit: break
1796 if displayer.flush(rev):
1789 if displayer.flush(rev):
1797 count += 1
1790 count += 1
1798
1791
1799 def manifest(ui, repo, node=None, rev=None):
1792 def manifest(ui, repo, node=None, rev=None):
1800 """output the current or given revision of the project manifest
1793 """output the current or given revision of the project manifest
1801
1794
1802 Print a list of version controlled files for the given revision.
1795 Print a list of version controlled files for the given revision.
1803 If no revision is given, the parent of the working directory is used,
1796 If no revision is given, the parent of the working directory is used,
1804 or tip if no revision is checked out.
1797 or tip if no revision is checked out.
1805
1798
1806 The manifest is the list of files being version controlled. If no revision
1799 The manifest is the list of files being version controlled. If no revision
1807 is given then the first parent of the working directory is used.
1800 is given then the first parent of the working directory is used.
1808
1801
1809 With -v flag, print file permissions, symlink and executable bits. With
1802 With -v flag, print file permissions, symlink and executable bits. With
1810 --debug flag, print file revision hashes.
1803 --debug flag, print file revision hashes.
1811 """
1804 """
1812
1805
1813 if rev and node:
1806 if rev and node:
1814 raise util.Abort(_("please specify just one revision"))
1807 raise util.Abort(_("please specify just one revision"))
1815
1808
1816 if not node:
1809 if not node:
1817 node = rev
1810 node = rev
1818
1811
1819 m = repo.changectx(node).manifest()
1812 m = repo.changectx(node).manifest()
1820 files = m.keys()
1813 files = m.keys()
1821 files.sort()
1814 files.sort()
1822
1815
1823 for f in files:
1816 for f in files:
1824 if ui.debugflag:
1817 if ui.debugflag:
1825 ui.write("%40s " % hex(m[f]))
1818 ui.write("%40s " % hex(m[f]))
1826 if ui.verbose:
1819 if ui.verbose:
1827 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1820 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1828 perm = m.execf(f) and "755" or "644"
1821 perm = m.execf(f) and "755" or "644"
1829 ui.write("%3s %1s " % (perm, type))
1822 ui.write("%3s %1s " % (perm, type))
1830 ui.write("%s\n" % f)
1823 ui.write("%s\n" % f)
1831
1824
1832 def merge(ui, repo, node=None, force=None, rev=None):
1825 def merge(ui, repo, node=None, force=None, rev=None):
1833 """merge working directory with another revision
1826 """merge working directory with another revision
1834
1827
1835 Merge the contents of the current working directory and the
1828 Merge the contents of the current working directory and the
1836 requested revision. Files that changed between either parent are
1829 requested revision. Files that changed between either parent are
1837 marked as changed for the next commit and a commit must be
1830 marked as changed for the next commit and a commit must be
1838 performed before any further updates are allowed.
1831 performed before any further updates are allowed.
1839
1832
1840 If no revision is specified, the working directory's parent is a
1833 If no revision is specified, the working directory's parent is a
1841 head revision, and the repository contains exactly one other head,
1834 head revision, and the repository contains exactly one other head,
1842 the other head is merged with by default. Otherwise, an explicit
1835 the other head is merged with by default. Otherwise, an explicit
1843 revision to merge with must be provided.
1836 revision to merge with must be provided.
1844 """
1837 """
1845
1838
1846 if rev and node:
1839 if rev and node:
1847 raise util.Abort(_("please specify just one revision"))
1840 raise util.Abort(_("please specify just one revision"))
1848 if not node:
1841 if not node:
1849 node = rev
1842 node = rev
1850
1843
1851 if not node:
1844 if not node:
1852 heads = repo.heads()
1845 heads = repo.heads()
1853 if len(heads) > 2:
1846 if len(heads) > 2:
1854 raise util.Abort(_('repo has %d heads - '
1847 raise util.Abort(_('repo has %d heads - '
1855 'please merge with an explicit rev') %
1848 'please merge with an explicit rev') %
1856 len(heads))
1849 len(heads))
1857 parent = repo.dirstate.parents()[0]
1850 parent = repo.dirstate.parents()[0]
1858 if len(heads) == 1:
1851 if len(heads) == 1:
1859 msg = _('there is nothing to merge')
1852 msg = _('there is nothing to merge')
1860 if parent != repo.lookup(repo.workingctx().branch()):
1853 if parent != repo.lookup(repo.workingctx().branch()):
1861 msg = _('%s - use "hg update" instead') % msg
1854 msg = _('%s - use "hg update" instead') % msg
1862 raise util.Abort(msg)
1855 raise util.Abort(msg)
1863
1856
1864 if parent not in heads:
1857 if parent not in heads:
1865 raise util.Abort(_('working dir not at a head rev - '
1858 raise util.Abort(_('working dir not at a head rev - '
1866 'use "hg update" or merge with an explicit rev'))
1859 'use "hg update" or merge with an explicit rev'))
1867 node = parent == heads[0] and heads[-1] or heads[0]
1860 node = parent == heads[0] and heads[-1] or heads[0]
1868 return hg.merge(repo, node, force=force)
1861 return hg.merge(repo, node, force=force)
1869
1862
1870 def outgoing(ui, repo, dest=None, **opts):
1863 def outgoing(ui, repo, dest=None, **opts):
1871 """show changesets not found in destination
1864 """show changesets not found in destination
1872
1865
1873 Show changesets not found in the specified destination repository or
1866 Show changesets not found in the specified destination repository or
1874 the default push location. These are the changesets that would be pushed
1867 the default push location. These are the changesets that would be pushed
1875 if a push was requested.
1868 if a push was requested.
1876
1869
1877 See pull for valid destination format details.
1870 See pull for valid destination format details.
1878 """
1871 """
1879 dest, revs, checkout = hg.parseurl(
1872 dest, revs, checkout = hg.parseurl(
1880 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1873 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1881 cmdutil.setremoteconfig(ui, opts)
1874 cmdutil.setremoteconfig(ui, opts)
1882 if revs:
1875 if revs:
1883 revs = [repo.lookup(rev) for rev in revs]
1876 revs = [repo.lookup(rev) for rev in revs]
1884
1877
1885 other = hg.repository(ui, dest)
1878 other = hg.repository(ui, dest)
1886 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1879 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1887 o = repo.findoutgoing(other, force=opts['force'])
1880 o = repo.findoutgoing(other, force=opts['force'])
1888 if not o:
1881 if not o:
1889 ui.status(_("no changes found\n"))
1882 ui.status(_("no changes found\n"))
1890 return 1
1883 return 1
1891 o = repo.changelog.nodesbetween(o, revs)[0]
1884 o = repo.changelog.nodesbetween(o, revs)[0]
1892 if opts['newest_first']:
1885 if opts['newest_first']:
1893 o.reverse()
1886 o.reverse()
1894 displayer = cmdutil.show_changeset(ui, repo, opts)
1887 displayer = cmdutil.show_changeset(ui, repo, opts)
1895 for n in o:
1888 for n in o:
1896 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1889 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1897 if opts['no_merges'] and len(parents) == 2:
1890 if opts['no_merges'] and len(parents) == 2:
1898 continue
1891 continue
1899 displayer.show(changenode=n)
1892 displayer.show(changenode=n)
1900
1893
1901 def parents(ui, repo, file_=None, **opts):
1894 def parents(ui, repo, file_=None, **opts):
1902 """show the parents of the working dir or revision
1895 """show the parents of the working dir or revision
1903
1896
1904 Print the working directory's parent revisions. If a
1897 Print the working directory's parent revisions. If a
1905 revision is given via --rev, the parent of that revision
1898 revision is given via --rev, the parent of that revision
1906 will be printed. If a file argument is given, revision in
1899 will be printed. If a file argument is given, revision in
1907 which the file was last changed (before the working directory
1900 which the file was last changed (before the working directory
1908 revision or the argument to --rev if given) is printed.
1901 revision or the argument to --rev if given) is printed.
1909 """
1902 """
1910 rev = opts.get('rev')
1903 rev = opts.get('rev')
1911 if rev:
1904 if rev:
1912 ctx = repo.changectx(rev)
1905 ctx = repo.changectx(rev)
1913 else:
1906 else:
1914 ctx = repo.workingctx()
1907 ctx = repo.workingctx()
1915
1908
1916 if file_:
1909 if file_:
1917 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1910 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1918 if anypats or len(files) != 1:
1911 if anypats or len(files) != 1:
1919 raise util.Abort(_('can only specify an explicit file name'))
1912 raise util.Abort(_('can only specify an explicit file name'))
1920 file_ = files[0]
1913 file_ = files[0]
1921 filenodes = []
1914 filenodes = []
1922 for cp in ctx.parents():
1915 for cp in ctx.parents():
1923 if not cp:
1916 if not cp:
1924 continue
1917 continue
1925 try:
1918 try:
1926 filenodes.append(cp.filenode(file_))
1919 filenodes.append(cp.filenode(file_))
1927 except revlog.LookupError:
1920 except revlog.LookupError:
1928 pass
1921 pass
1929 if not filenodes:
1922 if not filenodes:
1930 raise util.Abort(_("'%s' not found in manifest!") % file_)
1923 raise util.Abort(_("'%s' not found in manifest!") % file_)
1931 fl = repo.file(file_)
1924 fl = repo.file(file_)
1932 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1925 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1933 else:
1926 else:
1934 p = [cp.node() for cp in ctx.parents()]
1927 p = [cp.node() for cp in ctx.parents()]
1935
1928
1936 displayer = cmdutil.show_changeset(ui, repo, opts)
1929 displayer = cmdutil.show_changeset(ui, repo, opts)
1937 for n in p:
1930 for n in p:
1938 if n != nullid:
1931 if n != nullid:
1939 displayer.show(changenode=n)
1932 displayer.show(changenode=n)
1940
1933
1941 def paths(ui, repo, search=None):
1934 def paths(ui, repo, search=None):
1942 """show definition of symbolic path names
1935 """show definition of symbolic path names
1943
1936
1944 Show definition of symbolic path name NAME. If no name is given, show
1937 Show definition of symbolic path name NAME. If no name is given, show
1945 definition of available names.
1938 definition of available names.
1946
1939
1947 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1940 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1948 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1941 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1949 """
1942 """
1950 if search:
1943 if search:
1951 for name, path in ui.configitems("paths"):
1944 for name, path in ui.configitems("paths"):
1952 if name == search:
1945 if name == search:
1953 ui.write("%s\n" % path)
1946 ui.write("%s\n" % path)
1954 return
1947 return
1955 ui.warn(_("not found!\n"))
1948 ui.warn(_("not found!\n"))
1956 return 1
1949 return 1
1957 else:
1950 else:
1958 for name, path in ui.configitems("paths"):
1951 for name, path in ui.configitems("paths"):
1959 ui.write("%s = %s\n" % (name, path))
1952 ui.write("%s = %s\n" % (name, path))
1960
1953
1961 def postincoming(ui, repo, modheads, optupdate, checkout):
1954 def postincoming(ui, repo, modheads, optupdate, checkout):
1962 if modheads == 0:
1955 if modheads == 0:
1963 return
1956 return
1964 if optupdate:
1957 if optupdate:
1965 if modheads <= 1 or checkout:
1958 if modheads <= 1 or checkout:
1966 return hg.update(repo, checkout)
1959 return hg.update(repo, checkout)
1967 else:
1960 else:
1968 ui.status(_("not updating, since new heads added\n"))
1961 ui.status(_("not updating, since new heads added\n"))
1969 if modheads > 1:
1962 if modheads > 1:
1970 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1963 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1971 else:
1964 else:
1972 ui.status(_("(run 'hg update' to get a working copy)\n"))
1965 ui.status(_("(run 'hg update' to get a working copy)\n"))
1973
1966
1974 def pull(ui, repo, source="default", **opts):
1967 def pull(ui, repo, source="default", **opts):
1975 """pull changes from the specified source
1968 """pull changes from the specified source
1976
1969
1977 Pull changes from a remote repository to a local one.
1970 Pull changes from a remote repository to a local one.
1978
1971
1979 This finds all changes from the repository at the specified path
1972 This finds all changes from the repository at the specified path
1980 or URL and adds them to the local repository. By default, this
1973 or URL and adds them to the local repository. By default, this
1981 does not update the copy of the project in the working directory.
1974 does not update the copy of the project in the working directory.
1982
1975
1983 Valid URLs are of the form:
1976 Valid URLs are of the form:
1984
1977
1985 local/filesystem/path (or file://local/filesystem/path)
1978 local/filesystem/path (or file://local/filesystem/path)
1986 http://[user@]host[:port]/[path]
1979 http://[user@]host[:port]/[path]
1987 https://[user@]host[:port]/[path]
1980 https://[user@]host[:port]/[path]
1988 ssh://[user@]host[:port]/[path]
1981 ssh://[user@]host[:port]/[path]
1989 static-http://host[:port]/[path]
1982 static-http://host[:port]/[path]
1990
1983
1991 Paths in the local filesystem can either point to Mercurial
1984 Paths in the local filesystem can either point to Mercurial
1992 repositories or to bundle files (as created by 'hg bundle' or
1985 repositories or to bundle files (as created by 'hg bundle' or
1993 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1986 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1994 allows access to a Mercurial repository where you simply use a web
1987 allows access to a Mercurial repository where you simply use a web
1995 server to publish the .hg directory as static content.
1988 server to publish the .hg directory as static content.
1996
1989
1997 An optional identifier after # indicates a particular branch, tag,
1990 An optional identifier after # indicates a particular branch, tag,
1998 or changeset to pull.
1991 or changeset to pull.
1999
1992
2000 Some notes about using SSH with Mercurial:
1993 Some notes about using SSH with Mercurial:
2001 - SSH requires an accessible shell account on the destination machine
1994 - SSH requires an accessible shell account on the destination machine
2002 and a copy of hg in the remote path or specified with as remotecmd.
1995 and a copy of hg in the remote path or specified with as remotecmd.
2003 - path is relative to the remote user's home directory by default.
1996 - path is relative to the remote user's home directory by default.
2004 Use an extra slash at the start of a path to specify an absolute path:
1997 Use an extra slash at the start of a path to specify an absolute path:
2005 ssh://example.com//tmp/repository
1998 ssh://example.com//tmp/repository
2006 - Mercurial doesn't use its own compression via SSH; the right thing
1999 - Mercurial doesn't use its own compression via SSH; the right thing
2007 to do is to configure it in your ~/.ssh/config, e.g.:
2000 to do is to configure it in your ~/.ssh/config, e.g.:
2008 Host *.mylocalnetwork.example.com
2001 Host *.mylocalnetwork.example.com
2009 Compression no
2002 Compression no
2010 Host *
2003 Host *
2011 Compression yes
2004 Compression yes
2012 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2005 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2013 with the --ssh command line option.
2006 with the --ssh command line option.
2014 """
2007 """
2015 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2008 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2016 cmdutil.setremoteconfig(ui, opts)
2009 cmdutil.setremoteconfig(ui, opts)
2017
2010
2018 other = hg.repository(ui, source)
2011 other = hg.repository(ui, source)
2019 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2012 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2020 if revs:
2013 if revs:
2021 try:
2014 try:
2022 revs = [other.lookup(rev) for rev in revs]
2015 revs = [other.lookup(rev) for rev in revs]
2023 except repo.NoCapability:
2016 except repo.NoCapability:
2024 error = _("Other repository doesn't support revision lookup, "
2017 error = _("Other repository doesn't support revision lookup, "
2025 "so a rev cannot be specified.")
2018 "so a rev cannot be specified.")
2026 raise util.Abort(error)
2019 raise util.Abort(error)
2027
2020
2028 modheads = repo.pull(other, heads=revs, force=opts['force'])
2021 modheads = repo.pull(other, heads=revs, force=opts['force'])
2029 return postincoming(ui, repo, modheads, opts['update'], checkout)
2022 return postincoming(ui, repo, modheads, opts['update'], checkout)
2030
2023
2031 def push(ui, repo, dest=None, **opts):
2024 def push(ui, repo, dest=None, **opts):
2032 """push changes to the specified destination
2025 """push changes to the specified destination
2033
2026
2034 Push changes from the local repository to the given destination.
2027 Push changes from the local repository to the given destination.
2035
2028
2036 This is the symmetrical operation for pull. It helps to move
2029 This is the symmetrical operation for pull. It helps to move
2037 changes from the current repository to a different one. If the
2030 changes from the current repository to a different one. If the
2038 destination is local this is identical to a pull in that directory
2031 destination is local this is identical to a pull in that directory
2039 from the current one.
2032 from the current one.
2040
2033
2041 By default, push will refuse to run if it detects the result would
2034 By default, push will refuse to run if it detects the result would
2042 increase the number of remote heads. This generally indicates the
2035 increase the number of remote heads. This generally indicates the
2043 the client has forgotten to sync and merge before pushing.
2036 the client has forgotten to sync and merge before pushing.
2044
2037
2045 Valid URLs are of the form:
2038 Valid URLs are of the form:
2046
2039
2047 local/filesystem/path (or file://local/filesystem/path)
2040 local/filesystem/path (or file://local/filesystem/path)
2048 ssh://[user@]host[:port]/[path]
2041 ssh://[user@]host[:port]/[path]
2049 http://[user@]host[:port]/[path]
2042 http://[user@]host[:port]/[path]
2050 https://[user@]host[:port]/[path]
2043 https://[user@]host[:port]/[path]
2051
2044
2052 An optional identifier after # indicates a particular branch, tag,
2045 An optional identifier after # indicates a particular branch, tag,
2053 or changeset to push.
2046 or changeset to push.
2054
2047
2055 Look at the help text for the pull command for important details
2048 Look at the help text for the pull command for important details
2056 about ssh:// URLs.
2049 about ssh:// URLs.
2057
2050
2058 Pushing to http:// and https:// URLs is only possible, if this
2051 Pushing to http:// and https:// URLs is only possible, if this
2059 feature is explicitly enabled on the remote Mercurial server.
2052 feature is explicitly enabled on the remote Mercurial server.
2060 """
2053 """
2061 dest, revs, checkout = hg.parseurl(
2054 dest, revs, checkout = hg.parseurl(
2062 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2055 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2063 cmdutil.setremoteconfig(ui, opts)
2056 cmdutil.setremoteconfig(ui, opts)
2064
2057
2065 other = hg.repository(ui, dest)
2058 other = hg.repository(ui, dest)
2066 ui.status('pushing to %s\n' % util.hidepassword(dest))
2059 ui.status('pushing to %s\n' % util.hidepassword(dest))
2067 if revs:
2060 if revs:
2068 revs = [repo.lookup(rev) for rev in revs]
2061 revs = [repo.lookup(rev) for rev in revs]
2069 r = repo.push(other, opts['force'], revs=revs)
2062 r = repo.push(other, opts['force'], revs=revs)
2070 return r == 0
2063 return r == 0
2071
2064
2072 def rawcommit(ui, repo, *pats, **opts):
2065 def rawcommit(ui, repo, *pats, **opts):
2073 """raw commit interface (DEPRECATED)
2066 """raw commit interface (DEPRECATED)
2074
2067
2075 (DEPRECATED)
2068 (DEPRECATED)
2076 Lowlevel commit, for use in helper scripts.
2069 Lowlevel commit, for use in helper scripts.
2077
2070
2078 This command is not intended to be used by normal users, as it is
2071 This command is not intended to be used by normal users, as it is
2079 primarily useful for importing from other SCMs.
2072 primarily useful for importing from other SCMs.
2080
2073
2081 This command is now deprecated and will be removed in a future
2074 This command is now deprecated and will be removed in a future
2082 release, please use debugsetparents and commit instead.
2075 release, please use debugsetparents and commit instead.
2083 """
2076 """
2084
2077
2085 ui.warn(_("(the rawcommit command is deprecated)\n"))
2078 ui.warn(_("(the rawcommit command is deprecated)\n"))
2086
2079
2087 message = cmdutil.logmessage(opts)
2080 message = cmdutil.logmessage(opts)
2088
2081
2089 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2082 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2090 if opts['files']:
2083 if opts['files']:
2091 files += open(opts['files']).read().splitlines()
2084 files += open(opts['files']).read().splitlines()
2092
2085
2093 parents = [repo.lookup(p) for p in opts['parent']]
2086 parents = [repo.lookup(p) for p in opts['parent']]
2094
2087
2095 try:
2088 try:
2096 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2089 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2097 except ValueError, inst:
2090 except ValueError, inst:
2098 raise util.Abort(str(inst))
2091 raise util.Abort(str(inst))
2099
2092
2100 def recover(ui, repo):
2093 def recover(ui, repo):
2101 """roll back an interrupted transaction
2094 """roll back an interrupted transaction
2102
2095
2103 Recover from an interrupted commit or pull.
2096 Recover from an interrupted commit or pull.
2104
2097
2105 This command tries to fix the repository status after an interrupted
2098 This command tries to fix the repository status after an interrupted
2106 operation. It should only be necessary when Mercurial suggests it.
2099 operation. It should only be necessary when Mercurial suggests it.
2107 """
2100 """
2108 if repo.recover():
2101 if repo.recover():
2109 return hg.verify(repo)
2102 return hg.verify(repo)
2110 return 1
2103 return 1
2111
2104
2112 def remove(ui, repo, *pats, **opts):
2105 def remove(ui, repo, *pats, **opts):
2113 """remove the specified files on the next commit
2106 """remove the specified files on the next commit
2114
2107
2115 Schedule the indicated files for removal from the repository.
2108 Schedule the indicated files for removal from the repository.
2116
2109
2117 This only removes files from the current branch, not from the
2110 This only removes files from the current branch, not from the
2118 entire project history. If the files still exist in the working
2111 entire project history. If the files still exist in the working
2119 directory, they will be deleted from it. If invoked with --after,
2112 directory, they will be deleted from it. If invoked with --after,
2120 files are marked as removed, but not actually unlinked unless --force
2113 files are marked as removed, but not actually unlinked unless --force
2121 is also given. Without exact file names, --after will only mark
2114 is also given. Without exact file names, --after will only mark
2122 files as removed if they are no longer in the working directory.
2115 files as removed if they are no longer in the working directory.
2123
2116
2124 This command schedules the files to be removed at the next commit.
2117 This command schedules the files to be removed at the next commit.
2125 To undo a remove before that, see hg revert.
2118 To undo a remove before that, see hg revert.
2126
2119
2127 Modified files and added files are not removed by default. To
2120 Modified files and added files are not removed by default. To
2128 remove them, use the -f/--force option.
2121 remove them, use the -f/--force option.
2129 """
2122 """
2130 if not opts['after'] and not pats:
2123 if not opts['after'] and not pats:
2131 raise util.Abort(_('no files specified'))
2124 raise util.Abort(_('no files specified'))
2132 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2125 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2133 exact = dict.fromkeys(files)
2126 exact = dict.fromkeys(files)
2134 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2127 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2135 modified, added, removed, deleted, unknown = mardu
2128 modified, added, removed, deleted, unknown = mardu
2136 remove, forget = [], []
2129 remove, forget = [], []
2137 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2130 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2138 reason = None
2131 reason = None
2139 if abs in modified and not opts['force']:
2132 if abs in modified and not opts['force']:
2140 reason = _('is modified (use -f to force removal)')
2133 reason = _('is modified (use -f to force removal)')
2141 elif abs in added:
2134 elif abs in added:
2142 if opts['force']:
2135 if opts['force']:
2143 forget.append(abs)
2136 forget.append(abs)
2144 continue
2137 continue
2145 reason = _('has been marked for add (use -f to force removal)')
2138 reason = _('has been marked for add (use -f to force removal)')
2146 exact = 1 # force the message
2139 exact = 1 # force the message
2147 elif abs not in repo.dirstate:
2140 elif abs not in repo.dirstate:
2148 reason = _('is not managed')
2141 reason = _('is not managed')
2149 elif opts['after'] and not exact and abs not in deleted:
2142 elif opts['after'] and not exact and abs not in deleted:
2150 continue
2143 continue
2151 elif abs in removed:
2144 elif abs in removed:
2152 continue
2145 continue
2153 if reason:
2146 if reason:
2154 if exact:
2147 if exact:
2155 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2148 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2156 else:
2149 else:
2157 if ui.verbose or not exact:
2150 if ui.verbose or not exact:
2158 ui.status(_('removing %s\n') % rel)
2151 ui.status(_('removing %s\n') % rel)
2159 remove.append(abs)
2152 remove.append(abs)
2160 repo.forget(forget)
2153 repo.forget(forget)
2161 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2154 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2162
2155
2163 def rename(ui, repo, *pats, **opts):
2156 def rename(ui, repo, *pats, **opts):
2164 """rename files; equivalent of copy + remove
2157 """rename files; equivalent of copy + remove
2165
2158
2166 Mark dest as copies of sources; mark sources for deletion. If
2159 Mark dest as copies of sources; mark sources for deletion. If
2167 dest is a directory, copies are put in that directory. If dest is
2160 dest is a directory, copies are put in that directory. If dest is
2168 a file, there can only be one source.
2161 a file, there can only be one source.
2169
2162
2170 By default, this command copies the contents of files as they
2163 By default, this command copies the contents of files as they
2171 stand in the working directory. If invoked with --after, the
2164 stand in the working directory. If invoked with --after, the
2172 operation is recorded, but no copying is performed.
2165 operation is recorded, but no copying is performed.
2173
2166
2174 This command takes effect in the next commit. To undo a rename
2167 This command takes effect in the next commit. To undo a rename
2175 before that, see hg revert.
2168 before that, see hg revert.
2176 """
2169 """
2177 wlock = repo.wlock(False)
2170 wlock = repo.wlock(False)
2178 try:
2171 try:
2179 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2172 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2180 finally:
2173 finally:
2181 del wlock
2174 del wlock
2182
2175
2183 def revert(ui, repo, *pats, **opts):
2176 def revert(ui, repo, *pats, **opts):
2184 """restore individual files or dirs to an earlier state
2177 """restore individual files or dirs to an earlier state
2185
2178
2186 (use update -r to check out earlier revisions, revert does not
2179 (use update -r to check out earlier revisions, revert does not
2187 change the working dir parents)
2180 change the working dir parents)
2188
2181
2189 With no revision specified, revert the named files or directories
2182 With no revision specified, revert the named files or directories
2190 to the contents they had in the parent of the working directory.
2183 to the contents they had in the parent of the working directory.
2191 This restores the contents of the affected files to an unmodified
2184 This restores the contents of the affected files to an unmodified
2192 state and unschedules adds, removes, copies, and renames. If the
2185 state and unschedules adds, removes, copies, and renames. If the
2193 working directory has two parents, you must explicitly specify the
2186 working directory has two parents, you must explicitly specify the
2194 revision to revert to.
2187 revision to revert to.
2195
2188
2196 Using the -r option, revert the given files or directories to their
2189 Using the -r option, revert the given files or directories to their
2197 contents as of a specific revision. This can be helpful to "roll
2190 contents as of a specific revision. This can be helpful to "roll
2198 back" some or all of an earlier change.
2191 back" some or all of an earlier change.
2199 See 'hg help dates' for a list of formats valid for -d/--date.
2192 See 'hg help dates' for a list of formats valid for -d/--date.
2200
2193
2201 Revert modifies the working directory. It does not commit any
2194 Revert modifies the working directory. It does not commit any
2202 changes, or change the parent of the working directory. If you
2195 changes, or change the parent of the working directory. If you
2203 revert to a revision other than the parent of the working
2196 revert to a revision other than the parent of the working
2204 directory, the reverted files will thus appear modified
2197 directory, the reverted files will thus appear modified
2205 afterwards.
2198 afterwards.
2206
2199
2207 If a file has been deleted, it is restored. If the executable
2200 If a file has been deleted, it is restored. If the executable
2208 mode of a file was changed, it is reset.
2201 mode of a file was changed, it is reset.
2209
2202
2210 If names are given, all files matching the names are reverted.
2203 If names are given, all files matching the names are reverted.
2211 If no arguments are given, no files are reverted.
2204 If no arguments are given, no files are reverted.
2212
2205
2213 Modified files are saved with a .orig suffix before reverting.
2206 Modified files are saved with a .orig suffix before reverting.
2214 To disable these backups, use --no-backup.
2207 To disable these backups, use --no-backup.
2215 """
2208 """
2216
2209
2217 if opts["date"]:
2210 if opts["date"]:
2218 if opts["rev"]:
2211 if opts["rev"]:
2219 raise util.Abort(_("you can't specify a revision and a date"))
2212 raise util.Abort(_("you can't specify a revision and a date"))
2220 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2213 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2221
2214
2222 if not pats and not opts['all']:
2215 if not pats and not opts['all']:
2223 raise util.Abort(_('no files or directories specified; '
2216 raise util.Abort(_('no files or directories specified; '
2224 'use --all to revert the whole repo'))
2217 'use --all to revert the whole repo'))
2225
2218
2226 parent, p2 = repo.dirstate.parents()
2219 parent, p2 = repo.dirstate.parents()
2227 if not opts['rev'] and p2 != nullid:
2220 if not opts['rev'] and p2 != nullid:
2228 raise util.Abort(_('uncommitted merge - please provide a '
2221 raise util.Abort(_('uncommitted merge - please provide a '
2229 'specific revision'))
2222 'specific revision'))
2230 ctx = repo.changectx(opts['rev'])
2223 ctx = repo.changectx(opts['rev'])
2231 node = ctx.node()
2224 node = ctx.node()
2232 mf = ctx.manifest()
2225 mf = ctx.manifest()
2233 if node == parent:
2226 if node == parent:
2234 pmf = mf
2227 pmf = mf
2235 else:
2228 else:
2236 pmf = None
2229 pmf = None
2237
2230
2238 # need all matching names in dirstate and manifest of target rev,
2231 # need all matching names in dirstate and manifest of target rev,
2239 # so have to walk both. do not print errors if files exist in one
2232 # so have to walk both. do not print errors if files exist in one
2240 # but not other.
2233 # but not other.
2241
2234
2242 names = {}
2235 names = {}
2243
2236
2244 wlock = repo.wlock()
2237 wlock = repo.wlock()
2245 try:
2238 try:
2246 # walk dirstate.
2239 # walk dirstate.
2247 files = []
2240 files = []
2248 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2241 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2249 badmatch=mf.has_key):
2242 badmatch=mf.has_key):
2250 names[abs] = (rel, exact)
2243 names[abs] = (rel, exact)
2251 if src != 'b':
2244 if src != 'b':
2252 files.append(abs)
2245 files.append(abs)
2253
2246
2254 # walk target manifest.
2247 # walk target manifest.
2255
2248
2256 def badmatch(path):
2249 def badmatch(path):
2257 if path in names:
2250 if path in names:
2258 return True
2251 return True
2259 path_ = path + '/'
2252 path_ = path + '/'
2260 for f in names:
2253 for f in names:
2261 if f.startswith(path_):
2254 if f.startswith(path_):
2262 return True
2255 return True
2263 return False
2256 return False
2264
2257
2265 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2258 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2266 badmatch=badmatch):
2259 badmatch=badmatch):
2267 if abs in names or src == 'b':
2260 if abs in names or src == 'b':
2268 continue
2261 continue
2269 names[abs] = (rel, exact)
2262 names[abs] = (rel, exact)
2270
2263
2271 changes = repo.status(files=files, match=names.has_key)[:4]
2264 changes = repo.status(files=files, match=names.has_key)[:4]
2272 modified, added, removed, deleted = map(dict.fromkeys, changes)
2265 modified, added, removed, deleted = map(dict.fromkeys, changes)
2273
2266
2274 # if f is a rename, also revert the source
2267 # if f is a rename, also revert the source
2275 cwd = repo.getcwd()
2268 cwd = repo.getcwd()
2276 for f in added:
2269 for f in added:
2277 src = repo.dirstate.copied(f)
2270 src = repo.dirstate.copied(f)
2278 if src and src not in names and repo.dirstate[src] == 'r':
2271 if src and src not in names and repo.dirstate[src] == 'r':
2279 removed[src] = None
2272 removed[src] = None
2280 names[src] = (repo.pathto(src, cwd), True)
2273 names[src] = (repo.pathto(src, cwd), True)
2281
2274
2282 def removeforget(abs):
2275 def removeforget(abs):
2283 if repo.dirstate[abs] == 'a':
2276 if repo.dirstate[abs] == 'a':
2284 return _('forgetting %s\n')
2277 return _('forgetting %s\n')
2285 return _('removing %s\n')
2278 return _('removing %s\n')
2286
2279
2287 revert = ([], _('reverting %s\n'))
2280 revert = ([], _('reverting %s\n'))
2288 add = ([], _('adding %s\n'))
2281 add = ([], _('adding %s\n'))
2289 remove = ([], removeforget)
2282 remove = ([], removeforget)
2290 undelete = ([], _('undeleting %s\n'))
2283 undelete = ([], _('undeleting %s\n'))
2291
2284
2292 disptable = (
2285 disptable = (
2293 # dispatch table:
2286 # dispatch table:
2294 # file state
2287 # file state
2295 # action if in target manifest
2288 # action if in target manifest
2296 # action if not in target manifest
2289 # action if not in target manifest
2297 # make backup if in target manifest
2290 # make backup if in target manifest
2298 # make backup if not in target manifest
2291 # make backup if not in target manifest
2299 (modified, revert, remove, True, True),
2292 (modified, revert, remove, True, True),
2300 (added, revert, remove, True, False),
2293 (added, revert, remove, True, False),
2301 (removed, undelete, None, False, False),
2294 (removed, undelete, None, False, False),
2302 (deleted, revert, remove, False, False),
2295 (deleted, revert, remove, False, False),
2303 )
2296 )
2304
2297
2305 entries = names.items()
2298 entries = names.items()
2306 entries.sort()
2299 entries.sort()
2307
2300
2308 for abs, (rel, exact) in entries:
2301 for abs, (rel, exact) in entries:
2309 mfentry = mf.get(abs)
2302 mfentry = mf.get(abs)
2310 target = repo.wjoin(abs)
2303 target = repo.wjoin(abs)
2311 def handle(xlist, dobackup):
2304 def handle(xlist, dobackup):
2312 xlist[0].append(abs)
2305 xlist[0].append(abs)
2313 if dobackup and not opts['no_backup'] and util.lexists(target):
2306 if dobackup and not opts['no_backup'] and util.lexists(target):
2314 bakname = "%s.orig" % rel
2307 bakname = "%s.orig" % rel
2315 ui.note(_('saving current version of %s as %s\n') %
2308 ui.note(_('saving current version of %s as %s\n') %
2316 (rel, bakname))
2309 (rel, bakname))
2317 if not opts.get('dry_run'):
2310 if not opts.get('dry_run'):
2318 util.copyfile(target, bakname)
2311 util.copyfile(target, bakname)
2319 if ui.verbose or not exact:
2312 if ui.verbose or not exact:
2320 msg = xlist[1]
2313 msg = xlist[1]
2321 if not isinstance(msg, basestring):
2314 if not isinstance(msg, basestring):
2322 msg = msg(abs)
2315 msg = msg(abs)
2323 ui.status(msg % rel)
2316 ui.status(msg % rel)
2324 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2317 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2325 if abs not in table: continue
2318 if abs not in table: continue
2326 # file has changed in dirstate
2319 # file has changed in dirstate
2327 if mfentry:
2320 if mfentry:
2328 handle(hitlist, backuphit)
2321 handle(hitlist, backuphit)
2329 elif misslist is not None:
2322 elif misslist is not None:
2330 handle(misslist, backupmiss)
2323 handle(misslist, backupmiss)
2331 break
2324 break
2332 else:
2325 else:
2333 if abs not in repo.dirstate:
2326 if abs not in repo.dirstate:
2334 if mfentry:
2327 if mfentry:
2335 handle(add, True)
2328 handle(add, True)
2336 elif exact:
2329 elif exact:
2337 ui.warn(_('file not managed: %s\n') % rel)
2330 ui.warn(_('file not managed: %s\n') % rel)
2338 continue
2331 continue
2339 # file has not changed in dirstate
2332 # file has not changed in dirstate
2340 if node == parent:
2333 if node == parent:
2341 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2334 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2342 continue
2335 continue
2343 if pmf is None:
2336 if pmf is None:
2344 # only need parent manifest in this unlikely case,
2337 # only need parent manifest in this unlikely case,
2345 # so do not read by default
2338 # so do not read by default
2346 pmf = repo.changectx(parent).manifest()
2339 pmf = repo.changectx(parent).manifest()
2347 if abs in pmf:
2340 if abs in pmf:
2348 if mfentry:
2341 if mfentry:
2349 # if version of file is same in parent and target
2342 # if version of file is same in parent and target
2350 # manifests, do nothing
2343 # manifests, do nothing
2351 if (pmf[abs] != mfentry or
2344 if (pmf[abs] != mfentry or
2352 pmf.flags(abs) != mf.flags(abs)):
2345 pmf.flags(abs) != mf.flags(abs)):
2353 handle(revert, False)
2346 handle(revert, False)
2354 else:
2347 else:
2355 handle(remove, False)
2348 handle(remove, False)
2356
2349
2357 if not opts.get('dry_run'):
2350 if not opts.get('dry_run'):
2358 def checkout(f):
2351 def checkout(f):
2359 fc = ctx[f]
2352 fc = ctx[f]
2360 repo.wwrite(f, fc.data(), fc.fileflags())
2353 repo.wwrite(f, fc.data(), fc.fileflags())
2361
2354
2362 audit_path = util.path_auditor(repo.root)
2355 audit_path = util.path_auditor(repo.root)
2363 for f in remove[0]:
2356 for f in remove[0]:
2364 if repo.dirstate[f] == 'a':
2357 if repo.dirstate[f] == 'a':
2365 repo.dirstate.forget(f)
2358 repo.dirstate.forget(f)
2366 continue
2359 continue
2367 audit_path(f)
2360 audit_path(f)
2368 try:
2361 try:
2369 util.unlink(repo.wjoin(f))
2362 util.unlink(repo.wjoin(f))
2370 except OSError:
2363 except OSError:
2371 pass
2364 pass
2372 repo.dirstate.remove(f)
2365 repo.dirstate.remove(f)
2373
2366
2374 for f in revert[0]:
2367 for f in revert[0]:
2375 checkout(f)
2368 checkout(f)
2376
2369
2377 for f in add[0]:
2370 for f in add[0]:
2378 checkout(f)
2371 checkout(f)
2379 repo.dirstate.add(f)
2372 repo.dirstate.add(f)
2380
2373
2381 normal = repo.dirstate.normallookup
2374 normal = repo.dirstate.normallookup
2382 if node == parent and p2 == nullid:
2375 if node == parent and p2 == nullid:
2383 normal = repo.dirstate.normal
2376 normal = repo.dirstate.normal
2384 for f in undelete[0]:
2377 for f in undelete[0]:
2385 checkout(f)
2378 checkout(f)
2386 normal(f)
2379 normal(f)
2387
2380
2388 finally:
2381 finally:
2389 del wlock
2382 del wlock
2390
2383
2391 def rollback(ui, repo):
2384 def rollback(ui, repo):
2392 """roll back the last transaction
2385 """roll back the last transaction
2393
2386
2394 This command should be used with care. There is only one level of
2387 This command should be used with care. There is only one level of
2395 rollback, and there is no way to undo a rollback. It will also
2388 rollback, and there is no way to undo a rollback. It will also
2396 restore the dirstate at the time of the last transaction, losing
2389 restore the dirstate at the time of the last transaction, losing
2397 any dirstate changes since that time.
2390 any dirstate changes since that time.
2398
2391
2399 Transactions are used to encapsulate the effects of all commands
2392 Transactions are used to encapsulate the effects of all commands
2400 that create new changesets or propagate existing changesets into a
2393 that create new changesets or propagate existing changesets into a
2401 repository. For example, the following commands are transactional,
2394 repository. For example, the following commands are transactional,
2402 and their effects can be rolled back:
2395 and their effects can be rolled back:
2403
2396
2404 commit
2397 commit
2405 import
2398 import
2406 pull
2399 pull
2407 push (with this repository as destination)
2400 push (with this repository as destination)
2408 unbundle
2401 unbundle
2409
2402
2410 This command is not intended for use on public repositories. Once
2403 This command is not intended for use on public repositories. Once
2411 changes are visible for pull by other users, rolling a transaction
2404 changes are visible for pull by other users, rolling a transaction
2412 back locally is ineffective (someone else may already have pulled
2405 back locally is ineffective (someone else may already have pulled
2413 the changes). Furthermore, a race is possible with readers of the
2406 the changes). Furthermore, a race is possible with readers of the
2414 repository; for example an in-progress pull from the repository
2407 repository; for example an in-progress pull from the repository
2415 may fail if a rollback is performed.
2408 may fail if a rollback is performed.
2416 """
2409 """
2417 repo.rollback()
2410 repo.rollback()
2418
2411
2419 def root(ui, repo):
2412 def root(ui, repo):
2420 """print the root (top) of the current working dir
2413 """print the root (top) of the current working dir
2421
2414
2422 Print the root directory of the current repository.
2415 Print the root directory of the current repository.
2423 """
2416 """
2424 ui.write(repo.root + "\n")
2417 ui.write(repo.root + "\n")
2425
2418
2426 def serve(ui, repo, **opts):
2419 def serve(ui, repo, **opts):
2427 """export the repository via HTTP
2420 """export the repository via HTTP
2428
2421
2429 Start a local HTTP repository browser and pull server.
2422 Start a local HTTP repository browser and pull server.
2430
2423
2431 By default, the server logs accesses to stdout and errors to
2424 By default, the server logs accesses to stdout and errors to
2432 stderr. Use the "-A" and "-E" options to log to files.
2425 stderr. Use the "-A" and "-E" options to log to files.
2433 """
2426 """
2434
2427
2435 if opts["stdio"]:
2428 if opts["stdio"]:
2436 if repo is None:
2429 if repo is None:
2437 raise hg.RepoError(_("There is no Mercurial repository here"
2430 raise hg.RepoError(_("There is no Mercurial repository here"
2438 " (.hg not found)"))
2431 " (.hg not found)"))
2439 s = sshserver.sshserver(ui, repo)
2432 s = sshserver.sshserver(ui, repo)
2440 s.serve_forever()
2433 s.serve_forever()
2441
2434
2442 parentui = ui.parentui or ui
2435 parentui = ui.parentui or ui
2443 optlist = ("name templates style address port prefix ipv6"
2436 optlist = ("name templates style address port prefix ipv6"
2444 " accesslog errorlog webdir_conf certificate")
2437 " accesslog errorlog webdir_conf certificate")
2445 for o in optlist.split():
2438 for o in optlist.split():
2446 if opts[o]:
2439 if opts[o]:
2447 parentui.setconfig("web", o, str(opts[o]))
2440 parentui.setconfig("web", o, str(opts[o]))
2448 if (repo is not None) and (repo.ui != parentui):
2441 if (repo is not None) and (repo.ui != parentui):
2449 repo.ui.setconfig("web", o, str(opts[o]))
2442 repo.ui.setconfig("web", o, str(opts[o]))
2450
2443
2451 if repo is None and not ui.config("web", "webdir_conf"):
2444 if repo is None and not ui.config("web", "webdir_conf"):
2452 raise hg.RepoError(_("There is no Mercurial repository here"
2445 raise hg.RepoError(_("There is no Mercurial repository here"
2453 " (.hg not found)"))
2446 " (.hg not found)"))
2454
2447
2455 class service:
2448 class service:
2456 def init(self):
2449 def init(self):
2457 util.set_signal_handler()
2450 util.set_signal_handler()
2458 try:
2451 try:
2459 self.httpd = hgweb.server.create_server(parentui, repo)
2452 self.httpd = hgweb.server.create_server(parentui, repo)
2460 except socket.error, inst:
2453 except socket.error, inst:
2461 raise util.Abort(_('cannot start server: ') + inst.args[1])
2454 raise util.Abort(_('cannot start server: ') + inst.args[1])
2462
2455
2463 if not ui.verbose: return
2456 if not ui.verbose: return
2464
2457
2465 if self.httpd.prefix:
2458 if self.httpd.prefix:
2466 prefix = self.httpd.prefix.strip('/') + '/'
2459 prefix = self.httpd.prefix.strip('/') + '/'
2467 else:
2460 else:
2468 prefix = ''
2461 prefix = ''
2469
2462
2470 if self.httpd.port != 80:
2463 if self.httpd.port != 80:
2471 ui.status(_('listening at http://%s:%d/%s\n') %
2464 ui.status(_('listening at http://%s:%d/%s\n') %
2472 (self.httpd.addr, self.httpd.port, prefix))
2465 (self.httpd.addr, self.httpd.port, prefix))
2473 else:
2466 else:
2474 ui.status(_('listening at http://%s/%s\n') %
2467 ui.status(_('listening at http://%s/%s\n') %
2475 (self.httpd.addr, prefix))
2468 (self.httpd.addr, prefix))
2476
2469
2477 def run(self):
2470 def run(self):
2478 self.httpd.serve_forever()
2471 self.httpd.serve_forever()
2479
2472
2480 service = service()
2473 service = service()
2481
2474
2482 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2475 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2483
2476
2484 def status(ui, repo, *pats, **opts):
2477 def status(ui, repo, *pats, **opts):
2485 """show changed files in the working directory
2478 """show changed files in the working directory
2486
2479
2487 Show status of files in the repository. If names are given, only
2480 Show status of files in the repository. If names are given, only
2488 files that match are shown. Files that are clean or ignored or
2481 files that match are shown. Files that are clean or ignored or
2489 source of a copy/move operation, are not listed unless -c (clean),
2482 source of a copy/move operation, are not listed unless -c (clean),
2490 -i (ignored), -C (copies) or -A is given. Unless options described
2483 -i (ignored), -C (copies) or -A is given. Unless options described
2491 with "show only ..." are given, the options -mardu are used.
2484 with "show only ..." are given, the options -mardu are used.
2492
2485
2493 NOTE: status may appear to disagree with diff if permissions have
2486 NOTE: status may appear to disagree with diff if permissions have
2494 changed or a merge has occurred. The standard diff format does not
2487 changed or a merge has occurred. The standard diff format does not
2495 report permission changes and diff only reports changes relative
2488 report permission changes and diff only reports changes relative
2496 to one merge parent.
2489 to one merge parent.
2497
2490
2498 If one revision is given, it is used as the base revision.
2491 If one revision is given, it is used as the base revision.
2499 If two revisions are given, the difference between them is shown.
2492 If two revisions are given, the difference between them is shown.
2500
2493
2501 The codes used to show the status of files are:
2494 The codes used to show the status of files are:
2502 M = modified
2495 M = modified
2503 A = added
2496 A = added
2504 R = removed
2497 R = removed
2505 C = clean
2498 C = clean
2506 ! = deleted, but still tracked
2499 ! = deleted, but still tracked
2507 ? = not tracked
2500 ? = not tracked
2508 I = ignored
2501 I = ignored
2509 = the previous added file was copied from here
2502 = the previous added file was copied from here
2510 """
2503 """
2511
2504
2512 all = opts['all']
2505 all = opts['all']
2513 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2506 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2514
2507
2515 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2508 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2516 cwd = (pats and repo.getcwd()) or ''
2509 cwd = (pats and repo.getcwd()) or ''
2517 modified, added, removed, deleted, unknown, ignored, clean = [
2510 modified, added, removed, deleted, unknown, ignored, clean = [
2518 n for n in repo.status(node1=node1, node2=node2, files=files,
2511 n for n in repo.status(node1=node1, node2=node2, files=files,
2519 match=matchfn,
2512 match=matchfn,
2520 list_ignored=all or opts['ignored'],
2513 list_ignored=all or opts['ignored'],
2521 list_clean=all or opts['clean'])]
2514 list_clean=all or opts['clean'])]
2522
2515
2523 changetypes = (('modified', 'M', modified),
2516 changetypes = (('modified', 'M', modified),
2524 ('added', 'A', added),
2517 ('added', 'A', added),
2525 ('removed', 'R', removed),
2518 ('removed', 'R', removed),
2526 ('deleted', '!', deleted),
2519 ('deleted', '!', deleted),
2527 ('unknown', '?', unknown),
2520 ('unknown', '?', unknown),
2528 ('ignored', 'I', ignored))
2521 ('ignored', 'I', ignored))
2529
2522
2530 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2523 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2531
2524
2532 end = opts['print0'] and '\0' or '\n'
2525 end = opts['print0'] and '\0' or '\n'
2533
2526
2534 for opt, char, changes in ([ct for ct in explicit_changetypes
2527 for opt, char, changes in ([ct for ct in explicit_changetypes
2535 if all or opts[ct[0]]]
2528 if all or opts[ct[0]]]
2536 or changetypes):
2529 or changetypes):
2537 if opts['no_status']:
2530 if opts['no_status']:
2538 format = "%%s%s" % end
2531 format = "%%s%s" % end
2539 else:
2532 else:
2540 format = "%s %%s%s" % (char, end)
2533 format = "%s %%s%s" % (char, end)
2541
2534
2542 for f in changes:
2535 for f in changes:
2543 ui.write(format % repo.pathto(f, cwd))
2536 ui.write(format % repo.pathto(f, cwd))
2544 if ((all or opts.get('copies')) and not opts.get('no_status')):
2537 if ((all or opts.get('copies')) and not opts.get('no_status')):
2545 copied = repo.dirstate.copied(f)
2538 copied = repo.dirstate.copied(f)
2546 if copied:
2539 if copied:
2547 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2540 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2548
2541
2549 def tag(ui, repo, name, rev_=None, **opts):
2542 def tag(ui, repo, name, rev_=None, **opts):
2550 """add a tag for the current or given revision
2543 """add a tag for the current or given revision
2551
2544
2552 Name a particular revision using <name>.
2545 Name a particular revision using <name>.
2553
2546
2554 Tags are used to name particular revisions of the repository and are
2547 Tags are used to name particular revisions of the repository and are
2555 very useful to compare different revision, to go back to significant
2548 very useful to compare different revision, to go back to significant
2556 earlier versions or to mark branch points as releases, etc.
2549 earlier versions or to mark branch points as releases, etc.
2557
2550
2558 If no revision is given, the parent of the working directory is used,
2551 If no revision is given, the parent of the working directory is used,
2559 or tip if no revision is checked out.
2552 or tip if no revision is checked out.
2560
2553
2561 To facilitate version control, distribution, and merging of tags,
2554 To facilitate version control, distribution, and merging of tags,
2562 they are stored as a file named ".hgtags" which is managed
2555 they are stored as a file named ".hgtags" which is managed
2563 similarly to other project files and can be hand-edited if
2556 similarly to other project files and can be hand-edited if
2564 necessary. The file '.hg/localtags' is used for local tags (not
2557 necessary. The file '.hg/localtags' is used for local tags (not
2565 shared among repositories).
2558 shared among repositories).
2566
2559
2567 See 'hg help dates' for a list of formats valid for -d/--date.
2560 See 'hg help dates' for a list of formats valid for -d/--date.
2568 """
2561 """
2569 if name in ['tip', '.', 'null']:
2562 if name in ['tip', '.', 'null']:
2570 raise util.Abort(_("the name '%s' is reserved") % name)
2563 raise util.Abort(_("the name '%s' is reserved") % name)
2571 if rev_ is not None:
2564 if rev_ is not None:
2572 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2565 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2573 "please use 'hg tag [-r REV] NAME' instead\n"))
2566 "please use 'hg tag [-r REV] NAME' instead\n"))
2574 if opts['rev']:
2567 if opts['rev']:
2575 raise util.Abort(_("use only one form to specify the revision"))
2568 raise util.Abort(_("use only one form to specify the revision"))
2576 if opts['rev'] and opts['remove']:
2569 if opts['rev'] and opts['remove']:
2577 raise util.Abort(_("--rev and --remove are incompatible"))
2570 raise util.Abort(_("--rev and --remove are incompatible"))
2578 if opts['rev']:
2571 if opts['rev']:
2579 rev_ = opts['rev']
2572 rev_ = opts['rev']
2580 message = opts['message']
2573 message = opts['message']
2581 if opts['remove']:
2574 if opts['remove']:
2582 tagtype = repo.tagtype(name)
2575 tagtype = repo.tagtype(name)
2583
2576
2584 if not tagtype:
2577 if not tagtype:
2585 raise util.Abort(_('tag %s does not exist') % name)
2578 raise util.Abort(_('tag %s does not exist') % name)
2586 if opts['local'] and tagtype == 'global':
2579 if opts['local'] and tagtype == 'global':
2587 raise util.Abort(_('%s tag is global') % name)
2580 raise util.Abort(_('%s tag is global') % name)
2588 if not opts['local'] and tagtype == 'local':
2581 if not opts['local'] and tagtype == 'local':
2589 raise util.Abort(_('%s tag is local') % name)
2582 raise util.Abort(_('%s tag is local') % name)
2590
2583
2591 rev_ = nullid
2584 rev_ = nullid
2592 if not message:
2585 if not message:
2593 message = _('Removed tag %s') % name
2586 message = _('Removed tag %s') % name
2594 elif name in repo.tags() and not opts['force']:
2587 elif name in repo.tags() and not opts['force']:
2595 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2588 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2596 % name)
2589 % name)
2597 if not rev_ and repo.dirstate.parents()[1] != nullid:
2590 if not rev_ and repo.dirstate.parents()[1] != nullid:
2598 raise util.Abort(_('uncommitted merge - please provide a '
2591 raise util.Abort(_('uncommitted merge - please provide a '
2599 'specific revision'))
2592 'specific revision'))
2600 r = repo.changectx(rev_).node()
2593 r = repo.changectx(rev_).node()
2601
2594
2602 if not message:
2595 if not message:
2603 message = _('Added tag %s for changeset %s') % (name, short(r))
2596 message = _('Added tag %s for changeset %s') % (name, short(r))
2604
2597
2605 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2598 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2606
2599
2607 def tags(ui, repo):
2600 def tags(ui, repo):
2608 """list repository tags
2601 """list repository tags
2609
2602
2610 List the repository tags.
2603 List the repository tags.
2611
2604
2612 This lists both regular and local tags. When the -v/--verbose switch
2605 This lists both regular and local tags. When the -v/--verbose switch
2613 is used, a third column "local" is printed for local tags.
2606 is used, a third column "local" is printed for local tags.
2614 """
2607 """
2615
2608
2616 l = repo.tagslist()
2609 l = repo.tagslist()
2617 l.reverse()
2610 l.reverse()
2618 hexfunc = ui.debugflag and hex or short
2611 hexfunc = ui.debugflag and hex or short
2619 tagtype = ""
2612 tagtype = ""
2620
2613
2621 for t, n in l:
2614 for t, n in l:
2622 if ui.quiet:
2615 if ui.quiet:
2623 ui.write("%s\n" % t)
2616 ui.write("%s\n" % t)
2624 continue
2617 continue
2625
2618
2626 try:
2619 try:
2627 hn = hexfunc(n)
2620 hn = hexfunc(n)
2628 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2621 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2629 except revlog.LookupError:
2622 except revlog.LookupError:
2630 r = " ?:%s" % hn
2623 r = " ?:%s" % hn
2631 else:
2624 else:
2632 spaces = " " * (30 - util.locallen(t))
2625 spaces = " " * (30 - util.locallen(t))
2633 if ui.verbose:
2626 if ui.verbose:
2634 if repo.tagtype(t) == 'local':
2627 if repo.tagtype(t) == 'local':
2635 tagtype = " local"
2628 tagtype = " local"
2636 else:
2629 else:
2637 tagtype = ""
2630 tagtype = ""
2638 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2631 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2639
2632
2640 def tip(ui, repo, **opts):
2633 def tip(ui, repo, **opts):
2641 """show the tip revision
2634 """show the tip revision
2642
2635
2643 Show the tip revision.
2636 Show the tip revision.
2644 """
2637 """
2645 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2638 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2646
2639
2647 def unbundle(ui, repo, fname1, *fnames, **opts):
2640 def unbundle(ui, repo, fname1, *fnames, **opts):
2648 """apply one or more changegroup files
2641 """apply one or more changegroup files
2649
2642
2650 Apply one or more compressed changegroup files generated by the
2643 Apply one or more compressed changegroup files generated by the
2651 bundle command.
2644 bundle command.
2652 """
2645 """
2653 fnames = (fname1,) + fnames
2646 fnames = (fname1,) + fnames
2654
2647
2655 lock = None
2648 lock = None
2656 try:
2649 try:
2657 lock = repo.lock()
2650 lock = repo.lock()
2658 for fname in fnames:
2651 for fname in fnames:
2659 if os.path.exists(fname):
2652 if os.path.exists(fname):
2660 f = open(fname, "rb")
2653 f = open(fname, "rb")
2661 else:
2654 else:
2662 f = urllib.urlopen(fname)
2655 f = urllib.urlopen(fname)
2663 gen = changegroup.readbundle(f, fname)
2656 gen = changegroup.readbundle(f, fname)
2664 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2657 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2665 finally:
2658 finally:
2666 del lock
2659 del lock
2667
2660
2668 return postincoming(ui, repo, modheads, opts['update'], None)
2661 return postincoming(ui, repo, modheads, opts['update'], None)
2669
2662
2670 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2663 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2671 """update working directory
2664 """update working directory
2672
2665
2673 Update the working directory to the specified revision, or the
2666 Update the working directory to the specified revision, or the
2674 tip of the current branch if none is specified.
2667 tip of the current branch if none is specified.
2675 See 'hg help dates' for a list of formats valid for -d/--date.
2668 See 'hg help dates' for a list of formats valid for -d/--date.
2676
2669
2677 If there are no outstanding changes in the working directory and
2670 If there are no outstanding changes in the working directory and
2678 there is a linear relationship between the current version and the
2671 there is a linear relationship between the current version and the
2679 requested version, the result is the requested version.
2672 requested version, the result is the requested version.
2680
2673
2681 To merge the working directory with another revision, use the
2674 To merge the working directory with another revision, use the
2682 merge command.
2675 merge command.
2683
2676
2684 By default, update will refuse to run if doing so would require
2677 By default, update will refuse to run if doing so would require
2685 discarding local changes.
2678 discarding local changes.
2686 """
2679 """
2687 if rev and node:
2680 if rev and node:
2688 raise util.Abort(_("please specify just one revision"))
2681 raise util.Abort(_("please specify just one revision"))
2689
2682
2690 if not rev:
2683 if not rev:
2691 rev = node
2684 rev = node
2692
2685
2693 if date:
2686 if date:
2694 if rev:
2687 if rev:
2695 raise util.Abort(_("you can't specify a revision and a date"))
2688 raise util.Abort(_("you can't specify a revision and a date"))
2696 rev = cmdutil.finddate(ui, repo, date)
2689 rev = cmdutil.finddate(ui, repo, date)
2697
2690
2698 if clean:
2691 if clean:
2699 return hg.clean(repo, rev)
2692 return hg.clean(repo, rev)
2700 else:
2693 else:
2701 return hg.update(repo, rev)
2694 return hg.update(repo, rev)
2702
2695
2703 def verify(ui, repo):
2696 def verify(ui, repo):
2704 """verify the integrity of the repository
2697 """verify the integrity of the repository
2705
2698
2706 Verify the integrity of the current repository.
2699 Verify the integrity of the current repository.
2707
2700
2708 This will perform an extensive check of the repository's
2701 This will perform an extensive check of the repository's
2709 integrity, validating the hashes and checksums of each entry in
2702 integrity, validating the hashes and checksums of each entry in
2710 the changelog, manifest, and tracked files, as well as the
2703 the changelog, manifest, and tracked files, as well as the
2711 integrity of their crosslinks and indices.
2704 integrity of their crosslinks and indices.
2712 """
2705 """
2713 return hg.verify(repo)
2706 return hg.verify(repo)
2714
2707
2715 def version_(ui):
2708 def version_(ui):
2716 """output version and copyright information"""
2709 """output version and copyright information"""
2717 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2710 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2718 % version.get_version())
2711 % version.get_version())
2719 ui.status(_(
2712 ui.status(_(
2720 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2713 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2721 "This is free software; see the source for copying conditions. "
2714 "This is free software; see the source for copying conditions. "
2722 "There is NO\nwarranty; "
2715 "There is NO\nwarranty; "
2723 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2716 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2724 ))
2717 ))
2725
2718
2726 # Command options and aliases are listed here, alphabetically
2719 # Command options and aliases are listed here, alphabetically
2727
2720
2728 globalopts = [
2721 globalopts = [
2729 ('R', 'repository', '',
2722 ('R', 'repository', '',
2730 _('repository root directory or symbolic path name')),
2723 _('repository root directory or symbolic path name')),
2731 ('', 'cwd', '', _('change working directory')),
2724 ('', 'cwd', '', _('change working directory')),
2732 ('y', 'noninteractive', None,
2725 ('y', 'noninteractive', None,
2733 _('do not prompt, assume \'yes\' for any required answers')),
2726 _('do not prompt, assume \'yes\' for any required answers')),
2734 ('q', 'quiet', None, _('suppress output')),
2727 ('q', 'quiet', None, _('suppress output')),
2735 ('v', 'verbose', None, _('enable additional output')),
2728 ('v', 'verbose', None, _('enable additional output')),
2736 ('', 'config', [], _('set/override config option')),
2729 ('', 'config', [], _('set/override config option')),
2737 ('', 'debug', None, _('enable debugging output')),
2730 ('', 'debug', None, _('enable debugging output')),
2738 ('', 'debugger', None, _('start debugger')),
2731 ('', 'debugger', None, _('start debugger')),
2739 ('', 'encoding', util._encoding, _('set the charset encoding')),
2732 ('', 'encoding', util._encoding, _('set the charset encoding')),
2740 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2733 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2741 ('', 'lsprof', None, _('print improved command execution profile')),
2734 ('', 'lsprof', None, _('print improved command execution profile')),
2742 ('', 'traceback', None, _('print traceback on exception')),
2735 ('', 'traceback', None, _('print traceback on exception')),
2743 ('', 'time', None, _('time how long the command takes')),
2736 ('', 'time', None, _('time how long the command takes')),
2744 ('', 'profile', None, _('print command execution profile')),
2737 ('', 'profile', None, _('print command execution profile')),
2745 ('', 'version', None, _('output version information and exit')),
2738 ('', 'version', None, _('output version information and exit')),
2746 ('h', 'help', None, _('display help and exit')),
2739 ('h', 'help', None, _('display help and exit')),
2747 ]
2740 ]
2748
2741
2749 dryrunopts = [('n', 'dry-run', None,
2742 dryrunopts = [('n', 'dry-run', None,
2750 _('do not perform actions, just print output'))]
2743 _('do not perform actions, just print output'))]
2751
2744
2752 remoteopts = [
2745 remoteopts = [
2753 ('e', 'ssh', '', _('specify ssh command to use')),
2746 ('e', 'ssh', '', _('specify ssh command to use')),
2754 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2747 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2755 ]
2748 ]
2756
2749
2757 walkopts = [
2750 walkopts = [
2758 ('I', 'include', [], _('include names matching the given patterns')),
2751 ('I', 'include', [], _('include names matching the given patterns')),
2759 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2752 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2760 ]
2753 ]
2761
2754
2762 commitopts = [
2755 commitopts = [
2763 ('m', 'message', '', _('use <text> as commit message')),
2756 ('m', 'message', '', _('use <text> as commit message')),
2764 ('l', 'logfile', '', _('read commit message from <file>')),
2757 ('l', 'logfile', '', _('read commit message from <file>')),
2765 ]
2758 ]
2766
2759
2767 commitopts2 = [
2760 commitopts2 = [
2768 ('d', 'date', '', _('record datecode as commit date')),
2761 ('d', 'date', '', _('record datecode as commit date')),
2769 ('u', 'user', '', _('record user as committer')),
2762 ('u', 'user', '', _('record user as committer')),
2770 ]
2763 ]
2771
2764
2772 table = {
2765 table = {
2773 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2766 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2774 "addremove":
2767 "addremove":
2775 (addremove,
2768 (addremove,
2776 [('s', 'similarity', '',
2769 [('s', 'similarity', '',
2777 _('guess renamed files by similarity (0<=s<=100)')),
2770 _('guess renamed files by similarity (0<=s<=100)')),
2778 ] + walkopts + dryrunopts,
2771 ] + walkopts + dryrunopts,
2779 _('hg addremove [OPTION]... [FILE]...')),
2772 _('hg addremove [OPTION]... [FILE]...')),
2780 "^annotate|blame":
2773 "^annotate|blame":
2781 (annotate,
2774 (annotate,
2782 [('r', 'rev', '', _('annotate the specified revision')),
2775 [('r', 'rev', '', _('annotate the specified revision')),
2783 ('f', 'follow', None, _('follow file copies and renames')),
2776 ('f', 'follow', None, _('follow file copies and renames')),
2784 ('a', 'text', None, _('treat all files as text')),
2777 ('a', 'text', None, _('treat all files as text')),
2785 ('u', 'user', None, _('list the author (long with -v)')),
2778 ('u', 'user', None, _('list the author (long with -v)')),
2786 ('d', 'date', None, _('list the date (short with -q)')),
2779 ('d', 'date', None, _('list the date (short with -q)')),
2787 ('n', 'number', None, _('list the revision number (default)')),
2780 ('n', 'number', None, _('list the revision number (default)')),
2788 ('c', 'changeset', None, _('list the changeset')),
2781 ('c', 'changeset', None, _('list the changeset')),
2789 ('l', 'line-number', None,
2782 ('l', 'line-number', None,
2790 _('show line number at the first appearance'))
2783 _('show line number at the first appearance'))
2791 ] + walkopts,
2784 ] + walkopts,
2792 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2785 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2793 "archive":
2786 "archive":
2794 (archive,
2787 (archive,
2795 [('', 'no-decode', None, _('do not pass files through decoders')),
2788 [('', 'no-decode', None, _('do not pass files through decoders')),
2796 ('p', 'prefix', '', _('directory prefix for files in archive')),
2789 ('p', 'prefix', '', _('directory prefix for files in archive')),
2797 ('r', 'rev', '', _('revision to distribute')),
2790 ('r', 'rev', '', _('revision to distribute')),
2798 ('t', 'type', '', _('type of distribution to create')),
2791 ('t', 'type', '', _('type of distribution to create')),
2799 ] + walkopts,
2792 ] + walkopts,
2800 _('hg archive [OPTION]... DEST')),
2793 _('hg archive [OPTION]... DEST')),
2801 "backout":
2794 "backout":
2802 (backout,
2795 (backout,
2803 [('', 'merge', None,
2796 [('', 'merge', None,
2804 _('merge with old dirstate parent after backout')),
2797 _('merge with old dirstate parent after backout')),
2805 ('', 'parent', '', _('parent to choose when backing out merge')),
2798 ('', 'parent', '', _('parent to choose when backing out merge')),
2806 ('r', 'rev', '', _('revision to backout')),
2799 ('r', 'rev', '', _('revision to backout')),
2807 ] + walkopts + commitopts + commitopts2,
2800 ] + walkopts + commitopts + commitopts2,
2808 _('hg backout [OPTION]... [-r] REV')),
2801 _('hg backout [OPTION]... [-r] REV')),
2809 "bisect":
2802 "bisect":
2810 (bisect,
2803 (bisect,
2811 [('r', 'reset', False, _('reset bisect state')),
2804 [('r', 'reset', False, _('reset bisect state')),
2812 ('g', 'good', False, _('mark changeset good')),
2805 ('g', 'good', False, _('mark changeset good')),
2813 ('b', 'bad', False, _('mark changeset bad')),
2806 ('b', 'bad', False, _('mark changeset bad')),
2814 ('s', 'skip', False, _('skip testing changeset')),
2807 ('s', 'skip', False, _('skip testing changeset')),
2815 ('U', 'noupdate', False, _('do not update to target'))],
2808 ('U', 'noupdate', False, _('do not update to target'))],
2816 _("hg bisect [-gbsr] [REV]")),
2809 _("hg bisect [-gbsr] [REV]")),
2817 "branch":
2810 "branch":
2818 (branch,
2811 (branch,
2819 [('f', 'force', None,
2812 [('f', 'force', None,
2820 _('set branch name even if it shadows an existing branch'))],
2813 _('set branch name even if it shadows an existing branch'))],
2821 _('hg branch [-f] [NAME]')),
2814 _('hg branch [-f] [NAME]')),
2822 "branches":
2815 "branches":
2823 (branches,
2816 (branches,
2824 [('a', 'active', False,
2817 [('a', 'active', False,
2825 _('show only branches that have unmerged heads'))],
2818 _('show only branches that have unmerged heads'))],
2826 _('hg branches [-a]')),
2819 _('hg branches [-a]')),
2827 "bundle":
2820 "bundle":
2828 (bundle,
2821 (bundle,
2829 [('f', 'force', None,
2822 [('f', 'force', None,
2830 _('run even when remote repository is unrelated')),
2823 _('run even when remote repository is unrelated')),
2831 ('r', 'rev', [],
2824 ('r', 'rev', [],
2832 _('a changeset you would like to bundle')),
2825 _('a changeset you would like to bundle')),
2833 ('', 'base', [],
2826 ('', 'base', [],
2834 _('a base changeset to specify instead of a destination')),
2827 _('a base changeset to specify instead of a destination')),
2835 ('a', 'all', None,
2828 ('a', 'all', None,
2836 _('bundle all changesets in the repository')),
2829 _('bundle all changesets in the repository')),
2837 ] + remoteopts,
2830 ] + remoteopts,
2838 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
2831 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
2839 "cat":
2832 "cat":
2840 (cat,
2833 (cat,
2841 [('o', 'output', '', _('print output to file with formatted name')),
2834 [('o', 'output', '', _('print output to file with formatted name')),
2842 ('r', 'rev', '', _('print the given revision')),
2835 ('r', 'rev', '', _('print the given revision')),
2843 ('', 'decode', None, _('apply any matching decode filter')),
2836 ('', 'decode', None, _('apply any matching decode filter')),
2844 ] + walkopts,
2837 ] + walkopts,
2845 _('hg cat [OPTION]... FILE...')),
2838 _('hg cat [OPTION]... FILE...')),
2846 "^clone":
2839 "^clone":
2847 (clone,
2840 (clone,
2848 [('U', 'noupdate', None, _('do not update the new working directory')),
2841 [('U', 'noupdate', None, _('do not update the new working directory')),
2849 ('r', 'rev', [],
2842 ('r', 'rev', [],
2850 _('a changeset you would like to have after cloning')),
2843 _('a changeset you would like to have after cloning')),
2851 ('', 'pull', None, _('use pull protocol to copy metadata')),
2844 ('', 'pull', None, _('use pull protocol to copy metadata')),
2852 ('', 'uncompressed', None,
2845 ('', 'uncompressed', None,
2853 _('use uncompressed transfer (fast over LAN)')),
2846 _('use uncompressed transfer (fast over LAN)')),
2854 ] + remoteopts,
2847 ] + remoteopts,
2855 _('hg clone [OPTION]... SOURCE [DEST]')),
2848 _('hg clone [OPTION]... SOURCE [DEST]')),
2856 "^commit|ci":
2849 "^commit|ci":
2857 (commit,
2850 (commit,
2858 [('A', 'addremove', None,
2851 [('A', 'addremove', None,
2859 _('mark new/missing files as added/removed before committing')),
2852 _('mark new/missing files as added/removed before committing')),
2860 ] + walkopts + commitopts + commitopts2,
2853 ] + walkopts + commitopts + commitopts2,
2861 _('hg commit [OPTION]... [FILE]...')),
2854 _('hg commit [OPTION]... [FILE]...')),
2862 "copy|cp":
2855 "copy|cp":
2863 (copy,
2856 (copy,
2864 [('A', 'after', None, _('record a copy that has already occurred')),
2857 [('A', 'after', None, _('record a copy that has already occurred')),
2865 ('f', 'force', None,
2858 ('f', 'force', None,
2866 _('forcibly copy over an existing managed file')),
2859 _('forcibly copy over an existing managed file')),
2867 ] + walkopts + dryrunopts,
2860 ] + walkopts + dryrunopts,
2868 _('hg copy [OPTION]... [SOURCE]... DEST')),
2861 _('hg copy [OPTION]... [SOURCE]... DEST')),
2869 "debugancestor": (debugancestor, [],
2862 "debugancestor": (debugancestor, [],
2870 _('hg debugancestor [INDEX] REV1 REV2')),
2863 _('hg debugancestor [INDEX] REV1 REV2')),
2871 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
2864 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
2872 "debugcomplete":
2865 "debugcomplete":
2873 (debugcomplete,
2866 (debugcomplete,
2874 [('o', 'options', None, _('show the command options'))],
2867 [('o', 'options', None, _('show the command options'))],
2875 _('hg debugcomplete [-o] CMD')),
2868 _('hg debugcomplete [-o] CMD')),
2876 "debugdate":
2869 "debugdate":
2877 (debugdate,
2870 (debugdate,
2878 [('e', 'extended', None, _('try extended date formats'))],
2871 [('e', 'extended', None, _('try extended date formats'))],
2879 _('hg debugdate [-e] DATE [RANGE]')),
2872 _('hg debugdate [-e] DATE [RANGE]')),
2880 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
2873 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
2881 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
2874 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
2882 "debugindex": (debugindex, [], _('hg debugindex FILE')),
2875 "debugindex": (debugindex, [], _('hg debugindex FILE')),
2883 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
2876 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
2884 "debuginstall": (debuginstall, [], _('hg debuginstall')),
2877 "debuginstall": (debuginstall, [], _('hg debuginstall')),
2885 "debugrawcommit|rawcommit":
2878 "debugrawcommit|rawcommit":
2886 (rawcommit,
2879 (rawcommit,
2887 [('p', 'parent', [], _('parent')),
2880 [('p', 'parent', [], _('parent')),
2888 ('F', 'files', '', _('file list'))
2881 ('F', 'files', '', _('file list'))
2889 ] + commitopts + commitopts2,
2882 ] + commitopts + commitopts2,
2890 _('hg debugrawcommit [OPTION]... [FILE]...')),
2883 _('hg debugrawcommit [OPTION]... [FILE]...')),
2891 "debugrebuildstate":
2884 "debugrebuildstate":
2892 (debugrebuildstate,
2885 (debugrebuildstate,
2893 [('r', 'rev', '', _('revision to rebuild to'))],
2886 [('r', 'rev', '', _('revision to rebuild to'))],
2894 _('hg debugrebuildstate [-r REV] [REV]')),
2887 _('hg debugrebuildstate [-r REV] [REV]')),
2895 "debugrename":
2888 "debugrename":
2896 (debugrename,
2889 (debugrename,
2897 [('r', 'rev', '', _('revision to debug'))],
2890 [('r', 'rev', '', _('revision to debug'))],
2898 _('hg debugrename [-r REV] FILE')),
2891 _('hg debugrename [-r REV] FILE')),
2899 "debugsetparents":
2892 "debugsetparents":
2900 (debugsetparents,
2893 (debugsetparents,
2901 [],
2894 [],
2902 _('hg debugsetparents REV1 [REV2]')),
2895 _('hg debugsetparents REV1 [REV2]')),
2903 "debugstate": (debugstate, [], _('hg debugstate')),
2896 "debugstate": (debugstate, [], _('hg debugstate')),
2904 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
2897 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
2905 "^diff":
2898 "^diff":
2906 (diff,
2899 (diff,
2907 [('r', 'rev', [], _('revision')),
2900 [('r', 'rev', [], _('revision')),
2908 ('a', 'text', None, _('treat all files as text')),
2901 ('a', 'text', None, _('treat all files as text')),
2909 ('p', 'show-function', None,
2902 ('p', 'show-function', None,
2910 _('show which function each change is in')),
2903 _('show which function each change is in')),
2911 ('g', 'git', None, _('use git extended diff format')),
2904 ('g', 'git', None, _('use git extended diff format')),
2912 ('', 'nodates', None, _("don't include dates in diff headers")),
2905 ('', 'nodates', None, _("don't include dates in diff headers")),
2913 ('w', 'ignore-all-space', None,
2906 ('w', 'ignore-all-space', None,
2914 _('ignore white space when comparing lines')),
2907 _('ignore white space when comparing lines')),
2915 ('b', 'ignore-space-change', None,
2908 ('b', 'ignore-space-change', None,
2916 _('ignore changes in the amount of white space')),
2909 _('ignore changes in the amount of white space')),
2917 ('B', 'ignore-blank-lines', None,
2910 ('B', 'ignore-blank-lines', None,
2918 _('ignore changes whose lines are all blank')),
2911 _('ignore changes whose lines are all blank')),
2919 ('U', 'unified', 3,
2912 ('U', 'unified', 3,
2920 _('number of lines of context to show'))
2913 _('number of lines of context to show'))
2921 ] + walkopts,
2914 ] + walkopts,
2922 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2915 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2923 "^export":
2916 "^export":
2924 (export,
2917 (export,
2925 [('o', 'output', '', _('print output to file with formatted name')),
2918 [('o', 'output', '', _('print output to file with formatted name')),
2926 ('a', 'text', None, _('treat all files as text')),
2919 ('a', 'text', None, _('treat all files as text')),
2927 ('g', 'git', None, _('use git extended diff format')),
2920 ('g', 'git', None, _('use git extended diff format')),
2928 ('', 'nodates', None, _("don't include dates in diff headers")),
2921 ('', 'nodates', None, _("don't include dates in diff headers")),
2929 ('', 'switch-parent', None, _('diff against the second parent'))],
2922 ('', 'switch-parent', None, _('diff against the second parent'))],
2930 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2923 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2931 "grep":
2924 "grep":
2932 (grep,
2925 (grep,
2933 [('0', 'print0', None, _('end fields with NUL')),
2926 [('0', 'print0', None, _('end fields with NUL')),
2934 ('', 'all', None, _('print all revisions that match')),
2927 ('', 'all', None, _('print all revisions that match')),
2935 ('f', 'follow', None,
2928 ('f', 'follow', None,
2936 _('follow changeset history, or file history across copies and renames')),
2929 _('follow changeset history, or file history across copies and renames')),
2937 ('i', 'ignore-case', None, _('ignore case when matching')),
2930 ('i', 'ignore-case', None, _('ignore case when matching')),
2938 ('l', 'files-with-matches', None,
2931 ('l', 'files-with-matches', None,
2939 _('print only filenames and revs that match')),
2932 _('print only filenames and revs that match')),
2940 ('n', 'line-number', None, _('print matching line numbers')),
2933 ('n', 'line-number', None, _('print matching line numbers')),
2941 ('r', 'rev', [], _('search in given revision range')),
2934 ('r', 'rev', [], _('search in given revision range')),
2942 ('u', 'user', None, _('list the author (long with -v)')),
2935 ('u', 'user', None, _('list the author (long with -v)')),
2943 ('d', 'date', None, _('list the date (short with -q)')),
2936 ('d', 'date', None, _('list the date (short with -q)')),
2944 ] + walkopts,
2937 ] + walkopts,
2945 _('hg grep [OPTION]... PATTERN [FILE]...')),
2938 _('hg grep [OPTION]... PATTERN [FILE]...')),
2946 "heads":
2939 "heads":
2947 (heads,
2940 (heads,
2948 [('', 'style', '', _('display using template map file')),
2941 [('', 'style', '', _('display using template map file')),
2949 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2942 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2950 ('', 'template', '', _('display with template'))],
2943 ('', 'template', '', _('display with template'))],
2951 _('hg heads [-r REV] [REV]...')),
2944 _('hg heads [-r REV] [REV]...')),
2952 "help": (help_, [], _('hg help [COMMAND]')),
2945 "help": (help_, [], _('hg help [COMMAND]')),
2953 "identify|id":
2946 "identify|id":
2954 (identify,
2947 (identify,
2955 [('r', 'rev', '', _('identify the specified rev')),
2948 [('r', 'rev', '', _('identify the specified rev')),
2956 ('n', 'num', None, _('show local revision number')),
2949 ('n', 'num', None, _('show local revision number')),
2957 ('i', 'id', None, _('show global revision id')),
2950 ('i', 'id', None, _('show global revision id')),
2958 ('b', 'branch', None, _('show branch')),
2951 ('b', 'branch', None, _('show branch')),
2959 ('t', 'tags', None, _('show tags'))],
2952 ('t', 'tags', None, _('show tags'))],
2960 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2953 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2961 "import|patch":
2954 "import|patch":
2962 (import_,
2955 (import_,
2963 [('p', 'strip', 1,
2956 [('p', 'strip', 1,
2964 _('directory strip option for patch. This has the same\n'
2957 _('directory strip option for patch. This has the same\n'
2965 'meaning as the corresponding patch option')),
2958 'meaning as the corresponding patch option')),
2966 ('b', 'base', '', _('base path')),
2959 ('b', 'base', '', _('base path')),
2967 ('f', 'force', None,
2960 ('f', 'force', None,
2968 _('skip check for outstanding uncommitted changes')),
2961 _('skip check for outstanding uncommitted changes')),
2969 ('', 'no-commit', None, _("don't commit, just update the working directory")),
2962 ('', 'no-commit', None, _("don't commit, just update the working directory")),
2970 ('', 'exact', None,
2963 ('', 'exact', None,
2971 _('apply patch to the nodes from which it was generated')),
2964 _('apply patch to the nodes from which it was generated')),
2972 ('', 'import-branch', None,
2965 ('', 'import-branch', None,
2973 _('Use any branch information in patch (implied by --exact)'))] +
2966 _('Use any branch information in patch (implied by --exact)'))] +
2974 commitopts + commitopts2,
2967 commitopts + commitopts2,
2975 _('hg import [OPTION]... PATCH...')),
2968 _('hg import [OPTION]... PATCH...')),
2976 "incoming|in":
2969 "incoming|in":
2977 (incoming,
2970 (incoming,
2978 [('M', 'no-merges', None, _('do not show merges')),
2971 [('M', 'no-merges', None, _('do not show merges')),
2979 ('f', 'force', None,
2972 ('f', 'force', None,
2980 _('run even when remote repository is unrelated')),
2973 _('run even when remote repository is unrelated')),
2981 ('', 'style', '', _('display using template map file')),
2974 ('', 'style', '', _('display using template map file')),
2982 ('n', 'newest-first', None, _('show newest record first')),
2975 ('n', 'newest-first', None, _('show newest record first')),
2983 ('', 'bundle', '', _('file to store the bundles into')),
2976 ('', 'bundle', '', _('file to store the bundles into')),
2984 ('p', 'patch', None, _('show patch')),
2977 ('p', 'patch', None, _('show patch')),
2985 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2978 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2986 ('', 'template', '', _('display with template')),
2979 ('', 'template', '', _('display with template')),
2987 ] + remoteopts,
2980 ] + remoteopts,
2988 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2981 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2989 ' [--bundle FILENAME] [SOURCE]')),
2982 ' [--bundle FILENAME] [SOURCE]')),
2990 "^init":
2983 "^init":
2991 (init,
2984 (init,
2992 remoteopts,
2985 remoteopts,
2993 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2986 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2994 "locate":
2987 "locate":
2995 (locate,
2988 (locate,
2996 [('r', 'rev', '', _('search the repository as it stood at rev')),
2989 [('r', 'rev', '', _('search the repository as it stood at rev')),
2997 ('0', 'print0', None,
2990 ('0', 'print0', None,
2998 _('end filenames with NUL, for use with xargs')),
2991 _('end filenames with NUL, for use with xargs')),
2999 ('f', 'fullpath', None,
2992 ('f', 'fullpath', None,
3000 _('print complete paths from the filesystem root')),
2993 _('print complete paths from the filesystem root')),
3001 ] + walkopts,
2994 ] + walkopts,
3002 _('hg locate [OPTION]... [PATTERN]...')),
2995 _('hg locate [OPTION]... [PATTERN]...')),
3003 "^log|history":
2996 "^log|history":
3004 (log,
2997 (log,
3005 [('f', 'follow', None,
2998 [('f', 'follow', None,
3006 _('follow changeset history, or file history across copies and renames')),
2999 _('follow changeset history, or file history across copies and renames')),
3007 ('', 'follow-first', None,
3000 ('', 'follow-first', None,
3008 _('only follow the first parent of merge changesets')),
3001 _('only follow the first parent of merge changesets')),
3009 ('d', 'date', '', _('show revs matching date spec')),
3002 ('d', 'date', '', _('show revs matching date spec')),
3010 ('C', 'copies', None, _('show copied files')),
3003 ('C', 'copies', None, _('show copied files')),
3011 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3004 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3012 ('l', 'limit', '', _('limit number of changes displayed')),
3005 ('l', 'limit', '', _('limit number of changes displayed')),
3013 ('r', 'rev', [], _('show the specified revision or range')),
3006 ('r', 'rev', [], _('show the specified revision or range')),
3014 ('', 'removed', None, _('include revs where files were removed')),
3007 ('', 'removed', None, _('include revs where files were removed')),
3015 ('M', 'no-merges', None, _('do not show merges')),
3008 ('M', 'no-merges', None, _('do not show merges')),
3016 ('', 'style', '', _('display using template map file')),
3009 ('', 'style', '', _('display using template map file')),
3017 ('m', 'only-merges', None, _('show only merges')),
3010 ('m', 'only-merges', None, _('show only merges')),
3018 ('b', 'only-branch', [],
3011 ('b', 'only-branch', [],
3019 _('show only changesets within the given named branch')),
3012 _('show only changesets within the given named branch')),
3020 ('p', 'patch', None, _('show patch')),
3013 ('p', 'patch', None, _('show patch')),
3021 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3014 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3022 ('', 'template', '', _('display with template')),
3015 ('', 'template', '', _('display with template')),
3023 ] + walkopts,
3016 ] + walkopts,
3024 _('hg log [OPTION]... [FILE]')),
3017 _('hg log [OPTION]... [FILE]')),
3025 "manifest":
3018 "manifest":
3026 (manifest,
3019 (manifest,
3027 [('r', 'rev', '', _('revision to display'))],
3020 [('r', 'rev', '', _('revision to display'))],
3028 _('hg manifest [-r REV]')),
3021 _('hg manifest [-r REV]')),
3029 "^merge":
3022 "^merge":
3030 (merge,
3023 (merge,
3031 [('f', 'force', None, _('force a merge with outstanding changes')),
3024 [('f', 'force', None, _('force a merge with outstanding changes')),
3032 ('r', 'rev', '', _('revision to merge')),
3025 ('r', 'rev', '', _('revision to merge')),
3033 ],
3026 ],
3034 _('hg merge [-f] [[-r] REV]')),
3027 _('hg merge [-f] [[-r] REV]')),
3035 "outgoing|out":
3028 "outgoing|out":
3036 (outgoing,
3029 (outgoing,
3037 [('M', 'no-merges', None, _('do not show merges')),
3030 [('M', 'no-merges', None, _('do not show merges')),
3038 ('f', 'force', None,
3031 ('f', 'force', None,
3039 _('run even when remote repository is unrelated')),
3032 _('run even when remote repository is unrelated')),
3040 ('p', 'patch', None, _('show patch')),
3033 ('p', 'patch', None, _('show patch')),
3041 ('', 'style', '', _('display using template map file')),
3034 ('', 'style', '', _('display using template map file')),
3042 ('r', 'rev', [], _('a specific revision you would like to push')),
3035 ('r', 'rev', [], _('a specific revision you would like to push')),
3043 ('n', 'newest-first', None, _('show newest record first')),
3036 ('n', 'newest-first', None, _('show newest record first')),
3044 ('', 'template', '', _('display with template')),
3037 ('', 'template', '', _('display with template')),
3045 ] + remoteopts,
3038 ] + remoteopts,
3046 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3039 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3047 "^parents":
3040 "^parents":
3048 (parents,
3041 (parents,
3049 [('r', 'rev', '', _('show parents from the specified rev')),
3042 [('r', 'rev', '', _('show parents from the specified rev')),
3050 ('', 'style', '', _('display using template map file')),
3043 ('', 'style', '', _('display using template map file')),
3051 ('', 'template', '', _('display with template'))],
3044 ('', 'template', '', _('display with template'))],
3052 _('hg parents [-r REV] [FILE]')),
3045 _('hg parents [-r REV] [FILE]')),
3053 "paths": (paths, [], _('hg paths [NAME]')),
3046 "paths": (paths, [], _('hg paths [NAME]')),
3054 "^pull":
3047 "^pull":
3055 (pull,
3048 (pull,
3056 [('u', 'update', None,
3049 [('u', 'update', None,
3057 _('update to new tip if changesets were pulled')),
3050 _('update to new tip if changesets were pulled')),
3058 ('f', 'force', None,
3051 ('f', 'force', None,
3059 _('run even when remote repository is unrelated')),
3052 _('run even when remote repository is unrelated')),
3060 ('r', 'rev', [],
3053 ('r', 'rev', [],
3061 _('a specific revision up to which you would like to pull')),
3054 _('a specific revision up to which you would like to pull')),
3062 ] + remoteopts,
3055 ] + remoteopts,
3063 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3056 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3064 "^push":
3057 "^push":
3065 (push,
3058 (push,
3066 [('f', 'force', None, _('force push')),
3059 [('f', 'force', None, _('force push')),
3067 ('r', 'rev', [], _('a specific revision you would like to push')),
3060 ('r', 'rev', [], _('a specific revision you would like to push')),
3068 ] + remoteopts,
3061 ] + remoteopts,
3069 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3062 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3070 "recover": (recover, [], _('hg recover')),
3063 "recover": (recover, [], _('hg recover')),
3071 "^remove|rm":
3064 "^remove|rm":
3072 (remove,
3065 (remove,
3073 [('A', 'after', None, _('record remove without deleting')),
3066 [('A', 'after', None, _('record remove without deleting')),
3074 ('f', 'force', None, _('remove file even if modified')),
3067 ('f', 'force', None, _('remove file even if modified')),
3075 ] + walkopts,
3068 ] + walkopts,
3076 _('hg remove [OPTION]... FILE...')),
3069 _('hg remove [OPTION]... FILE...')),
3077 "rename|mv":
3070 "rename|mv":
3078 (rename,
3071 (rename,
3079 [('A', 'after', None, _('record a rename that has already occurred')),
3072 [('A', 'after', None, _('record a rename that has already occurred')),
3080 ('f', 'force', None,
3073 ('f', 'force', None,
3081 _('forcibly copy over an existing managed file')),
3074 _('forcibly copy over an existing managed file')),
3082 ] + walkopts + dryrunopts,
3075 ] + walkopts + dryrunopts,
3083 _('hg rename [OPTION]... SOURCE... DEST')),
3076 _('hg rename [OPTION]... SOURCE... DEST')),
3084 "revert":
3077 "revert":
3085 (revert,
3078 (revert,
3086 [('a', 'all', None, _('revert all changes when no arguments given')),
3079 [('a', 'all', None, _('revert all changes when no arguments given')),
3087 ('d', 'date', '', _('tipmost revision matching date')),
3080 ('d', 'date', '', _('tipmost revision matching date')),
3088 ('r', 'rev', '', _('revision to revert to')),
3081 ('r', 'rev', '', _('revision to revert to')),
3089 ('', 'no-backup', None, _('do not save backup copies of files')),
3082 ('', 'no-backup', None, _('do not save backup copies of files')),
3090 ] + walkopts + dryrunopts,
3083 ] + walkopts + dryrunopts,
3091 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3084 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3092 "rollback": (rollback, [], _('hg rollback')),
3085 "rollback": (rollback, [], _('hg rollback')),
3093 "root": (root, [], _('hg root')),
3086 "root": (root, [], _('hg root')),
3094 "^serve":
3087 "^serve":
3095 (serve,
3088 (serve,
3096 [('A', 'accesslog', '', _('name of access log file to write to')),
3089 [('A', 'accesslog', '', _('name of access log file to write to')),
3097 ('d', 'daemon', None, _('run server in background')),
3090 ('d', 'daemon', None, _('run server in background')),
3098 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3091 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3099 ('E', 'errorlog', '', _('name of error log file to write to')),
3092 ('E', 'errorlog', '', _('name of error log file to write to')),
3100 ('p', 'port', 0, _('port to use (default: 8000)')),
3093 ('p', 'port', 0, _('port to use (default: 8000)')),
3101 ('a', 'address', '', _('address to use')),
3094 ('a', 'address', '', _('address to use')),
3102 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3095 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3103 ('n', 'name', '',
3096 ('n', 'name', '',
3104 _('name to show in web pages (default: working dir)')),
3097 _('name to show in web pages (default: working dir)')),
3105 ('', 'webdir-conf', '', _('name of the webdir config file'
3098 ('', 'webdir-conf', '', _('name of the webdir config file'
3106 ' (serve more than one repo)')),
3099 ' (serve more than one repo)')),
3107 ('', 'pid-file', '', _('name of file to write process ID to')),
3100 ('', 'pid-file', '', _('name of file to write process ID to')),
3108 ('', 'stdio', None, _('for remote clients')),
3101 ('', 'stdio', None, _('for remote clients')),
3109 ('t', 'templates', '', _('web templates to use')),
3102 ('t', 'templates', '', _('web templates to use')),
3110 ('', 'style', '', _('template style to use')),
3103 ('', 'style', '', _('template style to use')),
3111 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3104 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3112 ('', 'certificate', '', _('SSL certificate file'))],
3105 ('', 'certificate', '', _('SSL certificate file'))],
3113 _('hg serve [OPTION]...')),
3106 _('hg serve [OPTION]...')),
3114 "showconfig|debugconfig":
3107 "showconfig|debugconfig":
3115 (showconfig,
3108 (showconfig,
3116 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3109 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3117 _('hg showconfig [-u] [NAME]...')),
3110 _('hg showconfig [-u] [NAME]...')),
3118 "^status|st":
3111 "^status|st":
3119 (status,
3112 (status,
3120 [('A', 'all', None, _('show status of all files')),
3113 [('A', 'all', None, _('show status of all files')),
3121 ('m', 'modified', None, _('show only modified files')),
3114 ('m', 'modified', None, _('show only modified files')),
3122 ('a', 'added', None, _('show only added files')),
3115 ('a', 'added', None, _('show only added files')),
3123 ('r', 'removed', None, _('show only removed files')),
3116 ('r', 'removed', None, _('show only removed files')),
3124 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3117 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3125 ('c', 'clean', None, _('show only files without changes')),
3118 ('c', 'clean', None, _('show only files without changes')),
3126 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3119 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3127 ('i', 'ignored', None, _('show only ignored files')),
3120 ('i', 'ignored', None, _('show only ignored files')),
3128 ('n', 'no-status', None, _('hide status prefix')),
3121 ('n', 'no-status', None, _('hide status prefix')),
3129 ('C', 'copies', None, _('show source of copied files')),
3122 ('C', 'copies', None, _('show source of copied files')),
3130 ('0', 'print0', None,
3123 ('0', 'print0', None,
3131 _('end filenames with NUL, for use with xargs')),
3124 _('end filenames with NUL, for use with xargs')),
3132 ('', 'rev', [], _('show difference from revision')),
3125 ('', 'rev', [], _('show difference from revision')),
3133 ] + walkopts,
3126 ] + walkopts,
3134 _('hg status [OPTION]... [FILE]...')),
3127 _('hg status [OPTION]... [FILE]...')),
3135 "tag":
3128 "tag":
3136 (tag,
3129 (tag,
3137 [('f', 'force', None, _('replace existing tag')),
3130 [('f', 'force', None, _('replace existing tag')),
3138 ('l', 'local', None, _('make the tag local')),
3131 ('l', 'local', None, _('make the tag local')),
3139 ('r', 'rev', '', _('revision to tag')),
3132 ('r', 'rev', '', _('revision to tag')),
3140 ('', 'remove', None, _('remove a tag')),
3133 ('', 'remove', None, _('remove a tag')),
3141 # -l/--local is already there, commitopts cannot be used
3134 # -l/--local is already there, commitopts cannot be used
3142 ('m', 'message', '', _('use <text> as commit message')),
3135 ('m', 'message', '', _('use <text> as commit message')),
3143 ] + commitopts2,
3136 ] + commitopts2,
3144 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3137 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3145 "tags": (tags, [], _('hg tags')),
3138 "tags": (tags, [], _('hg tags')),
3146 "tip":
3139 "tip":
3147 (tip,
3140 (tip,
3148 [('', 'style', '', _('display using template map file')),
3141 [('', 'style', '', _('display using template map file')),
3149 ('p', 'patch', None, _('show patch')),
3142 ('p', 'patch', None, _('show patch')),
3150 ('', 'template', '', _('display with template'))],
3143 ('', 'template', '', _('display with template'))],
3151 _('hg tip [-p]')),
3144 _('hg tip [-p]')),
3152 "unbundle":
3145 "unbundle":
3153 (unbundle,
3146 (unbundle,
3154 [('u', 'update', None,
3147 [('u', 'update', None,
3155 _('update to new tip if changesets were unbundled'))],
3148 _('update to new tip if changesets were unbundled'))],
3156 _('hg unbundle [-u] FILE...')),
3149 _('hg unbundle [-u] FILE...')),
3157 "^update|up|checkout|co":
3150 "^update|up|checkout|co":
3158 (update,
3151 (update,
3159 [('C', 'clean', None, _('overwrite locally modified files')),
3152 [('C', 'clean', None, _('overwrite locally modified files')),
3160 ('d', 'date', '', _('tipmost revision matching date')),
3153 ('d', 'date', '', _('tipmost revision matching date')),
3161 ('r', 'rev', '', _('revision'))],
3154 ('r', 'rev', '', _('revision'))],
3162 _('hg update [-C] [-d DATE] [[-r] REV]')),
3155 _('hg update [-C] [-d DATE] [[-r] REV]')),
3163 "verify": (verify, [], _('hg verify')),
3156 "verify": (verify, [], _('hg verify')),
3164 "version": (version_, [], _('hg version')),
3157 "version": (version_, [], _('hg version')),
3165 }
3158 }
3166
3159
3167 norepo = ("clone init version help debugcomplete debugdata"
3160 norepo = ("clone init version help debugcomplete debugdata"
3168 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3161 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3169 optionalrepo = ("identify paths serve showconfig debugancestor")
3162 optionalrepo = ("identify paths serve showconfig debugancestor")
General Comments 0
You need to be logged in to leave comments. Login now