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