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