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