##// END OF EJS Templates
revsets: generate predicate help dynamically
Patrick Mezard -
r12821:165079e5 stable
parent child Browse files
Show More
@@ -1,4489 +1,4491
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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error
12 import hg, util, revlog, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 .hgignore. As with add, these changes take effect at the next
61 .hgignore. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 ctx = repo[opts.get('rev')]
129 ctx = repo[opts.get('rev')]
130 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
131 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
132 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
133 fctx = ctx[abs]
133 fctx = ctx[abs]
134 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
136 continue
136 continue
137
137
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
139 pieces = []
139 pieces = []
140
140
141 for f in funcmap:
141 for f in funcmap:
142 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
143 if l:
143 if l:
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
145 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
147
147
148 if pieces:
148 if pieces:
149 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
151
151
152 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
153 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
154
154
155 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
156 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
157
157
158 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
159 extension (or override using -t/--type).
159 extension (or override using -t/--type).
160
160
161 Valid types are:
161 Valid types are:
162
162
163 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
164 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
166 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
167 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
168 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
169
169
170 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
171 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
172
172
173 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
174 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
175 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
176 removed.
176 removed.
177
177
178 Returns 0 on success.
178 Returns 0 on success.
179 '''
179 '''
180
180
181 ctx = repo[opts.get('rev')]
181 ctx = repo[opts.get('rev')]
182 if not ctx:
182 if not ctx:
183 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
184 node = ctx.node()
184 node = ctx.node()
185 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
186 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
187 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
188
188
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
190 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
191
191
192 if dest == '-':
192 if dest == '-':
193 if kind == 'files':
193 if kind == 'files':
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
195 dest = sys.stdout
195 dest = sys.stdout
196 if not prefix:
196 if not prefix:
197 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
198
198
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
200 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
202 matchfn, prefix, subrepos=opts.get('subrepos'))
202 matchfn, prefix, subrepos=opts.get('subrepos'))
203
203
204 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
205 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
206
206
207 The backout command merges the reverse effect of the reverted
207 The backout command merges the reverse effect of the reverted
208 changeset into the working directory.
208 changeset into the working directory.
209
209
210 With the --merge option, it first commits the reverted changes
210 With the --merge option, it first commits the reverted changes
211 as a new changeset. This new changeset is a child of the reverted
211 as a new changeset. This new changeset is a child of the reverted
212 changeset.
212 changeset.
213 The --merge option remembers the parent of the working directory
213 The --merge option remembers the parent of the working directory
214 before starting the backout, then merges the new head with that
214 before starting the backout, then merges the new head with that
215 changeset afterwards.
215 changeset afterwards.
216 This will result in an explicit merge in the history.
216 This will result in an explicit merge in the history.
217
217
218 If you backout a changeset other than the original parent of the
218 If you backout a changeset other than the original parent of the
219 working directory, the result of this merge is not committed,
219 working directory, the result of this merge is not committed,
220 as with a normal merge. Otherwise, no merge is needed and the
220 as with a normal merge. Otherwise, no merge is needed and the
221 commit is automatic.
221 commit is automatic.
222
222
223 Note that the default behavior (without --merge) has changed in
223 Note that the default behavior (without --merge) has changed in
224 version 1.7. To restore the previous default behavior, use
224 version 1.7. To restore the previous default behavior, use
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
226 the ongoing merge.
226 the ongoing merge.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = repo.lookup(rev)
246 node = repo.lookup(rev)
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
285 ui.setconfig('ui', 'forcemerge', '')
286
286
287 commit_opts = opts.copy()
287 commit_opts = opts.copy()
288 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
289 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
290 # we don't translate commit messages
290 # we don't translate commit messages
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
293 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
294 def nice(node):
294 def nice(node):
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
297 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
298 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
299 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
300 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
301 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
306 ui.setconfig('ui', 'forcemerge', '')
307 return 0
307 return 0
308
308
309 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
310 reset=None, good=None, bad=None, skip=None, noupdate=None):
310 reset=None, good=None, bad=None, skip=None, noupdate=None):
311 """subdivision search of changesets
311 """subdivision search of changesets
312
312
313 This command helps to find changesets which introduce problems. To
313 This command helps to find changesets which introduce problems. To
314 use, mark the earliest changeset you know exhibits the problem as
314 use, mark the earliest changeset you know exhibits the problem as
315 bad, then mark the latest changeset which is free from the problem
315 bad, then mark the latest changeset which is free from the problem
316 as good. Bisect will update your working directory to a revision
316 as good. Bisect will update your working directory to a revision
317 for testing (unless the -U/--noupdate option is specified). Once
317 for testing (unless the -U/--noupdate option is specified). Once
318 you have performed tests, mark the working directory as good or
318 you have performed tests, mark the working directory as good or
319 bad, and bisect will either update to another candidate changeset
319 bad, and bisect will either update to another candidate changeset
320 or announce that it has found the bad revision.
320 or announce that it has found the bad revision.
321
321
322 As a shortcut, you can also use the revision argument to mark a
322 As a shortcut, you can also use the revision argument to mark a
323 revision as good or bad without checking it out first.
323 revision as good or bad without checking it out first.
324
324
325 If you supply a command, it will be used for automatic bisection.
325 If you supply a command, it will be used for automatic bisection.
326 Its exit status will be used to mark revisions as good or bad:
326 Its exit status will be used to mark revisions as good or bad:
327 status 0 means good, 125 means to skip the revision, 127
327 status 0 means good, 125 means to skip the revision, 127
328 (command not found) will abort the bisection, and any other
328 (command not found) will abort the bisection, and any other
329 non-zero exit status means the revision is bad.
329 non-zero exit status means the revision is bad.
330
330
331 Returns 0 on success.
331 Returns 0 on success.
332 """
332 """
333 def print_result(nodes, good):
333 def print_result(nodes, good):
334 displayer = cmdutil.show_changeset(ui, repo, {})
334 displayer = cmdutil.show_changeset(ui, repo, {})
335 if len(nodes) == 1:
335 if len(nodes) == 1:
336 # narrowed it down to a single revision
336 # narrowed it down to a single revision
337 if good:
337 if good:
338 ui.write(_("The first good revision is:\n"))
338 ui.write(_("The first good revision is:\n"))
339 else:
339 else:
340 ui.write(_("The first bad revision is:\n"))
340 ui.write(_("The first bad revision is:\n"))
341 displayer.show(repo[nodes[0]])
341 displayer.show(repo[nodes[0]])
342 parents = repo[nodes[0]].parents()
342 parents = repo[nodes[0]].parents()
343 if len(parents) > 1:
343 if len(parents) > 1:
344 side = good and state['bad'] or state['good']
344 side = good and state['bad'] or state['good']
345 num = len(set(i.node() for i in parents) & set(side))
345 num = len(set(i.node() for i in parents) & set(side))
346 if num == 1:
346 if num == 1:
347 common = parents[0].ancestor(parents[1])
347 common = parents[0].ancestor(parents[1])
348 ui.write(_('Not all ancestors of this changeset have been'
348 ui.write(_('Not all ancestors of this changeset have been'
349 ' checked.\nTo check the other ancestors, start'
349 ' checked.\nTo check the other ancestors, start'
350 ' from the common ancestor, %s.\n' % common))
350 ' from the common ancestor, %s.\n' % common))
351 else:
351 else:
352 # multiple possible revisions
352 # multiple possible revisions
353 if good:
353 if good:
354 ui.write(_("Due to skipped revisions, the first "
354 ui.write(_("Due to skipped revisions, the first "
355 "good revision could be any of:\n"))
355 "good revision could be any of:\n"))
356 else:
356 else:
357 ui.write(_("Due to skipped revisions, the first "
357 ui.write(_("Due to skipped revisions, the first "
358 "bad revision could be any of:\n"))
358 "bad revision could be any of:\n"))
359 for n in nodes:
359 for n in nodes:
360 displayer.show(repo[n])
360 displayer.show(repo[n])
361 displayer.close()
361 displayer.close()
362
362
363 def check_state(state, interactive=True):
363 def check_state(state, interactive=True):
364 if not state['good'] or not state['bad']:
364 if not state['good'] or not state['bad']:
365 if (good or bad or skip or reset) and interactive:
365 if (good or bad or skip or reset) and interactive:
366 return
366 return
367 if not state['good']:
367 if not state['good']:
368 raise util.Abort(_('cannot bisect (no known good revisions)'))
368 raise util.Abort(_('cannot bisect (no known good revisions)'))
369 else:
369 else:
370 raise util.Abort(_('cannot bisect (no known bad revisions)'))
370 raise util.Abort(_('cannot bisect (no known bad revisions)'))
371 return True
371 return True
372
372
373 # backward compatibility
373 # backward compatibility
374 if rev in "good bad reset init".split():
374 if rev in "good bad reset init".split():
375 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
375 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
376 cmd, rev, extra = rev, extra, None
376 cmd, rev, extra = rev, extra, None
377 if cmd == "good":
377 if cmd == "good":
378 good = True
378 good = True
379 elif cmd == "bad":
379 elif cmd == "bad":
380 bad = True
380 bad = True
381 else:
381 else:
382 reset = True
382 reset = True
383 elif extra or good + bad + skip + reset + bool(command) > 1:
383 elif extra or good + bad + skip + reset + bool(command) > 1:
384 raise util.Abort(_('incompatible arguments'))
384 raise util.Abort(_('incompatible arguments'))
385
385
386 if reset:
386 if reset:
387 p = repo.join("bisect.state")
387 p = repo.join("bisect.state")
388 if os.path.exists(p):
388 if os.path.exists(p):
389 os.unlink(p)
389 os.unlink(p)
390 return
390 return
391
391
392 state = hbisect.load_state(repo)
392 state = hbisect.load_state(repo)
393
393
394 if command:
394 if command:
395 changesets = 1
395 changesets = 1
396 try:
396 try:
397 while changesets:
397 while changesets:
398 # update state
398 # update state
399 status = util.system(command)
399 status = util.system(command)
400 if status == 125:
400 if status == 125:
401 transition = "skip"
401 transition = "skip"
402 elif status == 0:
402 elif status == 0:
403 transition = "good"
403 transition = "good"
404 # status < 0 means process was killed
404 # status < 0 means process was killed
405 elif status == 127:
405 elif status == 127:
406 raise util.Abort(_("failed to execute %s") % command)
406 raise util.Abort(_("failed to execute %s") % command)
407 elif status < 0:
407 elif status < 0:
408 raise util.Abort(_("%s killed") % command)
408 raise util.Abort(_("%s killed") % command)
409 else:
409 else:
410 transition = "bad"
410 transition = "bad"
411 ctx = repo[rev or '.']
411 ctx = repo[rev or '.']
412 state[transition].append(ctx.node())
412 state[transition].append(ctx.node())
413 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
413 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
414 check_state(state, interactive=False)
414 check_state(state, interactive=False)
415 # bisect
415 # bisect
416 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
416 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
417 # update to next check
417 # update to next check
418 cmdutil.bail_if_changed(repo)
418 cmdutil.bail_if_changed(repo)
419 hg.clean(repo, nodes[0], show_stats=False)
419 hg.clean(repo, nodes[0], show_stats=False)
420 finally:
420 finally:
421 hbisect.save_state(repo, state)
421 hbisect.save_state(repo, state)
422 print_result(nodes, good)
422 print_result(nodes, good)
423 return
423 return
424
424
425 # update state
425 # update state
426
426
427 if rev:
427 if rev:
428 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
428 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
429 else:
429 else:
430 nodes = [repo.lookup('.')]
430 nodes = [repo.lookup('.')]
431
431
432 if good or bad or skip:
432 if good or bad or skip:
433 if good:
433 if good:
434 state['good'] += nodes
434 state['good'] += nodes
435 elif bad:
435 elif bad:
436 state['bad'] += nodes
436 state['bad'] += nodes
437 elif skip:
437 elif skip:
438 state['skip'] += nodes
438 state['skip'] += nodes
439 hbisect.save_state(repo, state)
439 hbisect.save_state(repo, state)
440
440
441 if not check_state(state):
441 if not check_state(state):
442 return
442 return
443
443
444 # actually bisect
444 # actually bisect
445 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
445 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
446 if changesets == 0:
446 if changesets == 0:
447 print_result(nodes, good)
447 print_result(nodes, good)
448 else:
448 else:
449 assert len(nodes) == 1 # only a single node can be tested next
449 assert len(nodes) == 1 # only a single node can be tested next
450 node = nodes[0]
450 node = nodes[0]
451 # compute the approximate number of remaining tests
451 # compute the approximate number of remaining tests
452 tests, size = 0, 2
452 tests, size = 0, 2
453 while size <= changesets:
453 while size <= changesets:
454 tests, size = tests + 1, size * 2
454 tests, size = tests + 1, size * 2
455 rev = repo.changelog.rev(node)
455 rev = repo.changelog.rev(node)
456 ui.write(_("Testing changeset %d:%s "
456 ui.write(_("Testing changeset %d:%s "
457 "(%d changesets remaining, ~%d tests)\n")
457 "(%d changesets remaining, ~%d tests)\n")
458 % (rev, short(node), changesets, tests))
458 % (rev, short(node), changesets, tests))
459 if not noupdate:
459 if not noupdate:
460 cmdutil.bail_if_changed(repo)
460 cmdutil.bail_if_changed(repo)
461 return hg.clean(repo, node)
461 return hg.clean(repo, node)
462
462
463 def branch(ui, repo, label=None, **opts):
463 def branch(ui, repo, label=None, **opts):
464 """set or show the current branch name
464 """set or show the current branch name
465
465
466 With no argument, show the current branch name. With one argument,
466 With no argument, show the current branch name. With one argument,
467 set the working directory branch name (the branch will not exist
467 set the working directory branch name (the branch will not exist
468 in the repository until the next commit). Standard practice
468 in the repository until the next commit). Standard practice
469 recommends that primary development take place on the 'default'
469 recommends that primary development take place on the 'default'
470 branch.
470 branch.
471
471
472 Unless -f/--force is specified, branch will not let you set a
472 Unless -f/--force is specified, branch will not let you set a
473 branch name that already exists, even if it's inactive.
473 branch name that already exists, even if it's inactive.
474
474
475 Use -C/--clean to reset the working directory branch to that of
475 Use -C/--clean to reset the working directory branch to that of
476 the parent of the working directory, negating a previous branch
476 the parent of the working directory, negating a previous branch
477 change.
477 change.
478
478
479 Use the command :hg:`update` to switch to an existing branch. Use
479 Use the command :hg:`update` to switch to an existing branch. Use
480 :hg:`commit --close-branch` to mark this branch as closed.
480 :hg:`commit --close-branch` to mark this branch as closed.
481
481
482 Returns 0 on success.
482 Returns 0 on success.
483 """
483 """
484
484
485 if opts.get('clean'):
485 if opts.get('clean'):
486 label = repo[None].parents()[0].branch()
486 label = repo[None].parents()[0].branch()
487 repo.dirstate.setbranch(label)
487 repo.dirstate.setbranch(label)
488 ui.status(_('reset working directory to branch %s\n') % label)
488 ui.status(_('reset working directory to branch %s\n') % label)
489 elif label:
489 elif label:
490 utflabel = encoding.fromlocal(label)
490 utflabel = encoding.fromlocal(label)
491 if not opts.get('force') and utflabel in repo.branchtags():
491 if not opts.get('force') and utflabel in repo.branchtags():
492 if label not in [p.branch() for p in repo.parents()]:
492 if label not in [p.branch() for p in repo.parents()]:
493 raise util.Abort(_('a branch of the same name already exists'
493 raise util.Abort(_('a branch of the same name already exists'
494 " (use 'hg update' to switch to it)"))
494 " (use 'hg update' to switch to it)"))
495 repo.dirstate.setbranch(utflabel)
495 repo.dirstate.setbranch(utflabel)
496 ui.status(_('marked working directory as branch %s\n') % label)
496 ui.status(_('marked working directory as branch %s\n') % label)
497 else:
497 else:
498 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
498 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
499
499
500 def branches(ui, repo, active=False, closed=False):
500 def branches(ui, repo, active=False, closed=False):
501 """list repository named branches
501 """list repository named branches
502
502
503 List the repository's named branches, indicating which ones are
503 List the repository's named branches, indicating which ones are
504 inactive. If -c/--closed is specified, also list branches which have
504 inactive. If -c/--closed is specified, also list branches which have
505 been marked closed (see :hg:`commit --close-branch`).
505 been marked closed (see :hg:`commit --close-branch`).
506
506
507 If -a/--active is specified, only show active branches. A branch
507 If -a/--active is specified, only show active branches. A branch
508 is considered active if it contains repository heads.
508 is considered active if it contains repository heads.
509
509
510 Use the command :hg:`update` to switch to an existing branch.
510 Use the command :hg:`update` to switch to an existing branch.
511
511
512 Returns 0.
512 Returns 0.
513 """
513 """
514
514
515 hexfunc = ui.debugflag and hex or short
515 hexfunc = ui.debugflag and hex or short
516 activebranches = [repo[n].branch() for n in repo.heads()]
516 activebranches = [repo[n].branch() for n in repo.heads()]
517 def testactive(tag, node):
517 def testactive(tag, node):
518 realhead = tag in activebranches
518 realhead = tag in activebranches
519 open = node in repo.branchheads(tag, closed=False)
519 open = node in repo.branchheads(tag, closed=False)
520 return realhead and open
520 return realhead and open
521 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
521 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
522 for tag, node in repo.branchtags().items()],
522 for tag, node in repo.branchtags().items()],
523 reverse=True)
523 reverse=True)
524
524
525 for isactive, node, tag in branches:
525 for isactive, node, tag in branches:
526 if (not active) or isactive:
526 if (not active) or isactive:
527 encodedtag = encoding.tolocal(tag)
527 encodedtag = encoding.tolocal(tag)
528 if ui.quiet:
528 if ui.quiet:
529 ui.write("%s\n" % encodedtag)
529 ui.write("%s\n" % encodedtag)
530 else:
530 else:
531 hn = repo.lookup(node)
531 hn = repo.lookup(node)
532 if isactive:
532 if isactive:
533 label = 'branches.active'
533 label = 'branches.active'
534 notice = ''
534 notice = ''
535 elif hn not in repo.branchheads(tag, closed=False):
535 elif hn not in repo.branchheads(tag, closed=False):
536 if not closed:
536 if not closed:
537 continue
537 continue
538 label = 'branches.closed'
538 label = 'branches.closed'
539 notice = _(' (closed)')
539 notice = _(' (closed)')
540 else:
540 else:
541 label = 'branches.inactive'
541 label = 'branches.inactive'
542 notice = _(' (inactive)')
542 notice = _(' (inactive)')
543 if tag == repo.dirstate.branch():
543 if tag == repo.dirstate.branch():
544 label = 'branches.current'
544 label = 'branches.current'
545 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
545 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
546 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
546 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
547 encodedtag = ui.label(encodedtag, label)
547 encodedtag = ui.label(encodedtag, label)
548 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
548 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
549
549
550 def bundle(ui, repo, fname, dest=None, **opts):
550 def bundle(ui, repo, fname, dest=None, **opts):
551 """create a changegroup file
551 """create a changegroup file
552
552
553 Generate a compressed changegroup file collecting changesets not
553 Generate a compressed changegroup file collecting changesets not
554 known to be in another repository.
554 known to be in another repository.
555
555
556 If you omit the destination repository, then hg assumes the
556 If you omit the destination repository, then hg assumes the
557 destination will have all the nodes you specify with --base
557 destination will have all the nodes you specify with --base
558 parameters. To create a bundle containing all changesets, use
558 parameters. To create a bundle containing all changesets, use
559 -a/--all (or --base null).
559 -a/--all (or --base null).
560
560
561 You can change compression method with the -t/--type option.
561 You can change compression method with the -t/--type option.
562 The available compression methods are: none, bzip2, and
562 The available compression methods are: none, bzip2, and
563 gzip (by default, bundles are compressed using bzip2).
563 gzip (by default, bundles are compressed using bzip2).
564
564
565 The bundle file can then be transferred using conventional means
565 The bundle file can then be transferred using conventional means
566 and applied to another repository with the unbundle or pull
566 and applied to another repository with the unbundle or pull
567 command. This is useful when direct push and pull are not
567 command. This is useful when direct push and pull are not
568 available or when exporting an entire repository is undesirable.
568 available or when exporting an entire repository is undesirable.
569
569
570 Applying bundles preserves all changeset contents including
570 Applying bundles preserves all changeset contents including
571 permissions, copy/rename information, and revision history.
571 permissions, copy/rename information, and revision history.
572
572
573 Returns 0 on success, 1 if no changes found.
573 Returns 0 on success, 1 if no changes found.
574 """
574 """
575 revs = opts.get('rev') or None
575 revs = opts.get('rev') or None
576 if opts.get('all'):
576 if opts.get('all'):
577 base = ['null']
577 base = ['null']
578 else:
578 else:
579 base = opts.get('base')
579 base = opts.get('base')
580 if base:
580 if base:
581 if dest:
581 if dest:
582 raise util.Abort(_("--base is incompatible with specifying "
582 raise util.Abort(_("--base is incompatible with specifying "
583 "a destination"))
583 "a destination"))
584 base = [repo.lookup(rev) for rev in base]
584 base = [repo.lookup(rev) for rev in base]
585 # create the right base
585 # create the right base
586 # XXX: nodesbetween / changegroup* should be "fixed" instead
586 # XXX: nodesbetween / changegroup* should be "fixed" instead
587 o = []
587 o = []
588 has = set((nullid,))
588 has = set((nullid,))
589 for n in base:
589 for n in base:
590 has.update(repo.changelog.reachable(n))
590 has.update(repo.changelog.reachable(n))
591 if revs:
591 if revs:
592 revs = [repo.lookup(rev) for rev in revs]
592 revs = [repo.lookup(rev) for rev in revs]
593 visit = revs[:]
593 visit = revs[:]
594 has.difference_update(visit)
594 has.difference_update(visit)
595 else:
595 else:
596 visit = repo.changelog.heads()
596 visit = repo.changelog.heads()
597 seen = {}
597 seen = {}
598 while visit:
598 while visit:
599 n = visit.pop(0)
599 n = visit.pop(0)
600 parents = [p for p in repo.changelog.parents(n) if p not in has]
600 parents = [p for p in repo.changelog.parents(n) if p not in has]
601 if len(parents) == 0:
601 if len(parents) == 0:
602 if n not in has:
602 if n not in has:
603 o.append(n)
603 o.append(n)
604 else:
604 else:
605 for p in parents:
605 for p in parents:
606 if p not in seen:
606 if p not in seen:
607 seen[p] = 1
607 seen[p] = 1
608 visit.append(p)
608 visit.append(p)
609 else:
609 else:
610 dest = ui.expandpath(dest or 'default-push', dest or 'default')
610 dest = ui.expandpath(dest or 'default-push', dest or 'default')
611 dest, branches = hg.parseurl(dest, opts.get('branch'))
611 dest, branches = hg.parseurl(dest, opts.get('branch'))
612 other = hg.repository(hg.remoteui(repo, opts), dest)
612 other = hg.repository(hg.remoteui(repo, opts), dest)
613 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
613 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
614 if revs:
614 if revs:
615 revs = [repo.lookup(rev) for rev in revs]
615 revs = [repo.lookup(rev) for rev in revs]
616 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
616 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
617
617
618 if not o:
618 if not o:
619 ui.status(_("no changes found\n"))
619 ui.status(_("no changes found\n"))
620 return 1
620 return 1
621
621
622 if revs:
622 if revs:
623 cg = repo.changegroupsubset(o, revs, 'bundle')
623 cg = repo.changegroupsubset(o, revs, 'bundle')
624 else:
624 else:
625 cg = repo.changegroup(o, 'bundle')
625 cg = repo.changegroup(o, 'bundle')
626
626
627 bundletype = opts.get('type', 'bzip2').lower()
627 bundletype = opts.get('type', 'bzip2').lower()
628 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
628 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
629 bundletype = btypes.get(bundletype)
629 bundletype = btypes.get(bundletype)
630 if bundletype not in changegroup.bundletypes:
630 if bundletype not in changegroup.bundletypes:
631 raise util.Abort(_('unknown bundle type specified with --type'))
631 raise util.Abort(_('unknown bundle type specified with --type'))
632
632
633 changegroup.writebundle(cg, fname, bundletype)
633 changegroup.writebundle(cg, fname, bundletype)
634
634
635 def cat(ui, repo, file1, *pats, **opts):
635 def cat(ui, repo, file1, *pats, **opts):
636 """output the current or given revision of files
636 """output the current or given revision of files
637
637
638 Print the specified files as they were at the given revision. If
638 Print the specified files as they were at the given revision. If
639 no revision is given, the parent of the working directory is used,
639 no revision is given, the parent of the working directory is used,
640 or tip if no revision is checked out.
640 or tip if no revision is checked out.
641
641
642 Output may be to a file, in which case the name of the file is
642 Output may be to a file, in which case the name of the file is
643 given using a format string. The formatting rules are the same as
643 given using a format string. The formatting rules are the same as
644 for the export command, with the following additions:
644 for the export command, with the following additions:
645
645
646 :``%s``: basename of file being printed
646 :``%s``: basename of file being printed
647 :``%d``: dirname of file being printed, or '.' if in repository root
647 :``%d``: dirname of file being printed, or '.' if in repository root
648 :``%p``: root-relative path name of file being printed
648 :``%p``: root-relative path name of file being printed
649
649
650 Returns 0 on success.
650 Returns 0 on success.
651 """
651 """
652 ctx = cmdutil.revsingle(repo, opts.get('rev'))
652 ctx = cmdutil.revsingle(repo, opts.get('rev'))
653 err = 1
653 err = 1
654 m = cmdutil.match(repo, (file1,) + pats, opts)
654 m = cmdutil.match(repo, (file1,) + pats, opts)
655 for abs in ctx.walk(m):
655 for abs in ctx.walk(m):
656 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
656 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
657 data = ctx[abs].data()
657 data = ctx[abs].data()
658 if opts.get('decode'):
658 if opts.get('decode'):
659 data = repo.wwritedata(abs, data)
659 data = repo.wwritedata(abs, data)
660 fp.write(data)
660 fp.write(data)
661 err = 0
661 err = 0
662 return err
662 return err
663
663
664 def clone(ui, source, dest=None, **opts):
664 def clone(ui, source, dest=None, **opts):
665 """make a copy of an existing repository
665 """make a copy of an existing repository
666
666
667 Create a copy of an existing repository in a new directory.
667 Create a copy of an existing repository in a new directory.
668
668
669 If no destination directory name is specified, it defaults to the
669 If no destination directory name is specified, it defaults to the
670 basename of the source.
670 basename of the source.
671
671
672 The location of the source is added to the new repository's
672 The location of the source is added to the new repository's
673 .hg/hgrc file, as the default to be used for future pulls.
673 .hg/hgrc file, as the default to be used for future pulls.
674
674
675 See :hg:`help urls` for valid source format details.
675 See :hg:`help urls` for valid source format details.
676
676
677 It is possible to specify an ``ssh://`` URL as the destination, but no
677 It is possible to specify an ``ssh://`` URL as the destination, but no
678 .hg/hgrc and working directory will be created on the remote side.
678 .hg/hgrc and working directory will be created on the remote side.
679 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
679 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
680
680
681 A set of changesets (tags, or branch names) to pull may be specified
681 A set of changesets (tags, or branch names) to pull may be specified
682 by listing each changeset (tag, or branch name) with -r/--rev.
682 by listing each changeset (tag, or branch name) with -r/--rev.
683 If -r/--rev is used, the cloned repository will contain only a subset
683 If -r/--rev is used, the cloned repository will contain only a subset
684 of the changesets of the source repository. Only the set of changesets
684 of the changesets of the source repository. Only the set of changesets
685 defined by all -r/--rev options (including all their ancestors)
685 defined by all -r/--rev options (including all their ancestors)
686 will be pulled into the destination repository.
686 will be pulled into the destination repository.
687 No subsequent changesets (including subsequent tags) will be present
687 No subsequent changesets (including subsequent tags) will be present
688 in the destination.
688 in the destination.
689
689
690 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
690 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
691 local source repositories.
691 local source repositories.
692
692
693 For efficiency, hardlinks are used for cloning whenever the source
693 For efficiency, hardlinks are used for cloning whenever the source
694 and destination are on the same filesystem (note this applies only
694 and destination are on the same filesystem (note this applies only
695 to the repository data, not to the working directory). Some
695 to the repository data, not to the working directory). Some
696 filesystems, such as AFS, implement hardlinking incorrectly, but
696 filesystems, such as AFS, implement hardlinking incorrectly, but
697 do not report errors. In these cases, use the --pull option to
697 do not report errors. In these cases, use the --pull option to
698 avoid hardlinking.
698 avoid hardlinking.
699
699
700 In some cases, you can clone repositories and the working directory
700 In some cases, you can clone repositories and the working directory
701 using full hardlinks with ::
701 using full hardlinks with ::
702
702
703 $ cp -al REPO REPOCLONE
703 $ cp -al REPO REPOCLONE
704
704
705 This is the fastest way to clone, but it is not always safe. The
705 This is the fastest way to clone, but it is not always safe. The
706 operation is not atomic (making sure REPO is not modified during
706 operation is not atomic (making sure REPO is not modified during
707 the operation is up to you) and you have to make sure your editor
707 the operation is up to you) and you have to make sure your editor
708 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
708 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
709 this is not compatible with certain extensions that place their
709 this is not compatible with certain extensions that place their
710 metadata under the .hg directory, such as mq.
710 metadata under the .hg directory, such as mq.
711
711
712 Mercurial will update the working directory to the first applicable
712 Mercurial will update the working directory to the first applicable
713 revision from this list:
713 revision from this list:
714
714
715 a) null if -U or the source repository has no changesets
715 a) null if -U or the source repository has no changesets
716 b) if -u . and the source repository is local, the first parent of
716 b) if -u . and the source repository is local, the first parent of
717 the source repository's working directory
717 the source repository's working directory
718 c) the changeset specified with -u (if a branch name, this means the
718 c) the changeset specified with -u (if a branch name, this means the
719 latest head of that branch)
719 latest head of that branch)
720 d) the changeset specified with -r
720 d) the changeset specified with -r
721 e) the tipmost head specified with -b
721 e) the tipmost head specified with -b
722 f) the tipmost head specified with the url#branch source syntax
722 f) the tipmost head specified with the url#branch source syntax
723 g) the tipmost head of the default branch
723 g) the tipmost head of the default branch
724 h) tip
724 h) tip
725
725
726 Returns 0 on success.
726 Returns 0 on success.
727 """
727 """
728 if opts.get('noupdate') and opts.get('updaterev'):
728 if opts.get('noupdate') and opts.get('updaterev'):
729 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
729 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
730
730
731 r = hg.clone(hg.remoteui(ui, opts), source, dest,
731 r = hg.clone(hg.remoteui(ui, opts), source, dest,
732 pull=opts.get('pull'),
732 pull=opts.get('pull'),
733 stream=opts.get('uncompressed'),
733 stream=opts.get('uncompressed'),
734 rev=opts.get('rev'),
734 rev=opts.get('rev'),
735 update=opts.get('updaterev') or not opts.get('noupdate'),
735 update=opts.get('updaterev') or not opts.get('noupdate'),
736 branch=opts.get('branch'))
736 branch=opts.get('branch'))
737
737
738 return r is None
738 return r is None
739
739
740 def commit(ui, repo, *pats, **opts):
740 def commit(ui, repo, *pats, **opts):
741 """commit the specified files or all outstanding changes
741 """commit the specified files or all outstanding changes
742
742
743 Commit changes to the given files into the repository. Unlike a
743 Commit changes to the given files into the repository. Unlike a
744 centralized RCS, this operation is a local operation. See
744 centralized RCS, this operation is a local operation. See
745 :hg:`push` for a way to actively distribute your changes.
745 :hg:`push` for a way to actively distribute your changes.
746
746
747 If a list of files is omitted, all changes reported by :hg:`status`
747 If a list of files is omitted, all changes reported by :hg:`status`
748 will be committed.
748 will be committed.
749
749
750 If you are committing the result of a merge, do not provide any
750 If you are committing the result of a merge, do not provide any
751 filenames or -I/-X filters.
751 filenames or -I/-X filters.
752
752
753 If no commit message is specified, Mercurial starts your
753 If no commit message is specified, Mercurial starts your
754 configured editor where you can enter a message. In case your
754 configured editor where you can enter a message. In case your
755 commit fails, you will find a backup of your message in
755 commit fails, you will find a backup of your message in
756 ``.hg/last-message.txt``.
756 ``.hg/last-message.txt``.
757
757
758 See :hg:`help dates` for a list of formats valid for -d/--date.
758 See :hg:`help dates` for a list of formats valid for -d/--date.
759
759
760 Returns 0 on success, 1 if nothing changed.
760 Returns 0 on success, 1 if nothing changed.
761 """
761 """
762 extra = {}
762 extra = {}
763 if opts.get('close_branch'):
763 if opts.get('close_branch'):
764 if repo['.'].node() not in repo.branchheads():
764 if repo['.'].node() not in repo.branchheads():
765 # The topo heads set is included in the branch heads set of the
765 # The topo heads set is included in the branch heads set of the
766 # current branch, so it's sufficient to test branchheads
766 # current branch, so it's sufficient to test branchheads
767 raise util.Abort(_('can only close branch heads'))
767 raise util.Abort(_('can only close branch heads'))
768 extra['close'] = 1
768 extra['close'] = 1
769 e = cmdutil.commiteditor
769 e = cmdutil.commiteditor
770 if opts.get('force_editor'):
770 if opts.get('force_editor'):
771 e = cmdutil.commitforceeditor
771 e = cmdutil.commitforceeditor
772
772
773 def commitfunc(ui, repo, message, match, opts):
773 def commitfunc(ui, repo, message, match, opts):
774 return repo.commit(message, opts.get('user'), opts.get('date'), match,
774 return repo.commit(message, opts.get('user'), opts.get('date'), match,
775 editor=e, extra=extra)
775 editor=e, extra=extra)
776
776
777 branch = repo[None].branch()
777 branch = repo[None].branch()
778 bheads = repo.branchheads(branch)
778 bheads = repo.branchheads(branch)
779
779
780 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
780 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
781 if not node:
781 if not node:
782 ui.status(_("nothing changed\n"))
782 ui.status(_("nothing changed\n"))
783 return 1
783 return 1
784
784
785 ctx = repo[node]
785 ctx = repo[node]
786 parents = ctx.parents()
786 parents = ctx.parents()
787
787
788 if bheads and not [x for x in parents
788 if bheads and not [x for x in parents
789 if x.node() in bheads and x.branch() == branch]:
789 if x.node() in bheads and x.branch() == branch]:
790 ui.status(_('created new head\n'))
790 ui.status(_('created new head\n'))
791 # The message is not printed for initial roots. For the other
791 # The message is not printed for initial roots. For the other
792 # changesets, it is printed in the following situations:
792 # changesets, it is printed in the following situations:
793 #
793 #
794 # Par column: for the 2 parents with ...
794 # Par column: for the 2 parents with ...
795 # N: null or no parent
795 # N: null or no parent
796 # B: parent is on another named branch
796 # B: parent is on another named branch
797 # C: parent is a regular non head changeset
797 # C: parent is a regular non head changeset
798 # H: parent was a branch head of the current branch
798 # H: parent was a branch head of the current branch
799 # Msg column: whether we print "created new head" message
799 # Msg column: whether we print "created new head" message
800 # In the following, it is assumed that there already exists some
800 # In the following, it is assumed that there already exists some
801 # initial branch heads of the current branch, otherwise nothing is
801 # initial branch heads of the current branch, otherwise nothing is
802 # printed anyway.
802 # printed anyway.
803 #
803 #
804 # Par Msg Comment
804 # Par Msg Comment
805 # NN y additional topo root
805 # NN y additional topo root
806 #
806 #
807 # BN y additional branch root
807 # BN y additional branch root
808 # CN y additional topo head
808 # CN y additional topo head
809 # HN n usual case
809 # HN n usual case
810 #
810 #
811 # BB y weird additional branch root
811 # BB y weird additional branch root
812 # CB y branch merge
812 # CB y branch merge
813 # HB n merge with named branch
813 # HB n merge with named branch
814 #
814 #
815 # CC y additional head from merge
815 # CC y additional head from merge
816 # CH n merge with a head
816 # CH n merge with a head
817 #
817 #
818 # HH n head merge: head count decreases
818 # HH n head merge: head count decreases
819
819
820 if not opts.get('close_branch'):
820 if not opts.get('close_branch'):
821 for r in parents:
821 for r in parents:
822 if r.extra().get('close') and r.branch() == branch:
822 if r.extra().get('close') and r.branch() == branch:
823 ui.status(_('reopening closed branch head %d\n') % r)
823 ui.status(_('reopening closed branch head %d\n') % r)
824
824
825 if ui.debugflag:
825 if ui.debugflag:
826 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
826 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
827 elif ui.verbose:
827 elif ui.verbose:
828 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
828 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
829
829
830 def copy(ui, repo, *pats, **opts):
830 def copy(ui, repo, *pats, **opts):
831 """mark files as copied for the next commit
831 """mark files as copied for the next commit
832
832
833 Mark dest as having copies of source files. If dest is a
833 Mark dest as having copies of source files. If dest is a
834 directory, copies are put in that directory. If dest is a file,
834 directory, copies are put in that directory. If dest is a file,
835 the source must be a single file.
835 the source must be a single file.
836
836
837 By default, this command copies the contents of files as they
837 By default, this command copies the contents of files as they
838 exist in the working directory. If invoked with -A/--after, the
838 exist in the working directory. If invoked with -A/--after, the
839 operation is recorded, but no copying is performed.
839 operation is recorded, but no copying is performed.
840
840
841 This command takes effect with the next commit. To undo a copy
841 This command takes effect with the next commit. To undo a copy
842 before that, see :hg:`revert`.
842 before that, see :hg:`revert`.
843
843
844 Returns 0 on success, 1 if errors are encountered.
844 Returns 0 on success, 1 if errors are encountered.
845 """
845 """
846 wlock = repo.wlock(False)
846 wlock = repo.wlock(False)
847 try:
847 try:
848 return cmdutil.copy(ui, repo, pats, opts)
848 return cmdutil.copy(ui, repo, pats, opts)
849 finally:
849 finally:
850 wlock.release()
850 wlock.release()
851
851
852 def debugancestor(ui, repo, *args):
852 def debugancestor(ui, repo, *args):
853 """find the ancestor revision of two revisions in a given index"""
853 """find the ancestor revision of two revisions in a given index"""
854 if len(args) == 3:
854 if len(args) == 3:
855 index, rev1, rev2 = args
855 index, rev1, rev2 = args
856 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
856 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
857 lookup = r.lookup
857 lookup = r.lookup
858 elif len(args) == 2:
858 elif len(args) == 2:
859 if not repo:
859 if not repo:
860 raise util.Abort(_("there is no Mercurial repository here "
860 raise util.Abort(_("there is no Mercurial repository here "
861 "(.hg not found)"))
861 "(.hg not found)"))
862 rev1, rev2 = args
862 rev1, rev2 = args
863 r = repo.changelog
863 r = repo.changelog
864 lookup = repo.lookup
864 lookup = repo.lookup
865 else:
865 else:
866 raise util.Abort(_('either two or three arguments required'))
866 raise util.Abort(_('either two or three arguments required'))
867 a = r.ancestor(lookup(rev1), lookup(rev2))
867 a = r.ancestor(lookup(rev1), lookup(rev2))
868 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
868 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
869
869
870 def debugbuilddag(ui, repo, text,
870 def debugbuilddag(ui, repo, text,
871 mergeable_file=False,
871 mergeable_file=False,
872 appended_file=False,
872 appended_file=False,
873 overwritten_file=False,
873 overwritten_file=False,
874 new_file=False):
874 new_file=False):
875 """builds a repo with a given dag from scratch in the current empty repo
875 """builds a repo with a given dag from scratch in the current empty repo
876
876
877 Elements:
877 Elements:
878
878
879 - "+n" is a linear run of n nodes based on the current default parent
879 - "+n" is a linear run of n nodes based on the current default parent
880 - "." is a single node based on the current default parent
880 - "." is a single node based on the current default parent
881 - "$" resets the default parent to null (implied at the start);
881 - "$" resets the default parent to null (implied at the start);
882 otherwise the default parent is always the last node created
882 otherwise the default parent is always the last node created
883 - "<p" sets the default parent to the backref p
883 - "<p" sets the default parent to the backref p
884 - "*p" is a fork at parent p, which is a backref
884 - "*p" is a fork at parent p, which is a backref
885 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
885 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
886 - "/p2" is a merge of the preceding node and p2
886 - "/p2" is a merge of the preceding node and p2
887 - ":tag" defines a local tag for the preceding node
887 - ":tag" defines a local tag for the preceding node
888 - "@branch" sets the named branch for subsequent nodes
888 - "@branch" sets the named branch for subsequent nodes
889 - "!command" runs the command using your shell
889 - "!command" runs the command using your shell
890 - "!!my command\\n" is like "!", but to the end of the line
890 - "!!my command\\n" is like "!", but to the end of the line
891 - "#...\\n" is a comment up to the end of the line
891 - "#...\\n" is a comment up to the end of the line
892
892
893 Whitespace between the above elements is ignored.
893 Whitespace between the above elements is ignored.
894
894
895 A backref is either
895 A backref is either
896
896
897 - a number n, which references the node curr-n, where curr is the current
897 - a number n, which references the node curr-n, where curr is the current
898 node, or
898 node, or
899 - the name of a local tag you placed earlier using ":tag", or
899 - the name of a local tag you placed earlier using ":tag", or
900 - empty to denote the default parent.
900 - empty to denote the default parent.
901
901
902 All string valued-elements are either strictly alphanumeric, or must
902 All string valued-elements are either strictly alphanumeric, or must
903 be enclosed in double quotes ("..."), with "\\" as escape character.
903 be enclosed in double quotes ("..."), with "\\" as escape character.
904
904
905 Note that the --overwritten-file and --appended-file options imply the
905 Note that the --overwritten-file and --appended-file options imply the
906 use of "HGMERGE=internal:local" during DAG buildup.
906 use of "HGMERGE=internal:local" during DAG buildup.
907 """
907 """
908
908
909 if not (mergeable_file or appended_file or overwritten_file or new_file):
909 if not (mergeable_file or appended_file or overwritten_file or new_file):
910 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
910 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
911
911
912 if len(repo.changelog) > 0:
912 if len(repo.changelog) > 0:
913 raise util.Abort(_('repository is not empty'))
913 raise util.Abort(_('repository is not empty'))
914
914
915 if overwritten_file or appended_file:
915 if overwritten_file or appended_file:
916 # we don't want to fail in merges during buildup
916 # we don't want to fail in merges during buildup
917 os.environ['HGMERGE'] = 'internal:local'
917 os.environ['HGMERGE'] = 'internal:local'
918
918
919 def writefile(fname, text, fmode="wb"):
919 def writefile(fname, text, fmode="wb"):
920 f = open(fname, fmode)
920 f = open(fname, fmode)
921 try:
921 try:
922 f.write(text)
922 f.write(text)
923 finally:
923 finally:
924 f.close()
924 f.close()
925
925
926 if mergeable_file:
926 if mergeable_file:
927 linesperrev = 2
927 linesperrev = 2
928 # determine number of revs in DAG
928 # determine number of revs in DAG
929 n = 0
929 n = 0
930 for type, data in dagparser.parsedag(text):
930 for type, data in dagparser.parsedag(text):
931 if type == 'n':
931 if type == 'n':
932 n += 1
932 n += 1
933 # make a file with k lines per rev
933 # make a file with k lines per rev
934 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
934 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
935 + "\n")
935 + "\n")
936
936
937 at = -1
937 at = -1
938 atbranch = 'default'
938 atbranch = 'default'
939 for type, data in dagparser.parsedag(text):
939 for type, data in dagparser.parsedag(text):
940 if type == 'n':
940 if type == 'n':
941 ui.status('node %s\n' % str(data))
941 ui.status('node %s\n' % str(data))
942 id, ps = data
942 id, ps = data
943 p1 = ps[0]
943 p1 = ps[0]
944 if p1 != at:
944 if p1 != at:
945 update(ui, repo, node=str(p1), clean=True)
945 update(ui, repo, node=str(p1), clean=True)
946 at = p1
946 at = p1
947 if repo.dirstate.branch() != atbranch:
947 if repo.dirstate.branch() != atbranch:
948 branch(ui, repo, atbranch, force=True)
948 branch(ui, repo, atbranch, force=True)
949 if len(ps) > 1:
949 if len(ps) > 1:
950 p2 = ps[1]
950 p2 = ps[1]
951 merge(ui, repo, node=p2)
951 merge(ui, repo, node=p2)
952
952
953 if mergeable_file:
953 if mergeable_file:
954 f = open("mf", "rb+")
954 f = open("mf", "rb+")
955 try:
955 try:
956 lines = f.read().split("\n")
956 lines = f.read().split("\n")
957 lines[id * linesperrev] += " r%i" % id
957 lines[id * linesperrev] += " r%i" % id
958 f.seek(0)
958 f.seek(0)
959 f.write("\n".join(lines))
959 f.write("\n".join(lines))
960 finally:
960 finally:
961 f.close()
961 f.close()
962
962
963 if appended_file:
963 if appended_file:
964 writefile("af", "r%i\n" % id, "ab")
964 writefile("af", "r%i\n" % id, "ab")
965
965
966 if overwritten_file:
966 if overwritten_file:
967 writefile("of", "r%i\n" % id)
967 writefile("of", "r%i\n" % id)
968
968
969 if new_file:
969 if new_file:
970 writefile("nf%i" % id, "r%i\n" % id)
970 writefile("nf%i" % id, "r%i\n" % id)
971
971
972 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
972 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
973 at = id
973 at = id
974 elif type == 'l':
974 elif type == 'l':
975 id, name = data
975 id, name = data
976 ui.status('tag %s\n' % name)
976 ui.status('tag %s\n' % name)
977 tag(ui, repo, name, local=True)
977 tag(ui, repo, name, local=True)
978 elif type == 'a':
978 elif type == 'a':
979 ui.status('branch %s\n' % data)
979 ui.status('branch %s\n' % data)
980 atbranch = data
980 atbranch = data
981 elif type in 'cC':
981 elif type in 'cC':
982 r = util.system(data, cwd=repo.root)
982 r = util.system(data, cwd=repo.root)
983 if r:
983 if r:
984 desc, r = util.explain_exit(r)
984 desc, r = util.explain_exit(r)
985 raise util.Abort(_('%s command %s') % (data, desc))
985 raise util.Abort(_('%s command %s') % (data, desc))
986
986
987 def debugcommands(ui, cmd='', *args):
987 def debugcommands(ui, cmd='', *args):
988 """list all available commands and options"""
988 """list all available commands and options"""
989 for cmd, vals in sorted(table.iteritems()):
989 for cmd, vals in sorted(table.iteritems()):
990 cmd = cmd.split('|')[0].strip('^')
990 cmd = cmd.split('|')[0].strip('^')
991 opts = ', '.join([i[1] for i in vals[1]])
991 opts = ', '.join([i[1] for i in vals[1]])
992 ui.write('%s: %s\n' % (cmd, opts))
992 ui.write('%s: %s\n' % (cmd, opts))
993
993
994 def debugcomplete(ui, cmd='', **opts):
994 def debugcomplete(ui, cmd='', **opts):
995 """returns the completion list associated with the given command"""
995 """returns the completion list associated with the given command"""
996
996
997 if opts.get('options'):
997 if opts.get('options'):
998 options = []
998 options = []
999 otables = [globalopts]
999 otables = [globalopts]
1000 if cmd:
1000 if cmd:
1001 aliases, entry = cmdutil.findcmd(cmd, table, False)
1001 aliases, entry = cmdutil.findcmd(cmd, table, False)
1002 otables.append(entry[1])
1002 otables.append(entry[1])
1003 for t in otables:
1003 for t in otables:
1004 for o in t:
1004 for o in t:
1005 if "(DEPRECATED)" in o[3]:
1005 if "(DEPRECATED)" in o[3]:
1006 continue
1006 continue
1007 if o[0]:
1007 if o[0]:
1008 options.append('-%s' % o[0])
1008 options.append('-%s' % o[0])
1009 options.append('--%s' % o[1])
1009 options.append('--%s' % o[1])
1010 ui.write("%s\n" % "\n".join(options))
1010 ui.write("%s\n" % "\n".join(options))
1011 return
1011 return
1012
1012
1013 cmdlist = cmdutil.findpossible(cmd, table)
1013 cmdlist = cmdutil.findpossible(cmd, table)
1014 if ui.verbose:
1014 if ui.verbose:
1015 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1015 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1016 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1016 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1017
1017
1018 def debugfsinfo(ui, path = "."):
1018 def debugfsinfo(ui, path = "."):
1019 """show information detected about current filesystem"""
1019 """show information detected about current filesystem"""
1020 open('.debugfsinfo', 'w').write('')
1020 open('.debugfsinfo', 'w').write('')
1021 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1021 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1022 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1022 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1023 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1023 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1024 and 'yes' or 'no'))
1024 and 'yes' or 'no'))
1025 os.unlink('.debugfsinfo')
1025 os.unlink('.debugfsinfo')
1026
1026
1027 def debugrebuildstate(ui, repo, rev="tip"):
1027 def debugrebuildstate(ui, repo, rev="tip"):
1028 """rebuild the dirstate as it would look like for the given revision"""
1028 """rebuild the dirstate as it would look like for the given revision"""
1029 ctx = repo[rev]
1029 ctx = repo[rev]
1030 wlock = repo.wlock()
1030 wlock = repo.wlock()
1031 try:
1031 try:
1032 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1032 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1033 finally:
1033 finally:
1034 wlock.release()
1034 wlock.release()
1035
1035
1036 def debugcheckstate(ui, repo):
1036 def debugcheckstate(ui, repo):
1037 """validate the correctness of the current dirstate"""
1037 """validate the correctness of the current dirstate"""
1038 parent1, parent2 = repo.dirstate.parents()
1038 parent1, parent2 = repo.dirstate.parents()
1039 m1 = repo[parent1].manifest()
1039 m1 = repo[parent1].manifest()
1040 m2 = repo[parent2].manifest()
1040 m2 = repo[parent2].manifest()
1041 errors = 0
1041 errors = 0
1042 for f in repo.dirstate:
1042 for f in repo.dirstate:
1043 state = repo.dirstate[f]
1043 state = repo.dirstate[f]
1044 if state in "nr" and f not in m1:
1044 if state in "nr" and f not in m1:
1045 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1045 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1046 errors += 1
1046 errors += 1
1047 if state in "a" and f in m1:
1047 if state in "a" and f in m1:
1048 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1048 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1049 errors += 1
1049 errors += 1
1050 if state in "m" and f not in m1 and f not in m2:
1050 if state in "m" and f not in m1 and f not in m2:
1051 ui.warn(_("%s in state %s, but not in either manifest\n") %
1051 ui.warn(_("%s in state %s, but not in either manifest\n") %
1052 (f, state))
1052 (f, state))
1053 errors += 1
1053 errors += 1
1054 for f in m1:
1054 for f in m1:
1055 state = repo.dirstate[f]
1055 state = repo.dirstate[f]
1056 if state not in "nrm":
1056 if state not in "nrm":
1057 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1057 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1058 errors += 1
1058 errors += 1
1059 if errors:
1059 if errors:
1060 error = _(".hg/dirstate inconsistent with current parent's manifest")
1060 error = _(".hg/dirstate inconsistent with current parent's manifest")
1061 raise util.Abort(error)
1061 raise util.Abort(error)
1062
1062
1063 def showconfig(ui, repo, *values, **opts):
1063 def showconfig(ui, repo, *values, **opts):
1064 """show combined config settings from all hgrc files
1064 """show combined config settings from all hgrc files
1065
1065
1066 With no arguments, print names and values of all config items.
1066 With no arguments, print names and values of all config items.
1067
1067
1068 With one argument of the form section.name, print just the value
1068 With one argument of the form section.name, print just the value
1069 of that config item.
1069 of that config item.
1070
1070
1071 With multiple arguments, print names and values of all config
1071 With multiple arguments, print names and values of all config
1072 items with matching section names.
1072 items with matching section names.
1073
1073
1074 With --debug, the source (filename and line number) is printed
1074 With --debug, the source (filename and line number) is printed
1075 for each config item.
1075 for each config item.
1076
1076
1077 Returns 0 on success.
1077 Returns 0 on success.
1078 """
1078 """
1079
1079
1080 for f in util.rcpath():
1080 for f in util.rcpath():
1081 ui.debug(_('read config from: %s\n') % f)
1081 ui.debug(_('read config from: %s\n') % f)
1082 untrusted = bool(opts.get('untrusted'))
1082 untrusted = bool(opts.get('untrusted'))
1083 if values:
1083 if values:
1084 sections = [v for v in values if '.' not in v]
1084 sections = [v for v in values if '.' not in v]
1085 items = [v for v in values if '.' in v]
1085 items = [v for v in values if '.' in v]
1086 if len(items) > 1 or items and sections:
1086 if len(items) > 1 or items and sections:
1087 raise util.Abort(_('only one config item permitted'))
1087 raise util.Abort(_('only one config item permitted'))
1088 for section, name, value in ui.walkconfig(untrusted=untrusted):
1088 for section, name, value in ui.walkconfig(untrusted=untrusted):
1089 sectname = section + '.' + name
1089 sectname = section + '.' + name
1090 if values:
1090 if values:
1091 for v in values:
1091 for v in values:
1092 if v == section:
1092 if v == section:
1093 ui.debug('%s: ' %
1093 ui.debug('%s: ' %
1094 ui.configsource(section, name, untrusted))
1094 ui.configsource(section, name, untrusted))
1095 ui.write('%s=%s\n' % (sectname, value))
1095 ui.write('%s=%s\n' % (sectname, value))
1096 elif v == sectname:
1096 elif v == sectname:
1097 ui.debug('%s: ' %
1097 ui.debug('%s: ' %
1098 ui.configsource(section, name, untrusted))
1098 ui.configsource(section, name, untrusted))
1099 ui.write(value, '\n')
1099 ui.write(value, '\n')
1100 else:
1100 else:
1101 ui.debug('%s: ' %
1101 ui.debug('%s: ' %
1102 ui.configsource(section, name, untrusted))
1102 ui.configsource(section, name, untrusted))
1103 ui.write('%s=%s\n' % (sectname, value))
1103 ui.write('%s=%s\n' % (sectname, value))
1104
1104
1105 def debugpushkey(ui, repopath, namespace, *keyinfo):
1105 def debugpushkey(ui, repopath, namespace, *keyinfo):
1106 '''access the pushkey key/value protocol
1106 '''access the pushkey key/value protocol
1107
1107
1108 With two args, list the keys in the given namespace.
1108 With two args, list the keys in the given namespace.
1109
1109
1110 With five args, set a key to new if it currently is set to old.
1110 With five args, set a key to new if it currently is set to old.
1111 Reports success or failure.
1111 Reports success or failure.
1112 '''
1112 '''
1113
1113
1114 target = hg.repository(ui, repopath)
1114 target = hg.repository(ui, repopath)
1115 if keyinfo:
1115 if keyinfo:
1116 key, old, new = keyinfo
1116 key, old, new = keyinfo
1117 r = target.pushkey(namespace, key, old, new)
1117 r = target.pushkey(namespace, key, old, new)
1118 ui.status(str(r) + '\n')
1118 ui.status(str(r) + '\n')
1119 return not(r)
1119 return not(r)
1120 else:
1120 else:
1121 for k, v in target.listkeys(namespace).iteritems():
1121 for k, v in target.listkeys(namespace).iteritems():
1122 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1122 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1123 v.encode('string-escape')))
1123 v.encode('string-escape')))
1124
1124
1125 def debugrevspec(ui, repo, expr):
1125 def debugrevspec(ui, repo, expr):
1126 '''parse and apply a revision specification'''
1126 '''parse and apply a revision specification'''
1127 if ui.verbose:
1127 if ui.verbose:
1128 tree = revset.parse(expr)
1128 tree = revset.parse(expr)
1129 ui.note(tree, "\n")
1129 ui.note(tree, "\n")
1130 func = revset.match(expr)
1130 func = revset.match(expr)
1131 for c in func(repo, range(len(repo))):
1131 for c in func(repo, range(len(repo))):
1132 ui.write("%s\n" % c)
1132 ui.write("%s\n" % c)
1133
1133
1134 def debugsetparents(ui, repo, rev1, rev2=None):
1134 def debugsetparents(ui, repo, rev1, rev2=None):
1135 """manually set the parents of the current working directory
1135 """manually set the parents of the current working directory
1136
1136
1137 This is useful for writing repository conversion tools, but should
1137 This is useful for writing repository conversion tools, but should
1138 be used with care.
1138 be used with care.
1139
1139
1140 Returns 0 on success.
1140 Returns 0 on success.
1141 """
1141 """
1142
1142
1143 if not rev2:
1143 if not rev2:
1144 rev2 = hex(nullid)
1144 rev2 = hex(nullid)
1145
1145
1146 wlock = repo.wlock()
1146 wlock = repo.wlock()
1147 try:
1147 try:
1148 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1148 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1149 finally:
1149 finally:
1150 wlock.release()
1150 wlock.release()
1151
1151
1152 def debugstate(ui, repo, nodates=None):
1152 def debugstate(ui, repo, nodates=None):
1153 """show the contents of the current dirstate"""
1153 """show the contents of the current dirstate"""
1154 timestr = ""
1154 timestr = ""
1155 showdate = not nodates
1155 showdate = not nodates
1156 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1156 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1157 if showdate:
1157 if showdate:
1158 if ent[3] == -1:
1158 if ent[3] == -1:
1159 # Pad or slice to locale representation
1159 # Pad or slice to locale representation
1160 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1160 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1161 time.localtime(0)))
1161 time.localtime(0)))
1162 timestr = 'unset'
1162 timestr = 'unset'
1163 timestr = (timestr[:locale_len] +
1163 timestr = (timestr[:locale_len] +
1164 ' ' * (locale_len - len(timestr)))
1164 ' ' * (locale_len - len(timestr)))
1165 else:
1165 else:
1166 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1166 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1167 time.localtime(ent[3]))
1167 time.localtime(ent[3]))
1168 if ent[1] & 020000:
1168 if ent[1] & 020000:
1169 mode = 'lnk'
1169 mode = 'lnk'
1170 else:
1170 else:
1171 mode = '%3o' % (ent[1] & 0777)
1171 mode = '%3o' % (ent[1] & 0777)
1172 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1172 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1173 for f in repo.dirstate.copies():
1173 for f in repo.dirstate.copies():
1174 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1174 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1175
1175
1176 def debugsub(ui, repo, rev=None):
1176 def debugsub(ui, repo, rev=None):
1177 if rev == '':
1177 if rev == '':
1178 rev = None
1178 rev = None
1179 for k, v in sorted(repo[rev].substate.items()):
1179 for k, v in sorted(repo[rev].substate.items()):
1180 ui.write('path %s\n' % k)
1180 ui.write('path %s\n' % k)
1181 ui.write(' source %s\n' % v[0])
1181 ui.write(' source %s\n' % v[0])
1182 ui.write(' revision %s\n' % v[1])
1182 ui.write(' revision %s\n' % v[1])
1183
1183
1184 def debugdag(ui, repo, file_=None, *revs, **opts):
1184 def debugdag(ui, repo, file_=None, *revs, **opts):
1185 """format the changelog or an index DAG as a concise textual description
1185 """format the changelog or an index DAG as a concise textual description
1186
1186
1187 If you pass a revlog index, the revlog's DAG is emitted. If you list
1187 If you pass a revlog index, the revlog's DAG is emitted. If you list
1188 revision numbers, they get labelled in the output as rN.
1188 revision numbers, they get labelled in the output as rN.
1189
1189
1190 Otherwise, the changelog DAG of the current repo is emitted.
1190 Otherwise, the changelog DAG of the current repo is emitted.
1191 """
1191 """
1192 spaces = opts.get('spaces')
1192 spaces = opts.get('spaces')
1193 dots = opts.get('dots')
1193 dots = opts.get('dots')
1194 if file_:
1194 if file_:
1195 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1195 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1196 revs = set((int(r) for r in revs))
1196 revs = set((int(r) for r in revs))
1197 def events():
1197 def events():
1198 for r in rlog:
1198 for r in rlog:
1199 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1199 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1200 if r in revs:
1200 if r in revs:
1201 yield 'l', (r, "r%i" % r)
1201 yield 'l', (r, "r%i" % r)
1202 elif repo:
1202 elif repo:
1203 cl = repo.changelog
1203 cl = repo.changelog
1204 tags = opts.get('tags')
1204 tags = opts.get('tags')
1205 branches = opts.get('branches')
1205 branches = opts.get('branches')
1206 if tags:
1206 if tags:
1207 labels = {}
1207 labels = {}
1208 for l, n in repo.tags().items():
1208 for l, n in repo.tags().items():
1209 labels.setdefault(cl.rev(n), []).append(l)
1209 labels.setdefault(cl.rev(n), []).append(l)
1210 def events():
1210 def events():
1211 b = "default"
1211 b = "default"
1212 for r in cl:
1212 for r in cl:
1213 if branches:
1213 if branches:
1214 newb = cl.read(cl.node(r))[5]['branch']
1214 newb = cl.read(cl.node(r))[5]['branch']
1215 if newb != b:
1215 if newb != b:
1216 yield 'a', newb
1216 yield 'a', newb
1217 b = newb
1217 b = newb
1218 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1218 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1219 if tags:
1219 if tags:
1220 ls = labels.get(r)
1220 ls = labels.get(r)
1221 if ls:
1221 if ls:
1222 for l in ls:
1222 for l in ls:
1223 yield 'l', (r, l)
1223 yield 'l', (r, l)
1224 else:
1224 else:
1225 raise util.Abort(_('need repo for changelog dag'))
1225 raise util.Abort(_('need repo for changelog dag'))
1226
1226
1227 for line in dagparser.dagtextlines(events(),
1227 for line in dagparser.dagtextlines(events(),
1228 addspaces=spaces,
1228 addspaces=spaces,
1229 wraplabels=True,
1229 wraplabels=True,
1230 wrapannotations=True,
1230 wrapannotations=True,
1231 wrapnonlinear=dots,
1231 wrapnonlinear=dots,
1232 usedots=dots,
1232 usedots=dots,
1233 maxlinewidth=70):
1233 maxlinewidth=70):
1234 ui.write(line)
1234 ui.write(line)
1235 ui.write("\n")
1235 ui.write("\n")
1236
1236
1237 def debugdata(ui, repo, file_, rev):
1237 def debugdata(ui, repo, file_, rev):
1238 """dump the contents of a data file revision"""
1238 """dump the contents of a data file revision"""
1239 r = None
1239 r = None
1240 if repo:
1240 if repo:
1241 filelog = repo.file(file_)
1241 filelog = repo.file(file_)
1242 if len(filelog):
1242 if len(filelog):
1243 r = filelog
1243 r = filelog
1244 if not r:
1244 if not r:
1245 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1245 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1246 try:
1246 try:
1247 ui.write(r.revision(r.lookup(rev)))
1247 ui.write(r.revision(r.lookup(rev)))
1248 except KeyError:
1248 except KeyError:
1249 raise util.Abort(_('invalid revision identifier %s') % rev)
1249 raise util.Abort(_('invalid revision identifier %s') % rev)
1250
1250
1251 def debugdate(ui, date, range=None, **opts):
1251 def debugdate(ui, date, range=None, **opts):
1252 """parse and display a date"""
1252 """parse and display a date"""
1253 if opts["extended"]:
1253 if opts["extended"]:
1254 d = util.parsedate(date, util.extendeddateformats)
1254 d = util.parsedate(date, util.extendeddateformats)
1255 else:
1255 else:
1256 d = util.parsedate(date)
1256 d = util.parsedate(date)
1257 ui.write("internal: %s %s\n" % d)
1257 ui.write("internal: %s %s\n" % d)
1258 ui.write("standard: %s\n" % util.datestr(d))
1258 ui.write("standard: %s\n" % util.datestr(d))
1259 if range:
1259 if range:
1260 m = util.matchdate(range)
1260 m = util.matchdate(range)
1261 ui.write("match: %s\n" % m(d[0]))
1261 ui.write("match: %s\n" % m(d[0]))
1262
1262
1263 def debugindex(ui, repo, file_):
1263 def debugindex(ui, repo, file_):
1264 """dump the contents of an index file"""
1264 """dump the contents of an index file"""
1265 r = None
1265 r = None
1266 if repo:
1266 if repo:
1267 filelog = repo.file(file_)
1267 filelog = repo.file(file_)
1268 if len(filelog):
1268 if len(filelog):
1269 r = filelog
1269 r = filelog
1270 if not r:
1270 if not r:
1271 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1271 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1272 ui.write(" rev offset length base linkrev"
1272 ui.write(" rev offset length base linkrev"
1273 " nodeid p1 p2\n")
1273 " nodeid p1 p2\n")
1274 for i in r:
1274 for i in r:
1275 node = r.node(i)
1275 node = r.node(i)
1276 try:
1276 try:
1277 pp = r.parents(node)
1277 pp = r.parents(node)
1278 except:
1278 except:
1279 pp = [nullid, nullid]
1279 pp = [nullid, nullid]
1280 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1280 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1281 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1281 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1282 short(node), short(pp[0]), short(pp[1])))
1282 short(node), short(pp[0]), short(pp[1])))
1283
1283
1284 def debugindexdot(ui, repo, file_):
1284 def debugindexdot(ui, repo, file_):
1285 """dump an index DAG as a graphviz dot file"""
1285 """dump an index DAG as a graphviz dot file"""
1286 r = None
1286 r = None
1287 if repo:
1287 if repo:
1288 filelog = repo.file(file_)
1288 filelog = repo.file(file_)
1289 if len(filelog):
1289 if len(filelog):
1290 r = filelog
1290 r = filelog
1291 if not r:
1291 if not r:
1292 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1292 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1293 ui.write("digraph G {\n")
1293 ui.write("digraph G {\n")
1294 for i in r:
1294 for i in r:
1295 node = r.node(i)
1295 node = r.node(i)
1296 pp = r.parents(node)
1296 pp = r.parents(node)
1297 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1297 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1298 if pp[1] != nullid:
1298 if pp[1] != nullid:
1299 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1299 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1300 ui.write("}\n")
1300 ui.write("}\n")
1301
1301
1302 def debuginstall(ui):
1302 def debuginstall(ui):
1303 '''test Mercurial installation
1303 '''test Mercurial installation
1304
1304
1305 Returns 0 on success.
1305 Returns 0 on success.
1306 '''
1306 '''
1307
1307
1308 def writetemp(contents):
1308 def writetemp(contents):
1309 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1309 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1310 f = os.fdopen(fd, "wb")
1310 f = os.fdopen(fd, "wb")
1311 f.write(contents)
1311 f.write(contents)
1312 f.close()
1312 f.close()
1313 return name
1313 return name
1314
1314
1315 problems = 0
1315 problems = 0
1316
1316
1317 # encoding
1317 # encoding
1318 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1318 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1319 try:
1319 try:
1320 encoding.fromlocal("test")
1320 encoding.fromlocal("test")
1321 except util.Abort, inst:
1321 except util.Abort, inst:
1322 ui.write(" %s\n" % inst)
1322 ui.write(" %s\n" % inst)
1323 ui.write(_(" (check that your locale is properly set)\n"))
1323 ui.write(_(" (check that your locale is properly set)\n"))
1324 problems += 1
1324 problems += 1
1325
1325
1326 # compiled modules
1326 # compiled modules
1327 ui.status(_("Checking installed modules (%s)...\n")
1327 ui.status(_("Checking installed modules (%s)...\n")
1328 % os.path.dirname(__file__))
1328 % os.path.dirname(__file__))
1329 try:
1329 try:
1330 import bdiff, mpatch, base85, osutil
1330 import bdiff, mpatch, base85, osutil
1331 except Exception, inst:
1331 except Exception, inst:
1332 ui.write(" %s\n" % inst)
1332 ui.write(" %s\n" % inst)
1333 ui.write(_(" One or more extensions could not be found"))
1333 ui.write(_(" One or more extensions could not be found"))
1334 ui.write(_(" (check that you compiled the extensions)\n"))
1334 ui.write(_(" (check that you compiled the extensions)\n"))
1335 problems += 1
1335 problems += 1
1336
1336
1337 # templates
1337 # templates
1338 ui.status(_("Checking templates...\n"))
1338 ui.status(_("Checking templates...\n"))
1339 try:
1339 try:
1340 import templater
1340 import templater
1341 templater.templater(templater.templatepath("map-cmdline.default"))
1341 templater.templater(templater.templatepath("map-cmdline.default"))
1342 except Exception, inst:
1342 except Exception, inst:
1343 ui.write(" %s\n" % inst)
1343 ui.write(" %s\n" % inst)
1344 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1344 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1345 problems += 1
1345 problems += 1
1346
1346
1347 # patch
1347 # patch
1348 ui.status(_("Checking patch...\n"))
1348 ui.status(_("Checking patch...\n"))
1349 patchproblems = 0
1349 patchproblems = 0
1350 a = "1\n2\n3\n4\n"
1350 a = "1\n2\n3\n4\n"
1351 b = "1\n2\n3\ninsert\n4\n"
1351 b = "1\n2\n3\ninsert\n4\n"
1352 fa = writetemp(a)
1352 fa = writetemp(a)
1353 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1353 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1354 os.path.basename(fa))
1354 os.path.basename(fa))
1355 fd = writetemp(d)
1355 fd = writetemp(d)
1356
1356
1357 files = {}
1357 files = {}
1358 try:
1358 try:
1359 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1359 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1360 except util.Abort, e:
1360 except util.Abort, e:
1361 ui.write(_(" patch call failed:\n"))
1361 ui.write(_(" patch call failed:\n"))
1362 ui.write(" " + str(e) + "\n")
1362 ui.write(" " + str(e) + "\n")
1363 patchproblems += 1
1363 patchproblems += 1
1364 else:
1364 else:
1365 if list(files) != [os.path.basename(fa)]:
1365 if list(files) != [os.path.basename(fa)]:
1366 ui.write(_(" unexpected patch output!\n"))
1366 ui.write(_(" unexpected patch output!\n"))
1367 patchproblems += 1
1367 patchproblems += 1
1368 a = open(fa).read()
1368 a = open(fa).read()
1369 if a != b:
1369 if a != b:
1370 ui.write(_(" patch test failed!\n"))
1370 ui.write(_(" patch test failed!\n"))
1371 patchproblems += 1
1371 patchproblems += 1
1372
1372
1373 if patchproblems:
1373 if patchproblems:
1374 if ui.config('ui', 'patch'):
1374 if ui.config('ui', 'patch'):
1375 ui.write(_(" (Current patch tool may be incompatible with patch,"
1375 ui.write(_(" (Current patch tool may be incompatible with patch,"
1376 " or misconfigured. Please check your configuration"
1376 " or misconfigured. Please check your configuration"
1377 " file)\n"))
1377 " file)\n"))
1378 else:
1378 else:
1379 ui.write(_(" Internal patcher failure, please report this error"
1379 ui.write(_(" Internal patcher failure, please report this error"
1380 " to http://mercurial.selenic.com/bts/\n"))
1380 " to http://mercurial.selenic.com/bts/\n"))
1381 problems += patchproblems
1381 problems += patchproblems
1382
1382
1383 os.unlink(fa)
1383 os.unlink(fa)
1384 os.unlink(fd)
1384 os.unlink(fd)
1385
1385
1386 # editor
1386 # editor
1387 ui.status(_("Checking commit editor...\n"))
1387 ui.status(_("Checking commit editor...\n"))
1388 editor = ui.geteditor()
1388 editor = ui.geteditor()
1389 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1389 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1390 if not cmdpath:
1390 if not cmdpath:
1391 if editor == 'vi':
1391 if editor == 'vi':
1392 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1392 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1393 ui.write(_(" (specify a commit editor in your configuration"
1393 ui.write(_(" (specify a commit editor in your configuration"
1394 " file)\n"))
1394 " file)\n"))
1395 else:
1395 else:
1396 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1396 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1397 ui.write(_(" (specify a commit editor in your configuration"
1397 ui.write(_(" (specify a commit editor in your configuration"
1398 " file)\n"))
1398 " file)\n"))
1399 problems += 1
1399 problems += 1
1400
1400
1401 # check username
1401 # check username
1402 ui.status(_("Checking username...\n"))
1402 ui.status(_("Checking username...\n"))
1403 try:
1403 try:
1404 ui.username()
1404 ui.username()
1405 except util.Abort, e:
1405 except util.Abort, e:
1406 ui.write(" %s\n" % e)
1406 ui.write(" %s\n" % e)
1407 ui.write(_(" (specify a username in your configuration file)\n"))
1407 ui.write(_(" (specify a username in your configuration file)\n"))
1408 problems += 1
1408 problems += 1
1409
1409
1410 if not problems:
1410 if not problems:
1411 ui.status(_("No problems detected\n"))
1411 ui.status(_("No problems detected\n"))
1412 else:
1412 else:
1413 ui.write(_("%s problems detected,"
1413 ui.write(_("%s problems detected,"
1414 " please check your install!\n") % problems)
1414 " please check your install!\n") % problems)
1415
1415
1416 return problems
1416 return problems
1417
1417
1418 def debugrename(ui, repo, file1, *pats, **opts):
1418 def debugrename(ui, repo, file1, *pats, **opts):
1419 """dump rename information"""
1419 """dump rename information"""
1420
1420
1421 ctx = repo[opts.get('rev')]
1421 ctx = repo[opts.get('rev')]
1422 m = cmdutil.match(repo, (file1,) + pats, opts)
1422 m = cmdutil.match(repo, (file1,) + pats, opts)
1423 for abs in ctx.walk(m):
1423 for abs in ctx.walk(m):
1424 fctx = ctx[abs]
1424 fctx = ctx[abs]
1425 o = fctx.filelog().renamed(fctx.filenode())
1425 o = fctx.filelog().renamed(fctx.filenode())
1426 rel = m.rel(abs)
1426 rel = m.rel(abs)
1427 if o:
1427 if o:
1428 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1428 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1429 else:
1429 else:
1430 ui.write(_("%s not renamed\n") % rel)
1430 ui.write(_("%s not renamed\n") % rel)
1431
1431
1432 def debugwalk(ui, repo, *pats, **opts):
1432 def debugwalk(ui, repo, *pats, **opts):
1433 """show how files match on given patterns"""
1433 """show how files match on given patterns"""
1434 m = cmdutil.match(repo, pats, opts)
1434 m = cmdutil.match(repo, pats, opts)
1435 items = list(repo.walk(m))
1435 items = list(repo.walk(m))
1436 if not items:
1436 if not items:
1437 return
1437 return
1438 fmt = 'f %%-%ds %%-%ds %%s' % (
1438 fmt = 'f %%-%ds %%-%ds %%s' % (
1439 max([len(abs) for abs in items]),
1439 max([len(abs) for abs in items]),
1440 max([len(m.rel(abs)) for abs in items]))
1440 max([len(m.rel(abs)) for abs in items]))
1441 for abs in items:
1441 for abs in items:
1442 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1442 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1443 ui.write("%s\n" % line.rstrip())
1443 ui.write("%s\n" % line.rstrip())
1444
1444
1445 def diff(ui, repo, *pats, **opts):
1445 def diff(ui, repo, *pats, **opts):
1446 """diff repository (or selected files)
1446 """diff repository (or selected files)
1447
1447
1448 Show differences between revisions for the specified files.
1448 Show differences between revisions for the specified files.
1449
1449
1450 Differences between files are shown using the unified diff format.
1450 Differences between files are shown using the unified diff format.
1451
1451
1452 .. note::
1452 .. note::
1453 diff may generate unexpected results for merges, as it will
1453 diff may generate unexpected results for merges, as it will
1454 default to comparing against the working directory's first
1454 default to comparing against the working directory's first
1455 parent changeset if no revisions are specified.
1455 parent changeset if no revisions are specified.
1456
1456
1457 When two revision arguments are given, then changes are shown
1457 When two revision arguments are given, then changes are shown
1458 between those revisions. If only one revision is specified then
1458 between those revisions. If only one revision is specified then
1459 that revision is compared to the working directory, and, when no
1459 that revision is compared to the working directory, and, when no
1460 revisions are specified, the working directory files are compared
1460 revisions are specified, the working directory files are compared
1461 to its parent.
1461 to its parent.
1462
1462
1463 Alternatively you can specify -c/--change with a revision to see
1463 Alternatively you can specify -c/--change with a revision to see
1464 the changes in that changeset relative to its first parent.
1464 the changes in that changeset relative to its first parent.
1465
1465
1466 Without the -a/--text option, diff will avoid generating diffs of
1466 Without the -a/--text option, diff will avoid generating diffs of
1467 files it detects as binary. With -a, diff will generate a diff
1467 files it detects as binary. With -a, diff will generate a diff
1468 anyway, probably with undesirable results.
1468 anyway, probably with undesirable results.
1469
1469
1470 Use the -g/--git option to generate diffs in the git extended diff
1470 Use the -g/--git option to generate diffs in the git extended diff
1471 format. For more information, read :hg:`help diffs`.
1471 format. For more information, read :hg:`help diffs`.
1472
1472
1473 Returns 0 on success.
1473 Returns 0 on success.
1474 """
1474 """
1475
1475
1476 revs = opts.get('rev')
1476 revs = opts.get('rev')
1477 change = opts.get('change')
1477 change = opts.get('change')
1478 stat = opts.get('stat')
1478 stat = opts.get('stat')
1479 reverse = opts.get('reverse')
1479 reverse = opts.get('reverse')
1480
1480
1481 if revs and change:
1481 if revs and change:
1482 msg = _('cannot specify --rev and --change at the same time')
1482 msg = _('cannot specify --rev and --change at the same time')
1483 raise util.Abort(msg)
1483 raise util.Abort(msg)
1484 elif change:
1484 elif change:
1485 node2 = repo.lookup(change)
1485 node2 = repo.lookup(change)
1486 node1 = repo[node2].parents()[0].node()
1486 node1 = repo[node2].parents()[0].node()
1487 else:
1487 else:
1488 node1, node2 = cmdutil.revpair(repo, revs)
1488 node1, node2 = cmdutil.revpair(repo, revs)
1489
1489
1490 if reverse:
1490 if reverse:
1491 node1, node2 = node2, node1
1491 node1, node2 = node2, node1
1492
1492
1493 diffopts = patch.diffopts(ui, opts)
1493 diffopts = patch.diffopts(ui, opts)
1494 m = cmdutil.match(repo, pats, opts)
1494 m = cmdutil.match(repo, pats, opts)
1495 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1495 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1496 listsubrepos=opts.get('subrepos'))
1496 listsubrepos=opts.get('subrepos'))
1497
1497
1498 def export(ui, repo, *changesets, **opts):
1498 def export(ui, repo, *changesets, **opts):
1499 """dump the header and diffs for one or more changesets
1499 """dump the header and diffs for one or more changesets
1500
1500
1501 Print the changeset header and diffs for one or more revisions.
1501 Print the changeset header and diffs for one or more revisions.
1502
1502
1503 The information shown in the changeset header is: author, date,
1503 The information shown in the changeset header is: author, date,
1504 branch name (if non-default), changeset hash, parent(s) and commit
1504 branch name (if non-default), changeset hash, parent(s) and commit
1505 comment.
1505 comment.
1506
1506
1507 .. note::
1507 .. note::
1508 export may generate unexpected diff output for merge
1508 export may generate unexpected diff output for merge
1509 changesets, as it will compare the merge changeset against its
1509 changesets, as it will compare the merge changeset against its
1510 first parent only.
1510 first parent only.
1511
1511
1512 Output may be to a file, in which case the name of the file is
1512 Output may be to a file, in which case the name of the file is
1513 given using a format string. The formatting rules are as follows:
1513 given using a format string. The formatting rules are as follows:
1514
1514
1515 :``%%``: literal "%" character
1515 :``%%``: literal "%" character
1516 :``%H``: changeset hash (40 hexadecimal digits)
1516 :``%H``: changeset hash (40 hexadecimal digits)
1517 :``%N``: number of patches being generated
1517 :``%N``: number of patches being generated
1518 :``%R``: changeset revision number
1518 :``%R``: changeset revision number
1519 :``%b``: basename of the exporting repository
1519 :``%b``: basename of the exporting repository
1520 :``%h``: short-form changeset hash (12 hexadecimal digits)
1520 :``%h``: short-form changeset hash (12 hexadecimal digits)
1521 :``%n``: zero-padded sequence number, starting at 1
1521 :``%n``: zero-padded sequence number, starting at 1
1522 :``%r``: zero-padded changeset revision number
1522 :``%r``: zero-padded changeset revision number
1523
1523
1524 Without the -a/--text option, export will avoid generating diffs
1524 Without the -a/--text option, export will avoid generating diffs
1525 of files it detects as binary. With -a, export will generate a
1525 of files it detects as binary. With -a, export will generate a
1526 diff anyway, probably with undesirable results.
1526 diff anyway, probably with undesirable results.
1527
1527
1528 Use the -g/--git option to generate diffs in the git extended diff
1528 Use the -g/--git option to generate diffs in the git extended diff
1529 format. See :hg:`help diffs` for more information.
1529 format. See :hg:`help diffs` for more information.
1530
1530
1531 With the --switch-parent option, the diff will be against the
1531 With the --switch-parent option, the diff will be against the
1532 second parent. It can be useful to review a merge.
1532 second parent. It can be useful to review a merge.
1533
1533
1534 Returns 0 on success.
1534 Returns 0 on success.
1535 """
1535 """
1536 changesets += tuple(opts.get('rev', []))
1536 changesets += tuple(opts.get('rev', []))
1537 if not changesets:
1537 if not changesets:
1538 raise util.Abort(_("export requires at least one changeset"))
1538 raise util.Abort(_("export requires at least one changeset"))
1539 revs = cmdutil.revrange(repo, changesets)
1539 revs = cmdutil.revrange(repo, changesets)
1540 if len(revs) > 1:
1540 if len(revs) > 1:
1541 ui.note(_('exporting patches:\n'))
1541 ui.note(_('exporting patches:\n'))
1542 else:
1542 else:
1543 ui.note(_('exporting patch:\n'))
1543 ui.note(_('exporting patch:\n'))
1544 cmdutil.export(repo, revs, template=opts.get('output'),
1544 cmdutil.export(repo, revs, template=opts.get('output'),
1545 switch_parent=opts.get('switch_parent'),
1545 switch_parent=opts.get('switch_parent'),
1546 opts=patch.diffopts(ui, opts))
1546 opts=patch.diffopts(ui, opts))
1547
1547
1548 def forget(ui, repo, *pats, **opts):
1548 def forget(ui, repo, *pats, **opts):
1549 """forget the specified files on the next commit
1549 """forget the specified files on the next commit
1550
1550
1551 Mark the specified files so they will no longer be tracked
1551 Mark the specified files so they will no longer be tracked
1552 after the next commit.
1552 after the next commit.
1553
1553
1554 This only removes files from the current branch, not from the
1554 This only removes files from the current branch, not from the
1555 entire project history, and it does not delete them from the
1555 entire project history, and it does not delete them from the
1556 working directory.
1556 working directory.
1557
1557
1558 To undo a forget before the next commit, see :hg:`add`.
1558 To undo a forget before the next commit, see :hg:`add`.
1559
1559
1560 Returns 0 on success.
1560 Returns 0 on success.
1561 """
1561 """
1562
1562
1563 if not pats:
1563 if not pats:
1564 raise util.Abort(_('no files specified'))
1564 raise util.Abort(_('no files specified'))
1565
1565
1566 m = cmdutil.match(repo, pats, opts)
1566 m = cmdutil.match(repo, pats, opts)
1567 s = repo.status(match=m, clean=True)
1567 s = repo.status(match=m, clean=True)
1568 forget = sorted(s[0] + s[1] + s[3] + s[6])
1568 forget = sorted(s[0] + s[1] + s[3] + s[6])
1569 errs = 0
1569 errs = 0
1570
1570
1571 for f in m.files():
1571 for f in m.files():
1572 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1572 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1573 ui.warn(_('not removing %s: file is already untracked\n')
1573 ui.warn(_('not removing %s: file is already untracked\n')
1574 % m.rel(f))
1574 % m.rel(f))
1575 errs = 1
1575 errs = 1
1576
1576
1577 for f in forget:
1577 for f in forget:
1578 if ui.verbose or not m.exact(f):
1578 if ui.verbose or not m.exact(f):
1579 ui.status(_('removing %s\n') % m.rel(f))
1579 ui.status(_('removing %s\n') % m.rel(f))
1580
1580
1581 repo[None].remove(forget, unlink=False)
1581 repo[None].remove(forget, unlink=False)
1582 return errs
1582 return errs
1583
1583
1584 def grep(ui, repo, pattern, *pats, **opts):
1584 def grep(ui, repo, pattern, *pats, **opts):
1585 """search for a pattern in specified files and revisions
1585 """search for a pattern in specified files and revisions
1586
1586
1587 Search revisions of files for a regular expression.
1587 Search revisions of files for a regular expression.
1588
1588
1589 This command behaves differently than Unix grep. It only accepts
1589 This command behaves differently than Unix grep. It only accepts
1590 Python/Perl regexps. It searches repository history, not the
1590 Python/Perl regexps. It searches repository history, not the
1591 working directory. It always prints the revision number in which a
1591 working directory. It always prints the revision number in which a
1592 match appears.
1592 match appears.
1593
1593
1594 By default, grep only prints output for the first revision of a
1594 By default, grep only prints output for the first revision of a
1595 file in which it finds a match. To get it to print every revision
1595 file in which it finds a match. To get it to print every revision
1596 that contains a change in match status ("-" for a match that
1596 that contains a change in match status ("-" for a match that
1597 becomes a non-match, or "+" for a non-match that becomes a match),
1597 becomes a non-match, or "+" for a non-match that becomes a match),
1598 use the --all flag.
1598 use the --all flag.
1599
1599
1600 Returns 0 if a match is found, 1 otherwise.
1600 Returns 0 if a match is found, 1 otherwise.
1601 """
1601 """
1602 reflags = 0
1602 reflags = 0
1603 if opts.get('ignore_case'):
1603 if opts.get('ignore_case'):
1604 reflags |= re.I
1604 reflags |= re.I
1605 try:
1605 try:
1606 regexp = re.compile(pattern, reflags)
1606 regexp = re.compile(pattern, reflags)
1607 except re.error, inst:
1607 except re.error, inst:
1608 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1608 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1609 return 1
1609 return 1
1610 sep, eol = ':', '\n'
1610 sep, eol = ':', '\n'
1611 if opts.get('print0'):
1611 if opts.get('print0'):
1612 sep = eol = '\0'
1612 sep = eol = '\0'
1613
1613
1614 getfile = util.lrucachefunc(repo.file)
1614 getfile = util.lrucachefunc(repo.file)
1615
1615
1616 def matchlines(body):
1616 def matchlines(body):
1617 begin = 0
1617 begin = 0
1618 linenum = 0
1618 linenum = 0
1619 while True:
1619 while True:
1620 match = regexp.search(body, begin)
1620 match = regexp.search(body, begin)
1621 if not match:
1621 if not match:
1622 break
1622 break
1623 mstart, mend = match.span()
1623 mstart, mend = match.span()
1624 linenum += body.count('\n', begin, mstart) + 1
1624 linenum += body.count('\n', begin, mstart) + 1
1625 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1625 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1626 begin = body.find('\n', mend) + 1 or len(body)
1626 begin = body.find('\n', mend) + 1 or len(body)
1627 lend = begin - 1
1627 lend = begin - 1
1628 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1628 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1629
1629
1630 class linestate(object):
1630 class linestate(object):
1631 def __init__(self, line, linenum, colstart, colend):
1631 def __init__(self, line, linenum, colstart, colend):
1632 self.line = line
1632 self.line = line
1633 self.linenum = linenum
1633 self.linenum = linenum
1634 self.colstart = colstart
1634 self.colstart = colstart
1635 self.colend = colend
1635 self.colend = colend
1636
1636
1637 def __hash__(self):
1637 def __hash__(self):
1638 return hash((self.linenum, self.line))
1638 return hash((self.linenum, self.line))
1639
1639
1640 def __eq__(self, other):
1640 def __eq__(self, other):
1641 return self.line == other.line
1641 return self.line == other.line
1642
1642
1643 matches = {}
1643 matches = {}
1644 copies = {}
1644 copies = {}
1645 def grepbody(fn, rev, body):
1645 def grepbody(fn, rev, body):
1646 matches[rev].setdefault(fn, [])
1646 matches[rev].setdefault(fn, [])
1647 m = matches[rev][fn]
1647 m = matches[rev][fn]
1648 for lnum, cstart, cend, line in matchlines(body):
1648 for lnum, cstart, cend, line in matchlines(body):
1649 s = linestate(line, lnum, cstart, cend)
1649 s = linestate(line, lnum, cstart, cend)
1650 m.append(s)
1650 m.append(s)
1651
1651
1652 def difflinestates(a, b):
1652 def difflinestates(a, b):
1653 sm = difflib.SequenceMatcher(None, a, b)
1653 sm = difflib.SequenceMatcher(None, a, b)
1654 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1654 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1655 if tag == 'insert':
1655 if tag == 'insert':
1656 for i in xrange(blo, bhi):
1656 for i in xrange(blo, bhi):
1657 yield ('+', b[i])
1657 yield ('+', b[i])
1658 elif tag == 'delete':
1658 elif tag == 'delete':
1659 for i in xrange(alo, ahi):
1659 for i in xrange(alo, ahi):
1660 yield ('-', a[i])
1660 yield ('-', a[i])
1661 elif tag == 'replace':
1661 elif tag == 'replace':
1662 for i in xrange(alo, ahi):
1662 for i in xrange(alo, ahi):
1663 yield ('-', a[i])
1663 yield ('-', a[i])
1664 for i in xrange(blo, bhi):
1664 for i in xrange(blo, bhi):
1665 yield ('+', b[i])
1665 yield ('+', b[i])
1666
1666
1667 def display(fn, ctx, pstates, states):
1667 def display(fn, ctx, pstates, states):
1668 rev = ctx.rev()
1668 rev = ctx.rev()
1669 datefunc = ui.quiet and util.shortdate or util.datestr
1669 datefunc = ui.quiet and util.shortdate or util.datestr
1670 found = False
1670 found = False
1671 filerevmatches = {}
1671 filerevmatches = {}
1672 if opts.get('all'):
1672 if opts.get('all'):
1673 iter = difflinestates(pstates, states)
1673 iter = difflinestates(pstates, states)
1674 else:
1674 else:
1675 iter = [('', l) for l in states]
1675 iter = [('', l) for l in states]
1676 for change, l in iter:
1676 for change, l in iter:
1677 cols = [fn, str(rev)]
1677 cols = [fn, str(rev)]
1678 before, match, after = None, None, None
1678 before, match, after = None, None, None
1679 if opts.get('line_number'):
1679 if opts.get('line_number'):
1680 cols.append(str(l.linenum))
1680 cols.append(str(l.linenum))
1681 if opts.get('all'):
1681 if opts.get('all'):
1682 cols.append(change)
1682 cols.append(change)
1683 if opts.get('user'):
1683 if opts.get('user'):
1684 cols.append(ui.shortuser(ctx.user()))
1684 cols.append(ui.shortuser(ctx.user()))
1685 if opts.get('date'):
1685 if opts.get('date'):
1686 cols.append(datefunc(ctx.date()))
1686 cols.append(datefunc(ctx.date()))
1687 if opts.get('files_with_matches'):
1687 if opts.get('files_with_matches'):
1688 c = (fn, rev)
1688 c = (fn, rev)
1689 if c in filerevmatches:
1689 if c in filerevmatches:
1690 continue
1690 continue
1691 filerevmatches[c] = 1
1691 filerevmatches[c] = 1
1692 else:
1692 else:
1693 before = l.line[:l.colstart]
1693 before = l.line[:l.colstart]
1694 match = l.line[l.colstart:l.colend]
1694 match = l.line[l.colstart:l.colend]
1695 after = l.line[l.colend:]
1695 after = l.line[l.colend:]
1696 ui.write(sep.join(cols))
1696 ui.write(sep.join(cols))
1697 if before is not None:
1697 if before is not None:
1698 ui.write(sep + before)
1698 ui.write(sep + before)
1699 ui.write(match, label='grep.match')
1699 ui.write(match, label='grep.match')
1700 ui.write(after)
1700 ui.write(after)
1701 ui.write(eol)
1701 ui.write(eol)
1702 found = True
1702 found = True
1703 return found
1703 return found
1704
1704
1705 skip = {}
1705 skip = {}
1706 revfiles = {}
1706 revfiles = {}
1707 matchfn = cmdutil.match(repo, pats, opts)
1707 matchfn = cmdutil.match(repo, pats, opts)
1708 found = False
1708 found = False
1709 follow = opts.get('follow')
1709 follow = opts.get('follow')
1710
1710
1711 def prep(ctx, fns):
1711 def prep(ctx, fns):
1712 rev = ctx.rev()
1712 rev = ctx.rev()
1713 pctx = ctx.parents()[0]
1713 pctx = ctx.parents()[0]
1714 parent = pctx.rev()
1714 parent = pctx.rev()
1715 matches.setdefault(rev, {})
1715 matches.setdefault(rev, {})
1716 matches.setdefault(parent, {})
1716 matches.setdefault(parent, {})
1717 files = revfiles.setdefault(rev, [])
1717 files = revfiles.setdefault(rev, [])
1718 for fn in fns:
1718 for fn in fns:
1719 flog = getfile(fn)
1719 flog = getfile(fn)
1720 try:
1720 try:
1721 fnode = ctx.filenode(fn)
1721 fnode = ctx.filenode(fn)
1722 except error.LookupError:
1722 except error.LookupError:
1723 continue
1723 continue
1724
1724
1725 copied = flog.renamed(fnode)
1725 copied = flog.renamed(fnode)
1726 copy = follow and copied and copied[0]
1726 copy = follow and copied and copied[0]
1727 if copy:
1727 if copy:
1728 copies.setdefault(rev, {})[fn] = copy
1728 copies.setdefault(rev, {})[fn] = copy
1729 if fn in skip:
1729 if fn in skip:
1730 if copy:
1730 if copy:
1731 skip[copy] = True
1731 skip[copy] = True
1732 continue
1732 continue
1733 files.append(fn)
1733 files.append(fn)
1734
1734
1735 if fn not in matches[rev]:
1735 if fn not in matches[rev]:
1736 grepbody(fn, rev, flog.read(fnode))
1736 grepbody(fn, rev, flog.read(fnode))
1737
1737
1738 pfn = copy or fn
1738 pfn = copy or fn
1739 if pfn not in matches[parent]:
1739 if pfn not in matches[parent]:
1740 try:
1740 try:
1741 fnode = pctx.filenode(pfn)
1741 fnode = pctx.filenode(pfn)
1742 grepbody(pfn, parent, flog.read(fnode))
1742 grepbody(pfn, parent, flog.read(fnode))
1743 except error.LookupError:
1743 except error.LookupError:
1744 pass
1744 pass
1745
1745
1746 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1746 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1747 rev = ctx.rev()
1747 rev = ctx.rev()
1748 parent = ctx.parents()[0].rev()
1748 parent = ctx.parents()[0].rev()
1749 for fn in sorted(revfiles.get(rev, [])):
1749 for fn in sorted(revfiles.get(rev, [])):
1750 states = matches[rev][fn]
1750 states = matches[rev][fn]
1751 copy = copies.get(rev, {}).get(fn)
1751 copy = copies.get(rev, {}).get(fn)
1752 if fn in skip:
1752 if fn in skip:
1753 if copy:
1753 if copy:
1754 skip[copy] = True
1754 skip[copy] = True
1755 continue
1755 continue
1756 pstates = matches.get(parent, {}).get(copy or fn, [])
1756 pstates = matches.get(parent, {}).get(copy or fn, [])
1757 if pstates or states:
1757 if pstates or states:
1758 r = display(fn, ctx, pstates, states)
1758 r = display(fn, ctx, pstates, states)
1759 found = found or r
1759 found = found or r
1760 if r and not opts.get('all'):
1760 if r and not opts.get('all'):
1761 skip[fn] = True
1761 skip[fn] = True
1762 if copy:
1762 if copy:
1763 skip[copy] = True
1763 skip[copy] = True
1764 del matches[rev]
1764 del matches[rev]
1765 del revfiles[rev]
1765 del revfiles[rev]
1766
1766
1767 return not found
1767 return not found
1768
1768
1769 def heads(ui, repo, *branchrevs, **opts):
1769 def heads(ui, repo, *branchrevs, **opts):
1770 """show current repository heads or show branch heads
1770 """show current repository heads or show branch heads
1771
1771
1772 With no arguments, show all repository branch heads.
1772 With no arguments, show all repository branch heads.
1773
1773
1774 Repository "heads" are changesets with no child changesets. They are
1774 Repository "heads" are changesets with no child changesets. They are
1775 where development generally takes place and are the usual targets
1775 where development generally takes place and are the usual targets
1776 for update and merge operations. Branch heads are changesets that have
1776 for update and merge operations. Branch heads are changesets that have
1777 no child changeset on the same branch.
1777 no child changeset on the same branch.
1778
1778
1779 If one or more REVs are given, only branch heads on the branches
1779 If one or more REVs are given, only branch heads on the branches
1780 associated with the specified changesets are shown.
1780 associated with the specified changesets are shown.
1781
1781
1782 If -c/--closed is specified, also show branch heads marked closed
1782 If -c/--closed is specified, also show branch heads marked closed
1783 (see :hg:`commit --close-branch`).
1783 (see :hg:`commit --close-branch`).
1784
1784
1785 If STARTREV is specified, only those heads that are descendants of
1785 If STARTREV is specified, only those heads that are descendants of
1786 STARTREV will be displayed.
1786 STARTREV will be displayed.
1787
1787
1788 If -t/--topo is specified, named branch mechanics will be ignored and only
1788 If -t/--topo is specified, named branch mechanics will be ignored and only
1789 changesets without children will be shown.
1789 changesets without children will be shown.
1790
1790
1791 Returns 0 if matching heads are found, 1 if not.
1791 Returns 0 if matching heads are found, 1 if not.
1792 """
1792 """
1793
1793
1794 if opts.get('rev'):
1794 if opts.get('rev'):
1795 start = repo.lookup(opts['rev'])
1795 start = repo.lookup(opts['rev'])
1796 else:
1796 else:
1797 start = None
1797 start = None
1798
1798
1799 if opts.get('topo'):
1799 if opts.get('topo'):
1800 heads = [repo[h] for h in repo.heads(start)]
1800 heads = [repo[h] for h in repo.heads(start)]
1801 else:
1801 else:
1802 heads = []
1802 heads = []
1803 for b, ls in repo.branchmap().iteritems():
1803 for b, ls in repo.branchmap().iteritems():
1804 if start is None:
1804 if start is None:
1805 heads += [repo[h] for h in ls]
1805 heads += [repo[h] for h in ls]
1806 continue
1806 continue
1807 startrev = repo.changelog.rev(start)
1807 startrev = repo.changelog.rev(start)
1808 descendants = set(repo.changelog.descendants(startrev))
1808 descendants = set(repo.changelog.descendants(startrev))
1809 descendants.add(startrev)
1809 descendants.add(startrev)
1810 rev = repo.changelog.rev
1810 rev = repo.changelog.rev
1811 heads += [repo[h] for h in ls if rev(h) in descendants]
1811 heads += [repo[h] for h in ls if rev(h) in descendants]
1812
1812
1813 if branchrevs:
1813 if branchrevs:
1814 decode, encode = encoding.fromlocal, encoding.tolocal
1814 decode, encode = encoding.fromlocal, encoding.tolocal
1815 branches = set(repo[decode(br)].branch() for br in branchrevs)
1815 branches = set(repo[decode(br)].branch() for br in branchrevs)
1816 heads = [h for h in heads if h.branch() in branches]
1816 heads = [h for h in heads if h.branch() in branches]
1817
1817
1818 if not opts.get('closed'):
1818 if not opts.get('closed'):
1819 heads = [h for h in heads if not h.extra().get('close')]
1819 heads = [h for h in heads if not h.extra().get('close')]
1820
1820
1821 if opts.get('active') and branchrevs:
1821 if opts.get('active') and branchrevs:
1822 dagheads = repo.heads(start)
1822 dagheads = repo.heads(start)
1823 heads = [h for h in heads if h.node() in dagheads]
1823 heads = [h for h in heads if h.node() in dagheads]
1824
1824
1825 if branchrevs:
1825 if branchrevs:
1826 haveheads = set(h.branch() for h in heads)
1826 haveheads = set(h.branch() for h in heads)
1827 if branches - haveheads:
1827 if branches - haveheads:
1828 headless = ', '.join(encode(b) for b in branches - haveheads)
1828 headless = ', '.join(encode(b) for b in branches - haveheads)
1829 msg = _('no open branch heads found on branches %s')
1829 msg = _('no open branch heads found on branches %s')
1830 if opts.get('rev'):
1830 if opts.get('rev'):
1831 msg += _(' (started at %s)' % opts['rev'])
1831 msg += _(' (started at %s)' % opts['rev'])
1832 ui.warn((msg + '\n') % headless)
1832 ui.warn((msg + '\n') % headless)
1833
1833
1834 if not heads:
1834 if not heads:
1835 return 1
1835 return 1
1836
1836
1837 heads = sorted(heads, key=lambda x: -x.rev())
1837 heads = sorted(heads, key=lambda x: -x.rev())
1838 displayer = cmdutil.show_changeset(ui, repo, opts)
1838 displayer = cmdutil.show_changeset(ui, repo, opts)
1839 for ctx in heads:
1839 for ctx in heads:
1840 displayer.show(ctx)
1840 displayer.show(ctx)
1841 displayer.close()
1841 displayer.close()
1842
1842
1843 def help_(ui, name=None, with_version=False, unknowncmd=False):
1843 def help_(ui, name=None, with_version=False, unknowncmd=False):
1844 """show help for a given topic or a help overview
1844 """show help for a given topic or a help overview
1845
1845
1846 With no arguments, print a list of commands with short help messages.
1846 With no arguments, print a list of commands with short help messages.
1847
1847
1848 Given a topic, extension, or command name, print help for that
1848 Given a topic, extension, or command name, print help for that
1849 topic.
1849 topic.
1850
1850
1851 Returns 0 if successful.
1851 Returns 0 if successful.
1852 """
1852 """
1853 option_lists = []
1853 option_lists = []
1854 textwidth = ui.termwidth() - 2
1854 textwidth = ui.termwidth() - 2
1855
1855
1856 def addglobalopts(aliases):
1856 def addglobalopts(aliases):
1857 if ui.verbose:
1857 if ui.verbose:
1858 option_lists.append((_("global options:"), globalopts))
1858 option_lists.append((_("global options:"), globalopts))
1859 if name == 'shortlist':
1859 if name == 'shortlist':
1860 option_lists.append((_('use "hg help" for the full list '
1860 option_lists.append((_('use "hg help" for the full list '
1861 'of commands'), ()))
1861 'of commands'), ()))
1862 else:
1862 else:
1863 if name == 'shortlist':
1863 if name == 'shortlist':
1864 msg = _('use "hg help" for the full list of commands '
1864 msg = _('use "hg help" for the full list of commands '
1865 'or "hg -v" for details')
1865 'or "hg -v" for details')
1866 elif aliases:
1866 elif aliases:
1867 msg = _('use "hg -v help%s" to show aliases and '
1867 msg = _('use "hg -v help%s" to show aliases and '
1868 'global options') % (name and " " + name or "")
1868 'global options') % (name and " " + name or "")
1869 else:
1869 else:
1870 msg = _('use "hg -v help %s" to show global options') % name
1870 msg = _('use "hg -v help %s" to show global options') % name
1871 option_lists.append((msg, ()))
1871 option_lists.append((msg, ()))
1872
1872
1873 def helpcmd(name):
1873 def helpcmd(name):
1874 if with_version:
1874 if with_version:
1875 version_(ui)
1875 version_(ui)
1876 ui.write('\n')
1876 ui.write('\n')
1877
1877
1878 try:
1878 try:
1879 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1879 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1880 except error.AmbiguousCommand, inst:
1880 except error.AmbiguousCommand, inst:
1881 # py3k fix: except vars can't be used outside the scope of the
1881 # py3k fix: except vars can't be used outside the scope of the
1882 # except block, nor can be used inside a lambda. python issue4617
1882 # except block, nor can be used inside a lambda. python issue4617
1883 prefix = inst.args[0]
1883 prefix = inst.args[0]
1884 select = lambda c: c.lstrip('^').startswith(prefix)
1884 select = lambda c: c.lstrip('^').startswith(prefix)
1885 helplist(_('list of commands:\n\n'), select)
1885 helplist(_('list of commands:\n\n'), select)
1886 return
1886 return
1887
1887
1888 # check if it's an invalid alias and display its error if it is
1888 # check if it's an invalid alias and display its error if it is
1889 if getattr(entry[0], 'badalias', False):
1889 if getattr(entry[0], 'badalias', False):
1890 if not unknowncmd:
1890 if not unknowncmd:
1891 entry[0](ui)
1891 entry[0](ui)
1892 return
1892 return
1893
1893
1894 # synopsis
1894 # synopsis
1895 if len(entry) > 2:
1895 if len(entry) > 2:
1896 if entry[2].startswith('hg'):
1896 if entry[2].startswith('hg'):
1897 ui.write("%s\n" % entry[2])
1897 ui.write("%s\n" % entry[2])
1898 else:
1898 else:
1899 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1899 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1900 else:
1900 else:
1901 ui.write('hg %s\n' % aliases[0])
1901 ui.write('hg %s\n' % aliases[0])
1902
1902
1903 # aliases
1903 # aliases
1904 if not ui.quiet and len(aliases) > 1:
1904 if not ui.quiet and len(aliases) > 1:
1905 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1905 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1906
1906
1907 # description
1907 # description
1908 doc = gettext(entry[0].__doc__)
1908 doc = gettext(entry[0].__doc__)
1909 if not doc:
1909 if not doc:
1910 doc = _("(no help text available)")
1910 doc = _("(no help text available)")
1911 if hasattr(entry[0], 'definition'): # aliased command
1911 if hasattr(entry[0], 'definition'): # aliased command
1912 if entry[0].definition.startswith('!'): # shell alias
1912 if entry[0].definition.startswith('!'): # shell alias
1913 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1913 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1914 else:
1914 else:
1915 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1915 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1916 if ui.quiet:
1916 if ui.quiet:
1917 doc = doc.splitlines()[0]
1917 doc = doc.splitlines()[0]
1918 keep = ui.verbose and ['verbose'] or []
1918 keep = ui.verbose and ['verbose'] or []
1919 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1919 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1920 ui.write("\n%s\n" % formatted)
1920 ui.write("\n%s\n" % formatted)
1921 if pruned:
1921 if pruned:
1922 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1922 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1923
1923
1924 if not ui.quiet:
1924 if not ui.quiet:
1925 # options
1925 # options
1926 if entry[1]:
1926 if entry[1]:
1927 option_lists.append((_("options:\n"), entry[1]))
1927 option_lists.append((_("options:\n"), entry[1]))
1928
1928
1929 addglobalopts(False)
1929 addglobalopts(False)
1930
1930
1931 def helplist(header, select=None):
1931 def helplist(header, select=None):
1932 h = {}
1932 h = {}
1933 cmds = {}
1933 cmds = {}
1934 for c, e in table.iteritems():
1934 for c, e in table.iteritems():
1935 f = c.split("|", 1)[0]
1935 f = c.split("|", 1)[0]
1936 if select and not select(f):
1936 if select and not select(f):
1937 continue
1937 continue
1938 if (not select and name != 'shortlist' and
1938 if (not select and name != 'shortlist' and
1939 e[0].__module__ != __name__):
1939 e[0].__module__ != __name__):
1940 continue
1940 continue
1941 if name == "shortlist" and not f.startswith("^"):
1941 if name == "shortlist" and not f.startswith("^"):
1942 continue
1942 continue
1943 f = f.lstrip("^")
1943 f = f.lstrip("^")
1944 if not ui.debugflag and f.startswith("debug"):
1944 if not ui.debugflag and f.startswith("debug"):
1945 continue
1945 continue
1946 doc = e[0].__doc__
1946 doc = e[0].__doc__
1947 if doc and 'DEPRECATED' in doc and not ui.verbose:
1947 if doc and 'DEPRECATED' in doc and not ui.verbose:
1948 continue
1948 continue
1949 doc = gettext(doc)
1949 doc = gettext(doc)
1950 if not doc:
1950 if not doc:
1951 doc = _("(no help text available)")
1951 doc = _("(no help text available)")
1952 h[f] = doc.splitlines()[0].rstrip()
1952 h[f] = doc.splitlines()[0].rstrip()
1953 cmds[f] = c.lstrip("^")
1953 cmds[f] = c.lstrip("^")
1954
1954
1955 if not h:
1955 if not h:
1956 ui.status(_('no commands defined\n'))
1956 ui.status(_('no commands defined\n'))
1957 return
1957 return
1958
1958
1959 ui.status(header)
1959 ui.status(header)
1960 fns = sorted(h)
1960 fns = sorted(h)
1961 m = max(map(len, fns))
1961 m = max(map(len, fns))
1962 for f in fns:
1962 for f in fns:
1963 if ui.verbose:
1963 if ui.verbose:
1964 commands = cmds[f].replace("|",", ")
1964 commands = cmds[f].replace("|",", ")
1965 ui.write(" %s:\n %s\n"%(commands, h[f]))
1965 ui.write(" %s:\n %s\n"%(commands, h[f]))
1966 else:
1966 else:
1967 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1967 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1968 initindent=' %-*s ' % (m, f),
1968 initindent=' %-*s ' % (m, f),
1969 hangindent=' ' * (m + 4))))
1969 hangindent=' ' * (m + 4))))
1970
1970
1971 if not ui.quiet:
1971 if not ui.quiet:
1972 addglobalopts(True)
1972 addglobalopts(True)
1973
1973
1974 def helptopic(name):
1974 def helptopic(name):
1975 for names, header, doc in help.helptable:
1975 for names, header, doc in help.helptable:
1976 if name in names:
1976 if name in names:
1977 break
1977 break
1978 else:
1978 else:
1979 raise error.UnknownCommand(name)
1979 raise error.UnknownCommand(name)
1980
1980
1981 # description
1981 # description
1982 if not doc:
1982 if not doc:
1983 doc = _("(no help text available)")
1983 doc = _("(no help text available)")
1984 if hasattr(doc, '__call__'):
1984 if hasattr(doc, '__call__'):
1985 doc = doc()
1985 doc = doc()
1986
1986
1987 ui.write("%s\n\n" % header)
1987 ui.write("%s\n\n" % header)
1988 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1988 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1989
1989
1990 def helpext(name):
1990 def helpext(name):
1991 try:
1991 try:
1992 mod = extensions.find(name)
1992 mod = extensions.find(name)
1993 doc = gettext(mod.__doc__) or _('no help text available')
1993 doc = gettext(mod.__doc__) or _('no help text available')
1994 except KeyError:
1994 except KeyError:
1995 mod = None
1995 mod = None
1996 doc = extensions.disabledext(name)
1996 doc = extensions.disabledext(name)
1997 if not doc:
1997 if not doc:
1998 raise error.UnknownCommand(name)
1998 raise error.UnknownCommand(name)
1999
1999
2000 if '\n' not in doc:
2000 if '\n' not in doc:
2001 head, tail = doc, ""
2001 head, tail = doc, ""
2002 else:
2002 else:
2003 head, tail = doc.split('\n', 1)
2003 head, tail = doc.split('\n', 1)
2004 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2004 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2005 if tail:
2005 if tail:
2006 ui.write(minirst.format(tail, textwidth))
2006 ui.write(minirst.format(tail, textwidth))
2007 ui.status('\n\n')
2007 ui.status('\n\n')
2008
2008
2009 if mod:
2009 if mod:
2010 try:
2010 try:
2011 ct = mod.cmdtable
2011 ct = mod.cmdtable
2012 except AttributeError:
2012 except AttributeError:
2013 ct = {}
2013 ct = {}
2014 modcmds = set([c.split('|', 1)[0] for c in ct])
2014 modcmds = set([c.split('|', 1)[0] for c in ct])
2015 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2015 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2016 else:
2016 else:
2017 ui.write(_('use "hg help extensions" for information on enabling '
2017 ui.write(_('use "hg help extensions" for information on enabling '
2018 'extensions\n'))
2018 'extensions\n'))
2019
2019
2020 def helpextcmd(name):
2020 def helpextcmd(name):
2021 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2021 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2022 doc = gettext(mod.__doc__).splitlines()[0]
2022 doc = gettext(mod.__doc__).splitlines()[0]
2023
2023
2024 msg = help.listexts(_("'%s' is provided by the following "
2024 msg = help.listexts(_("'%s' is provided by the following "
2025 "extension:") % cmd, {ext: doc}, len(ext),
2025 "extension:") % cmd, {ext: doc}, len(ext),
2026 indent=4)
2026 indent=4)
2027 ui.write(minirst.format(msg, textwidth))
2027 ui.write(minirst.format(msg, textwidth))
2028 ui.write('\n\n')
2028 ui.write('\n\n')
2029 ui.write(_('use "hg help extensions" for information on enabling '
2029 ui.write(_('use "hg help extensions" for information on enabling '
2030 'extensions\n'))
2030 'extensions\n'))
2031
2031
2032 help.addtopichook('revsets', revset.makedoc)
2033
2032 if name and name != 'shortlist':
2034 if name and name != 'shortlist':
2033 i = None
2035 i = None
2034 if unknowncmd:
2036 if unknowncmd:
2035 queries = (helpextcmd,)
2037 queries = (helpextcmd,)
2036 else:
2038 else:
2037 queries = (helptopic, helpcmd, helpext, helpextcmd)
2039 queries = (helptopic, helpcmd, helpext, helpextcmd)
2038 for f in queries:
2040 for f in queries:
2039 try:
2041 try:
2040 f(name)
2042 f(name)
2041 i = None
2043 i = None
2042 break
2044 break
2043 except error.UnknownCommand, inst:
2045 except error.UnknownCommand, inst:
2044 i = inst
2046 i = inst
2045 if i:
2047 if i:
2046 raise i
2048 raise i
2047
2049
2048 else:
2050 else:
2049 # program name
2051 # program name
2050 if ui.verbose or with_version:
2052 if ui.verbose or with_version:
2051 version_(ui)
2053 version_(ui)
2052 else:
2054 else:
2053 ui.status(_("Mercurial Distributed SCM\n"))
2055 ui.status(_("Mercurial Distributed SCM\n"))
2054 ui.status('\n')
2056 ui.status('\n')
2055
2057
2056 # list of commands
2058 # list of commands
2057 if name == "shortlist":
2059 if name == "shortlist":
2058 header = _('basic commands:\n\n')
2060 header = _('basic commands:\n\n')
2059 else:
2061 else:
2060 header = _('list of commands:\n\n')
2062 header = _('list of commands:\n\n')
2061
2063
2062 helplist(header)
2064 helplist(header)
2063 if name != 'shortlist':
2065 if name != 'shortlist':
2064 exts, maxlength = extensions.enabled()
2066 exts, maxlength = extensions.enabled()
2065 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2067 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2066 if text:
2068 if text:
2067 ui.write("\n%s\n" % minirst.format(text, textwidth))
2069 ui.write("\n%s\n" % minirst.format(text, textwidth))
2068
2070
2069 # list all option lists
2071 # list all option lists
2070 opt_output = []
2072 opt_output = []
2071 multioccur = False
2073 multioccur = False
2072 for title, options in option_lists:
2074 for title, options in option_lists:
2073 opt_output.append(("\n%s" % title, None))
2075 opt_output.append(("\n%s" % title, None))
2074 for option in options:
2076 for option in options:
2075 if len(option) == 5:
2077 if len(option) == 5:
2076 shortopt, longopt, default, desc, optlabel = option
2078 shortopt, longopt, default, desc, optlabel = option
2077 else:
2079 else:
2078 shortopt, longopt, default, desc = option
2080 shortopt, longopt, default, desc = option
2079 optlabel = _("VALUE") # default label
2081 optlabel = _("VALUE") # default label
2080
2082
2081 if _("DEPRECATED") in desc and not ui.verbose:
2083 if _("DEPRECATED") in desc and not ui.verbose:
2082 continue
2084 continue
2083 if isinstance(default, list):
2085 if isinstance(default, list):
2084 numqualifier = " %s [+]" % optlabel
2086 numqualifier = " %s [+]" % optlabel
2085 multioccur = True
2087 multioccur = True
2086 elif (default is not None) and not isinstance(default, bool):
2088 elif (default is not None) and not isinstance(default, bool):
2087 numqualifier = " %s" % optlabel
2089 numqualifier = " %s" % optlabel
2088 else:
2090 else:
2089 numqualifier = ""
2091 numqualifier = ""
2090 opt_output.append(("%2s%s" %
2092 opt_output.append(("%2s%s" %
2091 (shortopt and "-%s" % shortopt,
2093 (shortopt and "-%s" % shortopt,
2092 longopt and " --%s%s" %
2094 longopt and " --%s%s" %
2093 (longopt, numqualifier)),
2095 (longopt, numqualifier)),
2094 "%s%s" % (desc,
2096 "%s%s" % (desc,
2095 default
2097 default
2096 and _(" (default: %s)") % default
2098 and _(" (default: %s)") % default
2097 or "")))
2099 or "")))
2098 if multioccur:
2100 if multioccur:
2099 msg = _("\n[+] marked option can be specified multiple times")
2101 msg = _("\n[+] marked option can be specified multiple times")
2100 if ui.verbose and name != 'shortlist':
2102 if ui.verbose and name != 'shortlist':
2101 opt_output.append((msg, None))
2103 opt_output.append((msg, None))
2102 else:
2104 else:
2103 opt_output.insert(-1, (msg, None))
2105 opt_output.insert(-1, (msg, None))
2104
2106
2105 if not name:
2107 if not name:
2106 ui.write(_("\nadditional help topics:\n\n"))
2108 ui.write(_("\nadditional help topics:\n\n"))
2107 topics = []
2109 topics = []
2108 for names, header, doc in help.helptable:
2110 for names, header, doc in help.helptable:
2109 topics.append((sorted(names, key=len, reverse=True)[0], header))
2111 topics.append((sorted(names, key=len, reverse=True)[0], header))
2110 topics_len = max([len(s[0]) for s in topics])
2112 topics_len = max([len(s[0]) for s in topics])
2111 for t, desc in topics:
2113 for t, desc in topics:
2112 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2114 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2113
2115
2114 if opt_output:
2116 if opt_output:
2115 colwidth = encoding.colwidth
2117 colwidth = encoding.colwidth
2116 # normalize: (opt or message, desc or None, width of opt)
2118 # normalize: (opt or message, desc or None, width of opt)
2117 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2119 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2118 for opt, desc in opt_output]
2120 for opt, desc in opt_output]
2119 hanging = max([e[2] for e in entries])
2121 hanging = max([e[2] for e in entries])
2120 for opt, desc, width in entries:
2122 for opt, desc, width in entries:
2121 if desc:
2123 if desc:
2122 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2124 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2123 hangindent = ' ' * (hanging + 3)
2125 hangindent = ' ' * (hanging + 3)
2124 ui.write('%s\n' % (util.wrap(desc, textwidth,
2126 ui.write('%s\n' % (util.wrap(desc, textwidth,
2125 initindent=initindent,
2127 initindent=initindent,
2126 hangindent=hangindent)))
2128 hangindent=hangindent)))
2127 else:
2129 else:
2128 ui.write("%s\n" % opt)
2130 ui.write("%s\n" % opt)
2129
2131
2130 def identify(ui, repo, source=None,
2132 def identify(ui, repo, source=None,
2131 rev=None, num=None, id=None, branch=None, tags=None):
2133 rev=None, num=None, id=None, branch=None, tags=None):
2132 """identify the working copy or specified revision
2134 """identify the working copy or specified revision
2133
2135
2134 With no revision, print a summary of the current state of the
2136 With no revision, print a summary of the current state of the
2135 repository.
2137 repository.
2136
2138
2137 Specifying a path to a repository root or Mercurial bundle will
2139 Specifying a path to a repository root or Mercurial bundle will
2138 cause lookup to operate on that repository/bundle.
2140 cause lookup to operate on that repository/bundle.
2139
2141
2140 This summary identifies the repository state using one or two
2142 This summary identifies the repository state using one or two
2141 parent hash identifiers, followed by a "+" if there are
2143 parent hash identifiers, followed by a "+" if there are
2142 uncommitted changes in the working directory, a list of tags for
2144 uncommitted changes in the working directory, a list of tags for
2143 this revision and a branch name for non-default branches.
2145 this revision and a branch name for non-default branches.
2144
2146
2145 Returns 0 if successful.
2147 Returns 0 if successful.
2146 """
2148 """
2147
2149
2148 if not repo and not source:
2150 if not repo and not source:
2149 raise util.Abort(_("there is no Mercurial repository here "
2151 raise util.Abort(_("there is no Mercurial repository here "
2150 "(.hg not found)"))
2152 "(.hg not found)"))
2151
2153
2152 hexfunc = ui.debugflag and hex or short
2154 hexfunc = ui.debugflag and hex or short
2153 default = not (num or id or branch or tags)
2155 default = not (num or id or branch or tags)
2154 output = []
2156 output = []
2155
2157
2156 revs = []
2158 revs = []
2157 if source:
2159 if source:
2158 source, branches = hg.parseurl(ui.expandpath(source))
2160 source, branches = hg.parseurl(ui.expandpath(source))
2159 repo = hg.repository(ui, source)
2161 repo = hg.repository(ui, source)
2160 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2162 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2161
2163
2162 if not repo.local():
2164 if not repo.local():
2163 if not rev and revs:
2165 if not rev and revs:
2164 rev = revs[0]
2166 rev = revs[0]
2165 if not rev:
2167 if not rev:
2166 rev = "tip"
2168 rev = "tip"
2167 if num or branch or tags:
2169 if num or branch or tags:
2168 raise util.Abort(
2170 raise util.Abort(
2169 "can't query remote revision number, branch, or tags")
2171 "can't query remote revision number, branch, or tags")
2170 output = [hexfunc(repo.lookup(rev))]
2172 output = [hexfunc(repo.lookup(rev))]
2171 elif not rev:
2173 elif not rev:
2172 ctx = repo[None]
2174 ctx = repo[None]
2173 parents = ctx.parents()
2175 parents = ctx.parents()
2174 changed = False
2176 changed = False
2175 if default or id or num:
2177 if default or id or num:
2176 changed = util.any(repo.status())
2178 changed = util.any(repo.status())
2177 if default or id:
2179 if default or id:
2178 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2180 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2179 (changed) and "+" or "")]
2181 (changed) and "+" or "")]
2180 if num:
2182 if num:
2181 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2183 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2182 (changed) and "+" or ""))
2184 (changed) and "+" or ""))
2183 else:
2185 else:
2184 ctx = repo[rev]
2186 ctx = repo[rev]
2185 if default or id:
2187 if default or id:
2186 output = [hexfunc(ctx.node())]
2188 output = [hexfunc(ctx.node())]
2187 if num:
2189 if num:
2188 output.append(str(ctx.rev()))
2190 output.append(str(ctx.rev()))
2189
2191
2190 if repo.local() and default and not ui.quiet:
2192 if repo.local() and default and not ui.quiet:
2191 b = encoding.tolocal(ctx.branch())
2193 b = encoding.tolocal(ctx.branch())
2192 if b != 'default':
2194 if b != 'default':
2193 output.append("(%s)" % b)
2195 output.append("(%s)" % b)
2194
2196
2195 # multiple tags for a single parent separated by '/'
2197 # multiple tags for a single parent separated by '/'
2196 t = "/".join(ctx.tags())
2198 t = "/".join(ctx.tags())
2197 if t:
2199 if t:
2198 output.append(t)
2200 output.append(t)
2199
2201
2200 if branch:
2202 if branch:
2201 output.append(encoding.tolocal(ctx.branch()))
2203 output.append(encoding.tolocal(ctx.branch()))
2202
2204
2203 if tags:
2205 if tags:
2204 output.extend(ctx.tags())
2206 output.extend(ctx.tags())
2205
2207
2206 ui.write("%s\n" % ' '.join(output))
2208 ui.write("%s\n" % ' '.join(output))
2207
2209
2208 def import_(ui, repo, patch1, *patches, **opts):
2210 def import_(ui, repo, patch1, *patches, **opts):
2209 """import an ordered set of patches
2211 """import an ordered set of patches
2210
2212
2211 Import a list of patches and commit them individually (unless
2213 Import a list of patches and commit them individually (unless
2212 --no-commit is specified).
2214 --no-commit is specified).
2213
2215
2214 If there are outstanding changes in the working directory, import
2216 If there are outstanding changes in the working directory, import
2215 will abort unless given the -f/--force flag.
2217 will abort unless given the -f/--force flag.
2216
2218
2217 You can import a patch straight from a mail message. Even patches
2219 You can import a patch straight from a mail message. Even patches
2218 as attachments work (to use the body part, it must have type
2220 as attachments work (to use the body part, it must have type
2219 text/plain or text/x-patch). From and Subject headers of email
2221 text/plain or text/x-patch). From and Subject headers of email
2220 message are used as default committer and commit message. All
2222 message are used as default committer and commit message. All
2221 text/plain body parts before first diff are added to commit
2223 text/plain body parts before first diff are added to commit
2222 message.
2224 message.
2223
2225
2224 If the imported patch was generated by :hg:`export`, user and
2226 If the imported patch was generated by :hg:`export`, user and
2225 description from patch override values from message headers and
2227 description from patch override values from message headers and
2226 body. Values given on command line with -m/--message and -u/--user
2228 body. Values given on command line with -m/--message and -u/--user
2227 override these.
2229 override these.
2228
2230
2229 If --exact is specified, import will set the working directory to
2231 If --exact is specified, import will set the working directory to
2230 the parent of each patch before applying it, and will abort if the
2232 the parent of each patch before applying it, and will abort if the
2231 resulting changeset has a different ID than the one recorded in
2233 resulting changeset has a different ID than the one recorded in
2232 the patch. This may happen due to character set problems or other
2234 the patch. This may happen due to character set problems or other
2233 deficiencies in the text patch format.
2235 deficiencies in the text patch format.
2234
2236
2235 With -s/--similarity, hg will attempt to discover renames and
2237 With -s/--similarity, hg will attempt to discover renames and
2236 copies in the patch in the same way as 'addremove'.
2238 copies in the patch in the same way as 'addremove'.
2237
2239
2238 To read a patch from standard input, use "-" as the patch name. If
2240 To read a patch from standard input, use "-" as the patch name. If
2239 a URL is specified, the patch will be downloaded from it.
2241 a URL is specified, the patch will be downloaded from it.
2240 See :hg:`help dates` for a list of formats valid for -d/--date.
2242 See :hg:`help dates` for a list of formats valid for -d/--date.
2241
2243
2242 Returns 0 on success.
2244 Returns 0 on success.
2243 """
2245 """
2244 patches = (patch1,) + patches
2246 patches = (patch1,) + patches
2245
2247
2246 date = opts.get('date')
2248 date = opts.get('date')
2247 if date:
2249 if date:
2248 opts['date'] = util.parsedate(date)
2250 opts['date'] = util.parsedate(date)
2249
2251
2250 try:
2252 try:
2251 sim = float(opts.get('similarity') or 0)
2253 sim = float(opts.get('similarity') or 0)
2252 except ValueError:
2254 except ValueError:
2253 raise util.Abort(_('similarity must be a number'))
2255 raise util.Abort(_('similarity must be a number'))
2254 if sim < 0 or sim > 100:
2256 if sim < 0 or sim > 100:
2255 raise util.Abort(_('similarity must be between 0 and 100'))
2257 raise util.Abort(_('similarity must be between 0 and 100'))
2256
2258
2257 if opts.get('exact') or not opts.get('force'):
2259 if opts.get('exact') or not opts.get('force'):
2258 cmdutil.bail_if_changed(repo)
2260 cmdutil.bail_if_changed(repo)
2259
2261
2260 d = opts["base"]
2262 d = opts["base"]
2261 strip = opts["strip"]
2263 strip = opts["strip"]
2262 wlock = lock = None
2264 wlock = lock = None
2263
2265
2264 def tryone(ui, hunk):
2266 def tryone(ui, hunk):
2265 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2267 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2266 patch.extract(ui, hunk)
2268 patch.extract(ui, hunk)
2267
2269
2268 if not tmpname:
2270 if not tmpname:
2269 return None
2271 return None
2270 commitid = _('to working directory')
2272 commitid = _('to working directory')
2271
2273
2272 try:
2274 try:
2273 cmdline_message = cmdutil.logmessage(opts)
2275 cmdline_message = cmdutil.logmessage(opts)
2274 if cmdline_message:
2276 if cmdline_message:
2275 # pickup the cmdline msg
2277 # pickup the cmdline msg
2276 message = cmdline_message
2278 message = cmdline_message
2277 elif message:
2279 elif message:
2278 # pickup the patch msg
2280 # pickup the patch msg
2279 message = message.strip()
2281 message = message.strip()
2280 else:
2282 else:
2281 # launch the editor
2283 # launch the editor
2282 message = None
2284 message = None
2283 ui.debug('message:\n%s\n' % message)
2285 ui.debug('message:\n%s\n' % message)
2284
2286
2285 wp = repo.parents()
2287 wp = repo.parents()
2286 if opts.get('exact'):
2288 if opts.get('exact'):
2287 if not nodeid or not p1:
2289 if not nodeid or not p1:
2288 raise util.Abort(_('not a Mercurial patch'))
2290 raise util.Abort(_('not a Mercurial patch'))
2289 p1 = repo.lookup(p1)
2291 p1 = repo.lookup(p1)
2290 p2 = repo.lookup(p2 or hex(nullid))
2292 p2 = repo.lookup(p2 or hex(nullid))
2291
2293
2292 if p1 != wp[0].node():
2294 if p1 != wp[0].node():
2293 hg.clean(repo, p1)
2295 hg.clean(repo, p1)
2294 repo.dirstate.setparents(p1, p2)
2296 repo.dirstate.setparents(p1, p2)
2295 elif p2:
2297 elif p2:
2296 try:
2298 try:
2297 p1 = repo.lookup(p1)
2299 p1 = repo.lookup(p1)
2298 p2 = repo.lookup(p2)
2300 p2 = repo.lookup(p2)
2299 if p1 == wp[0].node():
2301 if p1 == wp[0].node():
2300 repo.dirstate.setparents(p1, p2)
2302 repo.dirstate.setparents(p1, p2)
2301 except error.RepoError:
2303 except error.RepoError:
2302 pass
2304 pass
2303 if opts.get('exact') or opts.get('import_branch'):
2305 if opts.get('exact') or opts.get('import_branch'):
2304 repo.dirstate.setbranch(branch or 'default')
2306 repo.dirstate.setbranch(branch or 'default')
2305
2307
2306 files = {}
2308 files = {}
2307 try:
2309 try:
2308 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2310 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2309 files=files, eolmode=None)
2311 files=files, eolmode=None)
2310 finally:
2312 finally:
2311 files = cmdutil.updatedir(ui, repo, files,
2313 files = cmdutil.updatedir(ui, repo, files,
2312 similarity=sim / 100.0)
2314 similarity=sim / 100.0)
2313 if not opts.get('no_commit'):
2315 if not opts.get('no_commit'):
2314 if opts.get('exact'):
2316 if opts.get('exact'):
2315 m = None
2317 m = None
2316 else:
2318 else:
2317 m = cmdutil.matchfiles(repo, files or [])
2319 m = cmdutil.matchfiles(repo, files or [])
2318 n = repo.commit(message, opts.get('user') or user,
2320 n = repo.commit(message, opts.get('user') or user,
2319 opts.get('date') or date, match=m,
2321 opts.get('date') or date, match=m,
2320 editor=cmdutil.commiteditor)
2322 editor=cmdutil.commiteditor)
2321 if opts.get('exact'):
2323 if opts.get('exact'):
2322 if hex(n) != nodeid:
2324 if hex(n) != nodeid:
2323 repo.rollback()
2325 repo.rollback()
2324 raise util.Abort(_('patch is damaged'
2326 raise util.Abort(_('patch is damaged'
2325 ' or loses information'))
2327 ' or loses information'))
2326 # Force a dirstate write so that the next transaction
2328 # Force a dirstate write so that the next transaction
2327 # backups an up-do-date file.
2329 # backups an up-do-date file.
2328 repo.dirstate.write()
2330 repo.dirstate.write()
2329 if n:
2331 if n:
2330 commitid = short(n)
2332 commitid = short(n)
2331
2333
2332 return commitid
2334 return commitid
2333 finally:
2335 finally:
2334 os.unlink(tmpname)
2336 os.unlink(tmpname)
2335
2337
2336 try:
2338 try:
2337 wlock = repo.wlock()
2339 wlock = repo.wlock()
2338 lock = repo.lock()
2340 lock = repo.lock()
2339 lastcommit = None
2341 lastcommit = None
2340 for p in patches:
2342 for p in patches:
2341 pf = os.path.join(d, p)
2343 pf = os.path.join(d, p)
2342
2344
2343 if pf == '-':
2345 if pf == '-':
2344 ui.status(_("applying patch from stdin\n"))
2346 ui.status(_("applying patch from stdin\n"))
2345 pf = sys.stdin
2347 pf = sys.stdin
2346 else:
2348 else:
2347 ui.status(_("applying %s\n") % p)
2349 ui.status(_("applying %s\n") % p)
2348 pf = url.open(ui, pf)
2350 pf = url.open(ui, pf)
2349
2351
2350 haspatch = False
2352 haspatch = False
2351 for hunk in patch.split(pf):
2353 for hunk in patch.split(pf):
2352 commitid = tryone(ui, hunk)
2354 commitid = tryone(ui, hunk)
2353 if commitid:
2355 if commitid:
2354 haspatch = True
2356 haspatch = True
2355 if lastcommit:
2357 if lastcommit:
2356 ui.status(_('applied %s\n') % lastcommit)
2358 ui.status(_('applied %s\n') % lastcommit)
2357 lastcommit = commitid
2359 lastcommit = commitid
2358
2360
2359 if not haspatch:
2361 if not haspatch:
2360 raise util.Abort(_('no diffs found'))
2362 raise util.Abort(_('no diffs found'))
2361
2363
2362 finally:
2364 finally:
2363 release(lock, wlock)
2365 release(lock, wlock)
2364
2366
2365 def incoming(ui, repo, source="default", **opts):
2367 def incoming(ui, repo, source="default", **opts):
2366 """show new changesets found in source
2368 """show new changesets found in source
2367
2369
2368 Show new changesets found in the specified path/URL or the default
2370 Show new changesets found in the specified path/URL or the default
2369 pull location. These are the changesets that would have been pulled
2371 pull location. These are the changesets that would have been pulled
2370 if a pull at the time you issued this command.
2372 if a pull at the time you issued this command.
2371
2373
2372 For remote repository, using --bundle avoids downloading the
2374 For remote repository, using --bundle avoids downloading the
2373 changesets twice if the incoming is followed by a pull.
2375 changesets twice if the incoming is followed by a pull.
2374
2376
2375 See pull for valid source format details.
2377 See pull for valid source format details.
2376
2378
2377 Returns 0 if there are incoming changes, 1 otherwise.
2379 Returns 0 if there are incoming changes, 1 otherwise.
2378 """
2380 """
2379 if opts.get('bundle') and opts.get('subrepos'):
2381 if opts.get('bundle') and opts.get('subrepos'):
2380 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2382 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2381
2383
2382 ret = hg.incoming(ui, repo, source, opts)
2384 ret = hg.incoming(ui, repo, source, opts)
2383 return ret
2385 return ret
2384
2386
2385 def init(ui, dest=".", **opts):
2387 def init(ui, dest=".", **opts):
2386 """create a new repository in the given directory
2388 """create a new repository in the given directory
2387
2389
2388 Initialize a new repository in the given directory. If the given
2390 Initialize a new repository in the given directory. If the given
2389 directory does not exist, it will be created.
2391 directory does not exist, it will be created.
2390
2392
2391 If no directory is given, the current directory is used.
2393 If no directory is given, the current directory is used.
2392
2394
2393 It is possible to specify an ``ssh://`` URL as the destination.
2395 It is possible to specify an ``ssh://`` URL as the destination.
2394 See :hg:`help urls` for more information.
2396 See :hg:`help urls` for more information.
2395
2397
2396 Returns 0 on success.
2398 Returns 0 on success.
2397 """
2399 """
2398 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2400 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2399
2401
2400 def locate(ui, repo, *pats, **opts):
2402 def locate(ui, repo, *pats, **opts):
2401 """locate files matching specific patterns
2403 """locate files matching specific patterns
2402
2404
2403 Print files under Mercurial control in the working directory whose
2405 Print files under Mercurial control in the working directory whose
2404 names match the given patterns.
2406 names match the given patterns.
2405
2407
2406 By default, this command searches all directories in the working
2408 By default, this command searches all directories in the working
2407 directory. To search just the current directory and its
2409 directory. To search just the current directory and its
2408 subdirectories, use "--include .".
2410 subdirectories, use "--include .".
2409
2411
2410 If no patterns are given to match, this command prints the names
2412 If no patterns are given to match, this command prints the names
2411 of all files under Mercurial control in the working directory.
2413 of all files under Mercurial control in the working directory.
2412
2414
2413 If you want to feed the output of this command into the "xargs"
2415 If you want to feed the output of this command into the "xargs"
2414 command, use the -0 option to both this command and "xargs". This
2416 command, use the -0 option to both this command and "xargs". This
2415 will avoid the problem of "xargs" treating single filenames that
2417 will avoid the problem of "xargs" treating single filenames that
2416 contain whitespace as multiple filenames.
2418 contain whitespace as multiple filenames.
2417
2419
2418 Returns 0 if a match is found, 1 otherwise.
2420 Returns 0 if a match is found, 1 otherwise.
2419 """
2421 """
2420 end = opts.get('print0') and '\0' or '\n'
2422 end = opts.get('print0') and '\0' or '\n'
2421 rev = opts.get('rev') or None
2423 rev = opts.get('rev') or None
2422
2424
2423 ret = 1
2425 ret = 1
2424 m = cmdutil.match(repo, pats, opts, default='relglob')
2426 m = cmdutil.match(repo, pats, opts, default='relglob')
2425 m.bad = lambda x, y: False
2427 m.bad = lambda x, y: False
2426 for abs in repo[rev].walk(m):
2428 for abs in repo[rev].walk(m):
2427 if not rev and abs not in repo.dirstate:
2429 if not rev and abs not in repo.dirstate:
2428 continue
2430 continue
2429 if opts.get('fullpath'):
2431 if opts.get('fullpath'):
2430 ui.write(repo.wjoin(abs), end)
2432 ui.write(repo.wjoin(abs), end)
2431 else:
2433 else:
2432 ui.write(((pats and m.rel(abs)) or abs), end)
2434 ui.write(((pats and m.rel(abs)) or abs), end)
2433 ret = 0
2435 ret = 0
2434
2436
2435 return ret
2437 return ret
2436
2438
2437 def log(ui, repo, *pats, **opts):
2439 def log(ui, repo, *pats, **opts):
2438 """show revision history of entire repository or files
2440 """show revision history of entire repository or files
2439
2441
2440 Print the revision history of the specified files or the entire
2442 Print the revision history of the specified files or the entire
2441 project.
2443 project.
2442
2444
2443 File history is shown without following rename or copy history of
2445 File history is shown without following rename or copy history of
2444 files. Use -f/--follow with a filename to follow history across
2446 files. Use -f/--follow with a filename to follow history across
2445 renames and copies. --follow without a filename will only show
2447 renames and copies. --follow without a filename will only show
2446 ancestors or descendants of the starting revision. --follow-first
2448 ancestors or descendants of the starting revision. --follow-first
2447 only follows the first parent of merge revisions.
2449 only follows the first parent of merge revisions.
2448
2450
2449 If no revision range is specified, the default is ``tip:0`` unless
2451 If no revision range is specified, the default is ``tip:0`` unless
2450 --follow is set, in which case the working directory parent is
2452 --follow is set, in which case the working directory parent is
2451 used as the starting revision. You can specify a revision set for
2453 used as the starting revision. You can specify a revision set for
2452 log, see :hg:`help revsets` for more information.
2454 log, see :hg:`help revsets` for more information.
2453
2455
2454 See :hg:`help dates` for a list of formats valid for -d/--date.
2456 See :hg:`help dates` for a list of formats valid for -d/--date.
2455
2457
2456 By default this command prints revision number and changeset id,
2458 By default this command prints revision number and changeset id,
2457 tags, non-trivial parents, user, date and time, and a summary for
2459 tags, non-trivial parents, user, date and time, and a summary for
2458 each commit. When the -v/--verbose switch is used, the list of
2460 each commit. When the -v/--verbose switch is used, the list of
2459 changed files and full commit message are shown.
2461 changed files and full commit message are shown.
2460
2462
2461 .. note::
2463 .. note::
2462 log -p/--patch may generate unexpected diff output for merge
2464 log -p/--patch may generate unexpected diff output for merge
2463 changesets, as it will only compare the merge changeset against
2465 changesets, as it will only compare the merge changeset against
2464 its first parent. Also, only files different from BOTH parents
2466 its first parent. Also, only files different from BOTH parents
2465 will appear in files:.
2467 will appear in files:.
2466
2468
2467 Returns 0 on success.
2469 Returns 0 on success.
2468 """
2470 """
2469
2471
2470 matchfn = cmdutil.match(repo, pats, opts)
2472 matchfn = cmdutil.match(repo, pats, opts)
2471 limit = cmdutil.loglimit(opts)
2473 limit = cmdutil.loglimit(opts)
2472 count = 0
2474 count = 0
2473
2475
2474 endrev = None
2476 endrev = None
2475 if opts.get('copies') and opts.get('rev'):
2477 if opts.get('copies') and opts.get('rev'):
2476 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2478 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2477
2479
2478 df = False
2480 df = False
2479 if opts["date"]:
2481 if opts["date"]:
2480 df = util.matchdate(opts["date"])
2482 df = util.matchdate(opts["date"])
2481
2483
2482 branches = opts.get('branch', []) + opts.get('only_branch', [])
2484 branches = opts.get('branch', []) + opts.get('only_branch', [])
2483 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2485 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2484
2486
2485 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2487 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2486 def prep(ctx, fns):
2488 def prep(ctx, fns):
2487 rev = ctx.rev()
2489 rev = ctx.rev()
2488 parents = [p for p in repo.changelog.parentrevs(rev)
2490 parents = [p for p in repo.changelog.parentrevs(rev)
2489 if p != nullrev]
2491 if p != nullrev]
2490 if opts.get('no_merges') and len(parents) == 2:
2492 if opts.get('no_merges') and len(parents) == 2:
2491 return
2493 return
2492 if opts.get('only_merges') and len(parents) != 2:
2494 if opts.get('only_merges') and len(parents) != 2:
2493 return
2495 return
2494 if opts.get('branch') and ctx.branch() not in opts['branch']:
2496 if opts.get('branch') and ctx.branch() not in opts['branch']:
2495 return
2497 return
2496 if df and not df(ctx.date()[0]):
2498 if df and not df(ctx.date()[0]):
2497 return
2499 return
2498 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2500 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2499 return
2501 return
2500 if opts.get('keyword'):
2502 if opts.get('keyword'):
2501 for k in [kw.lower() for kw in opts['keyword']]:
2503 for k in [kw.lower() for kw in opts['keyword']]:
2502 if (k in ctx.user().lower() or
2504 if (k in ctx.user().lower() or
2503 k in ctx.description().lower() or
2505 k in ctx.description().lower() or
2504 k in " ".join(ctx.files()).lower()):
2506 k in " ".join(ctx.files()).lower()):
2505 break
2507 break
2506 else:
2508 else:
2507 return
2509 return
2508
2510
2509 copies = None
2511 copies = None
2510 if opts.get('copies') and rev:
2512 if opts.get('copies') and rev:
2511 copies = []
2513 copies = []
2512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2514 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2513 for fn in ctx.files():
2515 for fn in ctx.files():
2514 rename = getrenamed(fn, rev)
2516 rename = getrenamed(fn, rev)
2515 if rename:
2517 if rename:
2516 copies.append((fn, rename[0]))
2518 copies.append((fn, rename[0]))
2517
2519
2518 revmatchfn = None
2520 revmatchfn = None
2519 if opts.get('patch') or opts.get('stat'):
2521 if opts.get('patch') or opts.get('stat'):
2520 if opts.get('follow') or opts.get('follow_first'):
2522 if opts.get('follow') or opts.get('follow_first'):
2521 # note: this might be wrong when following through merges
2523 # note: this might be wrong when following through merges
2522 revmatchfn = cmdutil.match(repo, fns, default='path')
2524 revmatchfn = cmdutil.match(repo, fns, default='path')
2523 else:
2525 else:
2524 revmatchfn = matchfn
2526 revmatchfn = matchfn
2525
2527
2526 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2528 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2527
2529
2528 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2530 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2529 if count == limit:
2531 if count == limit:
2530 break
2532 break
2531 if displayer.flush(ctx.rev()):
2533 if displayer.flush(ctx.rev()):
2532 count += 1
2534 count += 1
2533 displayer.close()
2535 displayer.close()
2534
2536
2535 def manifest(ui, repo, node=None, rev=None):
2537 def manifest(ui, repo, node=None, rev=None):
2536 """output the current or given revision of the project manifest
2538 """output the current or given revision of the project manifest
2537
2539
2538 Print a list of version controlled files for the given revision.
2540 Print a list of version controlled files for the given revision.
2539 If no revision is given, the first parent of the working directory
2541 If no revision is given, the first parent of the working directory
2540 is used, or the null revision if no revision is checked out.
2542 is used, or the null revision if no revision is checked out.
2541
2543
2542 With -v, print file permissions, symlink and executable bits.
2544 With -v, print file permissions, symlink and executable bits.
2543 With --debug, print file revision hashes.
2545 With --debug, print file revision hashes.
2544
2546
2545 Returns 0 on success.
2547 Returns 0 on success.
2546 """
2548 """
2547
2549
2548 if rev and node:
2550 if rev and node:
2549 raise util.Abort(_("please specify just one revision"))
2551 raise util.Abort(_("please specify just one revision"))
2550
2552
2551 if not node:
2553 if not node:
2552 node = rev
2554 node = rev
2553
2555
2554 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2556 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2555 ctx = repo[node]
2557 ctx = repo[node]
2556 for f in ctx:
2558 for f in ctx:
2557 if ui.debugflag:
2559 if ui.debugflag:
2558 ui.write("%40s " % hex(ctx.manifest()[f]))
2560 ui.write("%40s " % hex(ctx.manifest()[f]))
2559 if ui.verbose:
2561 if ui.verbose:
2560 ui.write(decor[ctx.flags(f)])
2562 ui.write(decor[ctx.flags(f)])
2561 ui.write("%s\n" % f)
2563 ui.write("%s\n" % f)
2562
2564
2563 def merge(ui, repo, node=None, **opts):
2565 def merge(ui, repo, node=None, **opts):
2564 """merge working directory with another revision
2566 """merge working directory with another revision
2565
2567
2566 The current working directory is updated with all changes made in
2568 The current working directory is updated with all changes made in
2567 the requested revision since the last common predecessor revision.
2569 the requested revision since the last common predecessor revision.
2568
2570
2569 Files that changed between either parent are marked as changed for
2571 Files that changed between either parent are marked as changed for
2570 the next commit and a commit must be performed before any further
2572 the next commit and a commit must be performed before any further
2571 updates to the repository are allowed. The next commit will have
2573 updates to the repository are allowed. The next commit will have
2572 two parents.
2574 two parents.
2573
2575
2574 ``--tool`` can be used to specify the merge tool used for file
2576 ``--tool`` can be used to specify the merge tool used for file
2575 merges. It overrides the HGMERGE environment variable and your
2577 merges. It overrides the HGMERGE environment variable and your
2576 configuration files.
2578 configuration files.
2577
2579
2578 If no revision is specified, the working directory's parent is a
2580 If no revision is specified, the working directory's parent is a
2579 head revision, and the current branch contains exactly one other
2581 head revision, and the current branch contains exactly one other
2580 head, the other head is merged with by default. Otherwise, an
2582 head, the other head is merged with by default. Otherwise, an
2581 explicit revision with which to merge with must be provided.
2583 explicit revision with which to merge with must be provided.
2582
2584
2583 :hg:`resolve` must be used to resolve unresolved files.
2585 :hg:`resolve` must be used to resolve unresolved files.
2584
2586
2585 To undo an uncommitted merge, use :hg:`update --clean .` which
2587 To undo an uncommitted merge, use :hg:`update --clean .` which
2586 will check out a clean copy of the original merge parent, losing
2588 will check out a clean copy of the original merge parent, losing
2587 all changes.
2589 all changes.
2588
2590
2589 Returns 0 on success, 1 if there are unresolved files.
2591 Returns 0 on success, 1 if there are unresolved files.
2590 """
2592 """
2591
2593
2592 if opts.get('rev') and node:
2594 if opts.get('rev') and node:
2593 raise util.Abort(_("please specify just one revision"))
2595 raise util.Abort(_("please specify just one revision"))
2594 if not node:
2596 if not node:
2595 node = opts.get('rev')
2597 node = opts.get('rev')
2596
2598
2597 if not node:
2599 if not node:
2598 branch = repo.changectx(None).branch()
2600 branch = repo.changectx(None).branch()
2599 bheads = repo.branchheads(branch)
2601 bheads = repo.branchheads(branch)
2600 if len(bheads) > 2:
2602 if len(bheads) > 2:
2601 raise util.Abort(_(
2603 raise util.Abort(_(
2602 'branch \'%s\' has %d heads - '
2604 'branch \'%s\' has %d heads - '
2603 'please merge with an explicit rev\n'
2605 'please merge with an explicit rev\n'
2604 '(run \'hg heads .\' to see heads)')
2606 '(run \'hg heads .\' to see heads)')
2605 % (branch, len(bheads)))
2607 % (branch, len(bheads)))
2606
2608
2607 parent = repo.dirstate.parents()[0]
2609 parent = repo.dirstate.parents()[0]
2608 if len(bheads) == 1:
2610 if len(bheads) == 1:
2609 if len(repo.heads()) > 1:
2611 if len(repo.heads()) > 1:
2610 raise util.Abort(_(
2612 raise util.Abort(_(
2611 'branch \'%s\' has one head - '
2613 'branch \'%s\' has one head - '
2612 'please merge with an explicit rev\n'
2614 'please merge with an explicit rev\n'
2613 '(run \'hg heads\' to see all heads)')
2615 '(run \'hg heads\' to see all heads)')
2614 % branch)
2616 % branch)
2615 msg = _('there is nothing to merge')
2617 msg = _('there is nothing to merge')
2616 if parent != repo.lookup(repo[None].branch()):
2618 if parent != repo.lookup(repo[None].branch()):
2617 msg = _('%s - use "hg update" instead') % msg
2619 msg = _('%s - use "hg update" instead') % msg
2618 raise util.Abort(msg)
2620 raise util.Abort(msg)
2619
2621
2620 if parent not in bheads:
2622 if parent not in bheads:
2621 raise util.Abort(_('working dir not at a head rev - '
2623 raise util.Abort(_('working dir not at a head rev - '
2622 'use "hg update" or merge with an explicit rev'))
2624 'use "hg update" or merge with an explicit rev'))
2623 node = parent == bheads[0] and bheads[-1] or bheads[0]
2625 node = parent == bheads[0] and bheads[-1] or bheads[0]
2624
2626
2625 if opts.get('preview'):
2627 if opts.get('preview'):
2626 # find nodes that are ancestors of p2 but not of p1
2628 # find nodes that are ancestors of p2 but not of p1
2627 p1 = repo.lookup('.')
2629 p1 = repo.lookup('.')
2628 p2 = repo.lookup(node)
2630 p2 = repo.lookup(node)
2629 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2631 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2630
2632
2631 displayer = cmdutil.show_changeset(ui, repo, opts)
2633 displayer = cmdutil.show_changeset(ui, repo, opts)
2632 for node in nodes:
2634 for node in nodes:
2633 displayer.show(repo[node])
2635 displayer.show(repo[node])
2634 displayer.close()
2636 displayer.close()
2635 return 0
2637 return 0
2636
2638
2637 try:
2639 try:
2638 # ui.forcemerge is an internal variable, do not document
2640 # ui.forcemerge is an internal variable, do not document
2639 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2641 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2640 return hg.merge(repo, node, force=opts.get('force'))
2642 return hg.merge(repo, node, force=opts.get('force'))
2641 finally:
2643 finally:
2642 ui.setconfig('ui', 'forcemerge', '')
2644 ui.setconfig('ui', 'forcemerge', '')
2643
2645
2644 def outgoing(ui, repo, dest=None, **opts):
2646 def outgoing(ui, repo, dest=None, **opts):
2645 """show changesets not found in the destination
2647 """show changesets not found in the destination
2646
2648
2647 Show changesets not found in the specified destination repository
2649 Show changesets not found in the specified destination repository
2648 or the default push location. These are the changesets that would
2650 or the default push location. These are the changesets that would
2649 be pushed if a push was requested.
2651 be pushed if a push was requested.
2650
2652
2651 See pull for details of valid destination formats.
2653 See pull for details of valid destination formats.
2652
2654
2653 Returns 0 if there are outgoing changes, 1 otherwise.
2655 Returns 0 if there are outgoing changes, 1 otherwise.
2654 """
2656 """
2655 ret = hg.outgoing(ui, repo, dest, opts)
2657 ret = hg.outgoing(ui, repo, dest, opts)
2656 return ret
2658 return ret
2657
2659
2658 def parents(ui, repo, file_=None, **opts):
2660 def parents(ui, repo, file_=None, **opts):
2659 """show the parents of the working directory or revision
2661 """show the parents of the working directory or revision
2660
2662
2661 Print the working directory's parent revisions. If a revision is
2663 Print the working directory's parent revisions. If a revision is
2662 given via -r/--rev, the parent of that revision will be printed.
2664 given via -r/--rev, the parent of that revision will be printed.
2663 If a file argument is given, the revision in which the file was
2665 If a file argument is given, the revision in which the file was
2664 last changed (before the working directory revision or the
2666 last changed (before the working directory revision or the
2665 argument to --rev if given) is printed.
2667 argument to --rev if given) is printed.
2666
2668
2667 Returns 0 on success.
2669 Returns 0 on success.
2668 """
2670 """
2669 rev = opts.get('rev')
2671 rev = opts.get('rev')
2670 if rev:
2672 if rev:
2671 ctx = repo[rev]
2673 ctx = repo[rev]
2672 else:
2674 else:
2673 ctx = repo[None]
2675 ctx = repo[None]
2674
2676
2675 if file_:
2677 if file_:
2676 m = cmdutil.match(repo, (file_,), opts)
2678 m = cmdutil.match(repo, (file_,), opts)
2677 if m.anypats() or len(m.files()) != 1:
2679 if m.anypats() or len(m.files()) != 1:
2678 raise util.Abort(_('can only specify an explicit filename'))
2680 raise util.Abort(_('can only specify an explicit filename'))
2679 file_ = m.files()[0]
2681 file_ = m.files()[0]
2680 filenodes = []
2682 filenodes = []
2681 for cp in ctx.parents():
2683 for cp in ctx.parents():
2682 if not cp:
2684 if not cp:
2683 continue
2685 continue
2684 try:
2686 try:
2685 filenodes.append(cp.filenode(file_))
2687 filenodes.append(cp.filenode(file_))
2686 except error.LookupError:
2688 except error.LookupError:
2687 pass
2689 pass
2688 if not filenodes:
2690 if not filenodes:
2689 raise util.Abort(_("'%s' not found in manifest!") % file_)
2691 raise util.Abort(_("'%s' not found in manifest!") % file_)
2690 fl = repo.file(file_)
2692 fl = repo.file(file_)
2691 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2693 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2692 else:
2694 else:
2693 p = [cp.node() for cp in ctx.parents()]
2695 p = [cp.node() for cp in ctx.parents()]
2694
2696
2695 displayer = cmdutil.show_changeset(ui, repo, opts)
2697 displayer = cmdutil.show_changeset(ui, repo, opts)
2696 for n in p:
2698 for n in p:
2697 if n != nullid:
2699 if n != nullid:
2698 displayer.show(repo[n])
2700 displayer.show(repo[n])
2699 displayer.close()
2701 displayer.close()
2700
2702
2701 def paths(ui, repo, search=None):
2703 def paths(ui, repo, search=None):
2702 """show aliases for remote repositories
2704 """show aliases for remote repositories
2703
2705
2704 Show definition of symbolic path name NAME. If no name is given,
2706 Show definition of symbolic path name NAME. If no name is given,
2705 show definition of all available names.
2707 show definition of all available names.
2706
2708
2707 Path names are defined in the [paths] section of your
2709 Path names are defined in the [paths] section of your
2708 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2710 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2709 repository, ``.hg/hgrc`` is used, too.
2711 repository, ``.hg/hgrc`` is used, too.
2710
2712
2711 The path names ``default`` and ``default-push`` have a special
2713 The path names ``default`` and ``default-push`` have a special
2712 meaning. When performing a push or pull operation, they are used
2714 meaning. When performing a push or pull operation, they are used
2713 as fallbacks if no location is specified on the command-line.
2715 as fallbacks if no location is specified on the command-line.
2714 When ``default-push`` is set, it will be used for push and
2716 When ``default-push`` is set, it will be used for push and
2715 ``default`` will be used for pull; otherwise ``default`` is used
2717 ``default`` will be used for pull; otherwise ``default`` is used
2716 as the fallback for both. When cloning a repository, the clone
2718 as the fallback for both. When cloning a repository, the clone
2717 source is written as ``default`` in ``.hg/hgrc``. Note that
2719 source is written as ``default`` in ``.hg/hgrc``. Note that
2718 ``default`` and ``default-push`` apply to all inbound (e.g.
2720 ``default`` and ``default-push`` apply to all inbound (e.g.
2719 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2721 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2720 :hg:`bundle`) operations.
2722 :hg:`bundle`) operations.
2721
2723
2722 See :hg:`help urls` for more information.
2724 See :hg:`help urls` for more information.
2723
2725
2724 Returns 0 on success.
2726 Returns 0 on success.
2725 """
2727 """
2726 if search:
2728 if search:
2727 for name, path in ui.configitems("paths"):
2729 for name, path in ui.configitems("paths"):
2728 if name == search:
2730 if name == search:
2729 ui.write("%s\n" % url.hidepassword(path))
2731 ui.write("%s\n" % url.hidepassword(path))
2730 return
2732 return
2731 ui.warn(_("not found!\n"))
2733 ui.warn(_("not found!\n"))
2732 return 1
2734 return 1
2733 else:
2735 else:
2734 for name, path in ui.configitems("paths"):
2736 for name, path in ui.configitems("paths"):
2735 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2737 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2736
2738
2737 def postincoming(ui, repo, modheads, optupdate, checkout):
2739 def postincoming(ui, repo, modheads, optupdate, checkout):
2738 if modheads == 0:
2740 if modheads == 0:
2739 return
2741 return
2740 if optupdate:
2742 if optupdate:
2741 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2743 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2742 return hg.update(repo, checkout)
2744 return hg.update(repo, checkout)
2743 else:
2745 else:
2744 ui.status(_("not updating, since new heads added\n"))
2746 ui.status(_("not updating, since new heads added\n"))
2745 if modheads > 1:
2747 if modheads > 1:
2746 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2748 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2747 else:
2749 else:
2748 ui.status(_("(run 'hg update' to get a working copy)\n"))
2750 ui.status(_("(run 'hg update' to get a working copy)\n"))
2749
2751
2750 def pull(ui, repo, source="default", **opts):
2752 def pull(ui, repo, source="default", **opts):
2751 """pull changes from the specified source
2753 """pull changes from the specified source
2752
2754
2753 Pull changes from a remote repository to a local one.
2755 Pull changes from a remote repository to a local one.
2754
2756
2755 This finds all changes from the repository at the specified path
2757 This finds all changes from the repository at the specified path
2756 or URL and adds them to a local repository (the current one unless
2758 or URL and adds them to a local repository (the current one unless
2757 -R is specified). By default, this does not update the copy of the
2759 -R is specified). By default, this does not update the copy of the
2758 project in the working directory.
2760 project in the working directory.
2759
2761
2760 Use :hg:`incoming` if you want to see what would have been added
2762 Use :hg:`incoming` if you want to see what would have been added
2761 by a pull at the time you issued this command. If you then decide
2763 by a pull at the time you issued this command. If you then decide
2762 to add those changes to the repository, you should use :hg:`pull
2764 to add those changes to the repository, you should use :hg:`pull
2763 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2765 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2764
2766
2765 If SOURCE is omitted, the 'default' path will be used.
2767 If SOURCE is omitted, the 'default' path will be used.
2766 See :hg:`help urls` for more information.
2768 See :hg:`help urls` for more information.
2767
2769
2768 Returns 0 on success, 1 if an update had unresolved files.
2770 Returns 0 on success, 1 if an update had unresolved files.
2769 """
2771 """
2770 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2772 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2771 other = hg.repository(hg.remoteui(repo, opts), source)
2773 other = hg.repository(hg.remoteui(repo, opts), source)
2772 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2774 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2773 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2775 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2774 if revs:
2776 if revs:
2775 try:
2777 try:
2776 revs = [other.lookup(rev) for rev in revs]
2778 revs = [other.lookup(rev) for rev in revs]
2777 except error.CapabilityError:
2779 except error.CapabilityError:
2778 err = _("other repository doesn't support revision lookup, "
2780 err = _("other repository doesn't support revision lookup, "
2779 "so a rev cannot be specified.")
2781 "so a rev cannot be specified.")
2780 raise util.Abort(err)
2782 raise util.Abort(err)
2781
2783
2782 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2784 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2783 if checkout:
2785 if checkout:
2784 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2786 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2785 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2787 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2786
2788
2787 def push(ui, repo, dest=None, **opts):
2789 def push(ui, repo, dest=None, **opts):
2788 """push changes to the specified destination
2790 """push changes to the specified destination
2789
2791
2790 Push changesets from the local repository to the specified
2792 Push changesets from the local repository to the specified
2791 destination.
2793 destination.
2792
2794
2793 This operation is symmetrical to pull: it is identical to a pull
2795 This operation is symmetrical to pull: it is identical to a pull
2794 in the destination repository from the current one.
2796 in the destination repository from the current one.
2795
2797
2796 By default, push will not allow creation of new heads at the
2798 By default, push will not allow creation of new heads at the
2797 destination, since multiple heads would make it unclear which head
2799 destination, since multiple heads would make it unclear which head
2798 to use. In this situation, it is recommended to pull and merge
2800 to use. In this situation, it is recommended to pull and merge
2799 before pushing.
2801 before pushing.
2800
2802
2801 Use --new-branch if you want to allow push to create a new named
2803 Use --new-branch if you want to allow push to create a new named
2802 branch that is not present at the destination. This allows you to
2804 branch that is not present at the destination. This allows you to
2803 only create a new branch without forcing other changes.
2805 only create a new branch without forcing other changes.
2804
2806
2805 Use -f/--force to override the default behavior and push all
2807 Use -f/--force to override the default behavior and push all
2806 changesets on all branches.
2808 changesets on all branches.
2807
2809
2808 If -r/--rev is used, the specified revision and all its ancestors
2810 If -r/--rev is used, the specified revision and all its ancestors
2809 will be pushed to the remote repository.
2811 will be pushed to the remote repository.
2810
2812
2811 Please see :hg:`help urls` for important details about ``ssh://``
2813 Please see :hg:`help urls` for important details about ``ssh://``
2812 URLs. If DESTINATION is omitted, a default path will be used.
2814 URLs. If DESTINATION is omitted, a default path will be used.
2813
2815
2814 Returns 0 if push was successful, 1 if nothing to push.
2816 Returns 0 if push was successful, 1 if nothing to push.
2815 """
2817 """
2816 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2818 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2817 dest, branches = hg.parseurl(dest, opts.get('branch'))
2819 dest, branches = hg.parseurl(dest, opts.get('branch'))
2818 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2820 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2819 other = hg.repository(hg.remoteui(repo, opts), dest)
2821 other = hg.repository(hg.remoteui(repo, opts), dest)
2820 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2822 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2821 if revs:
2823 if revs:
2822 revs = [repo.lookup(rev) for rev in revs]
2824 revs = [repo.lookup(rev) for rev in revs]
2823
2825
2824 # push subrepos depth-first for coherent ordering
2826 # push subrepos depth-first for coherent ordering
2825 c = repo['']
2827 c = repo['']
2826 subs = c.substate # only repos that are committed
2828 subs = c.substate # only repos that are committed
2827 for s in sorted(subs):
2829 for s in sorted(subs):
2828 if not c.sub(s).push(opts.get('force')):
2830 if not c.sub(s).push(opts.get('force')):
2829 return False
2831 return False
2830
2832
2831 r = repo.push(other, opts.get('force'), revs=revs,
2833 r = repo.push(other, opts.get('force'), revs=revs,
2832 newbranch=opts.get('new_branch'))
2834 newbranch=opts.get('new_branch'))
2833 return r == 0
2835 return r == 0
2834
2836
2835 def recover(ui, repo):
2837 def recover(ui, repo):
2836 """roll back an interrupted transaction
2838 """roll back an interrupted transaction
2837
2839
2838 Recover from an interrupted commit or pull.
2840 Recover from an interrupted commit or pull.
2839
2841
2840 This command tries to fix the repository status after an
2842 This command tries to fix the repository status after an
2841 interrupted operation. It should only be necessary when Mercurial
2843 interrupted operation. It should only be necessary when Mercurial
2842 suggests it.
2844 suggests it.
2843
2845
2844 Returns 0 if successful, 1 if nothing to recover or verify fails.
2846 Returns 0 if successful, 1 if nothing to recover or verify fails.
2845 """
2847 """
2846 if repo.recover():
2848 if repo.recover():
2847 return hg.verify(repo)
2849 return hg.verify(repo)
2848 return 1
2850 return 1
2849
2851
2850 def remove(ui, repo, *pats, **opts):
2852 def remove(ui, repo, *pats, **opts):
2851 """remove the specified files on the next commit
2853 """remove the specified files on the next commit
2852
2854
2853 Schedule the indicated files for removal from the repository.
2855 Schedule the indicated files for removal from the repository.
2854
2856
2855 This only removes files from the current branch, not from the
2857 This only removes files from the current branch, not from the
2856 entire project history. -A/--after can be used to remove only
2858 entire project history. -A/--after can be used to remove only
2857 files that have already been deleted, -f/--force can be used to
2859 files that have already been deleted, -f/--force can be used to
2858 force deletion, and -Af can be used to remove files from the next
2860 force deletion, and -Af can be used to remove files from the next
2859 revision without deleting them from the working directory.
2861 revision without deleting them from the working directory.
2860
2862
2861 The following table details the behavior of remove for different
2863 The following table details the behavior of remove for different
2862 file states (columns) and option combinations (rows). The file
2864 file states (columns) and option combinations (rows). The file
2863 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2865 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2864 reported by :hg:`status`). The actions are Warn, Remove (from
2866 reported by :hg:`status`). The actions are Warn, Remove (from
2865 branch) and Delete (from disk)::
2867 branch) and Delete (from disk)::
2866
2868
2867 A C M !
2869 A C M !
2868 none W RD W R
2870 none W RD W R
2869 -f R RD RD R
2871 -f R RD RD R
2870 -A W W W R
2872 -A W W W R
2871 -Af R R R R
2873 -Af R R R R
2872
2874
2873 This command schedules the files to be removed at the next commit.
2875 This command schedules the files to be removed at the next commit.
2874 To undo a remove before that, see :hg:`revert`.
2876 To undo a remove before that, see :hg:`revert`.
2875
2877
2876 Returns 0 on success, 1 if any warnings encountered.
2878 Returns 0 on success, 1 if any warnings encountered.
2877 """
2879 """
2878
2880
2879 ret = 0
2881 ret = 0
2880 after, force = opts.get('after'), opts.get('force')
2882 after, force = opts.get('after'), opts.get('force')
2881 if not pats and not after:
2883 if not pats and not after:
2882 raise util.Abort(_('no files specified'))
2884 raise util.Abort(_('no files specified'))
2883
2885
2884 m = cmdutil.match(repo, pats, opts)
2886 m = cmdutil.match(repo, pats, opts)
2885 s = repo.status(match=m, clean=True)
2887 s = repo.status(match=m, clean=True)
2886 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2888 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2887
2889
2888 for f in m.files():
2890 for f in m.files():
2889 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2891 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2890 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2892 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2891 ret = 1
2893 ret = 1
2892
2894
2893 if force:
2895 if force:
2894 remove, forget = modified + deleted + clean, added
2896 remove, forget = modified + deleted + clean, added
2895 elif after:
2897 elif after:
2896 remove, forget = deleted, []
2898 remove, forget = deleted, []
2897 for f in modified + added + clean:
2899 for f in modified + added + clean:
2898 ui.warn(_('not removing %s: file still exists (use -f'
2900 ui.warn(_('not removing %s: file still exists (use -f'
2899 ' to force removal)\n') % m.rel(f))
2901 ' to force removal)\n') % m.rel(f))
2900 ret = 1
2902 ret = 1
2901 else:
2903 else:
2902 remove, forget = deleted + clean, []
2904 remove, forget = deleted + clean, []
2903 for f in modified:
2905 for f in modified:
2904 ui.warn(_('not removing %s: file is modified (use -f'
2906 ui.warn(_('not removing %s: file is modified (use -f'
2905 ' to force removal)\n') % m.rel(f))
2907 ' to force removal)\n') % m.rel(f))
2906 ret = 1
2908 ret = 1
2907 for f in added:
2909 for f in added:
2908 ui.warn(_('not removing %s: file has been marked for add (use -f'
2910 ui.warn(_('not removing %s: file has been marked for add (use -f'
2909 ' to force removal)\n') % m.rel(f))
2911 ' to force removal)\n') % m.rel(f))
2910 ret = 1
2912 ret = 1
2911
2913
2912 for f in sorted(remove + forget):
2914 for f in sorted(remove + forget):
2913 if ui.verbose or not m.exact(f):
2915 if ui.verbose or not m.exact(f):
2914 ui.status(_('removing %s\n') % m.rel(f))
2916 ui.status(_('removing %s\n') % m.rel(f))
2915
2917
2916 repo[None].forget(forget)
2918 repo[None].forget(forget)
2917 repo[None].remove(remove, unlink=not after)
2919 repo[None].remove(remove, unlink=not after)
2918 return ret
2920 return ret
2919
2921
2920 def rename(ui, repo, *pats, **opts):
2922 def rename(ui, repo, *pats, **opts):
2921 """rename files; equivalent of copy + remove
2923 """rename files; equivalent of copy + remove
2922
2924
2923 Mark dest as copies of sources; mark sources for deletion. If dest
2925 Mark dest as copies of sources; mark sources for deletion. If dest
2924 is a directory, copies are put in that directory. If dest is a
2926 is a directory, copies are put in that directory. If dest is a
2925 file, there can only be one source.
2927 file, there can only be one source.
2926
2928
2927 By default, this command copies the contents of files as they
2929 By default, this command copies the contents of files as they
2928 exist in the working directory. If invoked with -A/--after, the
2930 exist in the working directory. If invoked with -A/--after, the
2929 operation is recorded, but no copying is performed.
2931 operation is recorded, but no copying is performed.
2930
2932
2931 This command takes effect at the next commit. To undo a rename
2933 This command takes effect at the next commit. To undo a rename
2932 before that, see :hg:`revert`.
2934 before that, see :hg:`revert`.
2933
2935
2934 Returns 0 on success, 1 if errors are encountered.
2936 Returns 0 on success, 1 if errors are encountered.
2935 """
2937 """
2936 wlock = repo.wlock(False)
2938 wlock = repo.wlock(False)
2937 try:
2939 try:
2938 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2940 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2939 finally:
2941 finally:
2940 wlock.release()
2942 wlock.release()
2941
2943
2942 def resolve(ui, repo, *pats, **opts):
2944 def resolve(ui, repo, *pats, **opts):
2943 """redo merges or set/view the merge status of files
2945 """redo merges or set/view the merge status of files
2944
2946
2945 Merges with unresolved conflicts are often the result of
2947 Merges with unresolved conflicts are often the result of
2946 non-interactive merging using the ``internal:merge`` configuration
2948 non-interactive merging using the ``internal:merge`` configuration
2947 setting, or a command-line merge tool like ``diff3``. The resolve
2949 setting, or a command-line merge tool like ``diff3``. The resolve
2948 command is used to manage the files involved in a merge, after
2950 command is used to manage the files involved in a merge, after
2949 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2951 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2950 working directory must have two parents).
2952 working directory must have two parents).
2951
2953
2952 The resolve command can be used in the following ways:
2954 The resolve command can be used in the following ways:
2953
2955
2954 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
2956 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
2955 files, discarding any previous merge attempts. Re-merging is not
2957 files, discarding any previous merge attempts. Re-merging is not
2956 performed for files already marked as resolved. Use ``--all/-a``
2958 performed for files already marked as resolved. Use ``--all/-a``
2957 to selects all unresolved files. ``--tool`` can be used to specify
2959 to selects all unresolved files. ``--tool`` can be used to specify
2958 the merge tool used for the given files. It overrides the HGMERGE
2960 the merge tool used for the given files. It overrides the HGMERGE
2959 environment variable and your configuration files.
2961 environment variable and your configuration files.
2960
2962
2961 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2963 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2962 (e.g. after having manually fixed-up the files). The default is
2964 (e.g. after having manually fixed-up the files). The default is
2963 to mark all unresolved files.
2965 to mark all unresolved files.
2964
2966
2965 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2967 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2966 default is to mark all resolved files.
2968 default is to mark all resolved files.
2967
2969
2968 - :hg:`resolve -l`: list files which had or still have conflicts.
2970 - :hg:`resolve -l`: list files which had or still have conflicts.
2969 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2971 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2970
2972
2971 Note that Mercurial will not let you commit files with unresolved
2973 Note that Mercurial will not let you commit files with unresolved
2972 merge conflicts. You must use :hg:`resolve -m ...` before you can
2974 merge conflicts. You must use :hg:`resolve -m ...` before you can
2973 commit after a conflicting merge.
2975 commit after a conflicting merge.
2974
2976
2975 Returns 0 on success, 1 if any files fail a resolve attempt.
2977 Returns 0 on success, 1 if any files fail a resolve attempt.
2976 """
2978 """
2977
2979
2978 all, mark, unmark, show, nostatus = \
2980 all, mark, unmark, show, nostatus = \
2979 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2981 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2980
2982
2981 if (show and (mark or unmark)) or (mark and unmark):
2983 if (show and (mark or unmark)) or (mark and unmark):
2982 raise util.Abort(_("too many options specified"))
2984 raise util.Abort(_("too many options specified"))
2983 if pats and all:
2985 if pats and all:
2984 raise util.Abort(_("can't specify --all and patterns"))
2986 raise util.Abort(_("can't specify --all and patterns"))
2985 if not (all or pats or show or mark or unmark):
2987 if not (all or pats or show or mark or unmark):
2986 raise util.Abort(_('no files or directories specified; '
2988 raise util.Abort(_('no files or directories specified; '
2987 'use --all to remerge all files'))
2989 'use --all to remerge all files'))
2988
2990
2989 ms = mergemod.mergestate(repo)
2991 ms = mergemod.mergestate(repo)
2990 m = cmdutil.match(repo, pats, opts)
2992 m = cmdutil.match(repo, pats, opts)
2991 ret = 0
2993 ret = 0
2992
2994
2993 for f in ms:
2995 for f in ms:
2994 if m(f):
2996 if m(f):
2995 if show:
2997 if show:
2996 if nostatus:
2998 if nostatus:
2997 ui.write("%s\n" % f)
2999 ui.write("%s\n" % f)
2998 else:
3000 else:
2999 ui.write("%s %s\n" % (ms[f].upper(), f),
3001 ui.write("%s %s\n" % (ms[f].upper(), f),
3000 label='resolve.' +
3002 label='resolve.' +
3001 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3003 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3002 elif mark:
3004 elif mark:
3003 ms.mark(f, "r")
3005 ms.mark(f, "r")
3004 elif unmark:
3006 elif unmark:
3005 ms.mark(f, "u")
3007 ms.mark(f, "u")
3006 else:
3008 else:
3007 wctx = repo[None]
3009 wctx = repo[None]
3008 mctx = wctx.parents()[-1]
3010 mctx = wctx.parents()[-1]
3009
3011
3010 # backup pre-resolve (merge uses .orig for its own purposes)
3012 # backup pre-resolve (merge uses .orig for its own purposes)
3011 a = repo.wjoin(f)
3013 a = repo.wjoin(f)
3012 util.copyfile(a, a + ".resolve")
3014 util.copyfile(a, a + ".resolve")
3013
3015
3014 try:
3016 try:
3015 # resolve file
3017 # resolve file
3016 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3018 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3017 if ms.resolve(f, wctx, mctx):
3019 if ms.resolve(f, wctx, mctx):
3018 ret = 1
3020 ret = 1
3019 finally:
3021 finally:
3020 ui.setconfig('ui', 'forcemerge', '')
3022 ui.setconfig('ui', 'forcemerge', '')
3021
3023
3022 # replace filemerge's .orig file with our resolve file
3024 # replace filemerge's .orig file with our resolve file
3023 util.rename(a + ".resolve", a + ".orig")
3025 util.rename(a + ".resolve", a + ".orig")
3024
3026
3025 ms.commit()
3027 ms.commit()
3026 return ret
3028 return ret
3027
3029
3028 def revert(ui, repo, *pats, **opts):
3030 def revert(ui, repo, *pats, **opts):
3029 """restore individual files or directories to an earlier state
3031 """restore individual files or directories to an earlier state
3030
3032
3031 .. note::
3033 .. note::
3032 This command is most likely not what you are looking for.
3034 This command is most likely not what you are looking for.
3033 Revert will partially overwrite content in the working
3035 Revert will partially overwrite content in the working
3034 directory without changing the working directory parents. Use
3036 directory without changing the working directory parents. Use
3035 :hg:`update -r rev` to check out earlier revisions, or
3037 :hg:`update -r rev` to check out earlier revisions, or
3036 :hg:`update --clean .` to undo a merge which has added another
3038 :hg:`update --clean .` to undo a merge which has added another
3037 parent.
3039 parent.
3038
3040
3039 With no revision specified, revert the named files or directories
3041 With no revision specified, revert the named files or directories
3040 to the contents they had in the parent of the working directory.
3042 to the contents they had in the parent of the working directory.
3041 This restores the contents of the affected files to an unmodified
3043 This restores the contents of the affected files to an unmodified
3042 state and unschedules adds, removes, copies, and renames. If the
3044 state and unschedules adds, removes, copies, and renames. If the
3043 working directory has two parents, you must explicitly specify a
3045 working directory has two parents, you must explicitly specify a
3044 revision.
3046 revision.
3045
3047
3046 Using the -r/--rev option, revert the given files or directories
3048 Using the -r/--rev option, revert the given files or directories
3047 to their contents as of a specific revision. This can be helpful
3049 to their contents as of a specific revision. This can be helpful
3048 to "roll back" some or all of an earlier change. See :hg:`help
3050 to "roll back" some or all of an earlier change. See :hg:`help
3049 dates` for a list of formats valid for -d/--date.
3051 dates` for a list of formats valid for -d/--date.
3050
3052
3051 Revert modifies the working directory. It does not commit any
3053 Revert modifies the working directory. It does not commit any
3052 changes, or change the parent of the working directory. If you
3054 changes, or change the parent of the working directory. If you
3053 revert to a revision other than the parent of the working
3055 revert to a revision other than the parent of the working
3054 directory, the reverted files will thus appear modified
3056 directory, the reverted files will thus appear modified
3055 afterwards.
3057 afterwards.
3056
3058
3057 If a file has been deleted, it is restored. If the executable mode
3059 If a file has been deleted, it is restored. If the executable mode
3058 of a file was changed, it is reset.
3060 of a file was changed, it is reset.
3059
3061
3060 If names are given, all files matching the names are reverted.
3062 If names are given, all files matching the names are reverted.
3061 If no arguments are given, no files are reverted.
3063 If no arguments are given, no files are reverted.
3062
3064
3063 Modified files are saved with a .orig suffix before reverting.
3065 Modified files are saved with a .orig suffix before reverting.
3064 To disable these backups, use --no-backup.
3066 To disable these backups, use --no-backup.
3065
3067
3066 Returns 0 on success.
3068 Returns 0 on success.
3067 """
3069 """
3068
3070
3069 if opts.get("date"):
3071 if opts.get("date"):
3070 if opts.get("rev"):
3072 if opts.get("rev"):
3071 raise util.Abort(_("you can't specify a revision and a date"))
3073 raise util.Abort(_("you can't specify a revision and a date"))
3072 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3074 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3073
3075
3074 if not pats and not opts.get('all'):
3076 if not pats and not opts.get('all'):
3075 raise util.Abort(_('no files or directories specified; '
3077 raise util.Abort(_('no files or directories specified; '
3076 'use --all to revert the whole repo'))
3078 'use --all to revert the whole repo'))
3077
3079
3078 parent, p2 = repo.dirstate.parents()
3080 parent, p2 = repo.dirstate.parents()
3079 if not opts.get('rev') and p2 != nullid:
3081 if not opts.get('rev') and p2 != nullid:
3080 raise util.Abort(_('uncommitted merge - please provide a '
3082 raise util.Abort(_('uncommitted merge - please provide a '
3081 'specific revision'))
3083 'specific revision'))
3082 ctx = repo[opts.get('rev')]
3084 ctx = repo[opts.get('rev')]
3083 node = ctx.node()
3085 node = ctx.node()
3084 mf = ctx.manifest()
3086 mf = ctx.manifest()
3085 if node == parent:
3087 if node == parent:
3086 pmf = mf
3088 pmf = mf
3087 else:
3089 else:
3088 pmf = None
3090 pmf = None
3089
3091
3090 # need all matching names in dirstate and manifest of target rev,
3092 # need all matching names in dirstate and manifest of target rev,
3091 # so have to walk both. do not print errors if files exist in one
3093 # so have to walk both. do not print errors if files exist in one
3092 # but not other.
3094 # but not other.
3093
3095
3094 names = {}
3096 names = {}
3095
3097
3096 wlock = repo.wlock()
3098 wlock = repo.wlock()
3097 try:
3099 try:
3098 # walk dirstate.
3100 # walk dirstate.
3099
3101
3100 m = cmdutil.match(repo, pats, opts)
3102 m = cmdutil.match(repo, pats, opts)
3101 m.bad = lambda x, y: False
3103 m.bad = lambda x, y: False
3102 for abs in repo.walk(m):
3104 for abs in repo.walk(m):
3103 names[abs] = m.rel(abs), m.exact(abs)
3105 names[abs] = m.rel(abs), m.exact(abs)
3104
3106
3105 # walk target manifest.
3107 # walk target manifest.
3106
3108
3107 def badfn(path, msg):
3109 def badfn(path, msg):
3108 if path in names:
3110 if path in names:
3109 return
3111 return
3110 path_ = path + '/'
3112 path_ = path + '/'
3111 for f in names:
3113 for f in names:
3112 if f.startswith(path_):
3114 if f.startswith(path_):
3113 return
3115 return
3114 ui.warn("%s: %s\n" % (m.rel(path), msg))
3116 ui.warn("%s: %s\n" % (m.rel(path), msg))
3115
3117
3116 m = cmdutil.match(repo, pats, opts)
3118 m = cmdutil.match(repo, pats, opts)
3117 m.bad = badfn
3119 m.bad = badfn
3118 for abs in repo[node].walk(m):
3120 for abs in repo[node].walk(m):
3119 if abs not in names:
3121 if abs not in names:
3120 names[abs] = m.rel(abs), m.exact(abs)
3122 names[abs] = m.rel(abs), m.exact(abs)
3121
3123
3122 m = cmdutil.matchfiles(repo, names)
3124 m = cmdutil.matchfiles(repo, names)
3123 changes = repo.status(match=m)[:4]
3125 changes = repo.status(match=m)[:4]
3124 modified, added, removed, deleted = map(set, changes)
3126 modified, added, removed, deleted = map(set, changes)
3125
3127
3126 # if f is a rename, also revert the source
3128 # if f is a rename, also revert the source
3127 cwd = repo.getcwd()
3129 cwd = repo.getcwd()
3128 for f in added:
3130 for f in added:
3129 src = repo.dirstate.copied(f)
3131 src = repo.dirstate.copied(f)
3130 if src and src not in names and repo.dirstate[src] == 'r':
3132 if src and src not in names and repo.dirstate[src] == 'r':
3131 removed.add(src)
3133 removed.add(src)
3132 names[src] = (repo.pathto(src, cwd), True)
3134 names[src] = (repo.pathto(src, cwd), True)
3133
3135
3134 def removeforget(abs):
3136 def removeforget(abs):
3135 if repo.dirstate[abs] == 'a':
3137 if repo.dirstate[abs] == 'a':
3136 return _('forgetting %s\n')
3138 return _('forgetting %s\n')
3137 return _('removing %s\n')
3139 return _('removing %s\n')
3138
3140
3139 revert = ([], _('reverting %s\n'))
3141 revert = ([], _('reverting %s\n'))
3140 add = ([], _('adding %s\n'))
3142 add = ([], _('adding %s\n'))
3141 remove = ([], removeforget)
3143 remove = ([], removeforget)
3142 undelete = ([], _('undeleting %s\n'))
3144 undelete = ([], _('undeleting %s\n'))
3143
3145
3144 disptable = (
3146 disptable = (
3145 # dispatch table:
3147 # dispatch table:
3146 # file state
3148 # file state
3147 # action if in target manifest
3149 # action if in target manifest
3148 # action if not in target manifest
3150 # action if not in target manifest
3149 # make backup if in target manifest
3151 # make backup if in target manifest
3150 # make backup if not in target manifest
3152 # make backup if not in target manifest
3151 (modified, revert, remove, True, True),
3153 (modified, revert, remove, True, True),
3152 (added, revert, remove, True, False),
3154 (added, revert, remove, True, False),
3153 (removed, undelete, None, False, False),
3155 (removed, undelete, None, False, False),
3154 (deleted, revert, remove, False, False),
3156 (deleted, revert, remove, False, False),
3155 )
3157 )
3156
3158
3157 for abs, (rel, exact) in sorted(names.items()):
3159 for abs, (rel, exact) in sorted(names.items()):
3158 mfentry = mf.get(abs)
3160 mfentry = mf.get(abs)
3159 target = repo.wjoin(abs)
3161 target = repo.wjoin(abs)
3160 def handle(xlist, dobackup):
3162 def handle(xlist, dobackup):
3161 xlist[0].append(abs)
3163 xlist[0].append(abs)
3162 if (dobackup and not opts.get('no_backup') and
3164 if (dobackup and not opts.get('no_backup') and
3163 os.path.lexists(target)):
3165 os.path.lexists(target)):
3164 bakname = "%s.orig" % rel
3166 bakname = "%s.orig" % rel
3165 ui.note(_('saving current version of %s as %s\n') %
3167 ui.note(_('saving current version of %s as %s\n') %
3166 (rel, bakname))
3168 (rel, bakname))
3167 if not opts.get('dry_run'):
3169 if not opts.get('dry_run'):
3168 util.rename(target, bakname)
3170 util.rename(target, bakname)
3169 if ui.verbose or not exact:
3171 if ui.verbose or not exact:
3170 msg = xlist[1]
3172 msg = xlist[1]
3171 if not isinstance(msg, basestring):
3173 if not isinstance(msg, basestring):
3172 msg = msg(abs)
3174 msg = msg(abs)
3173 ui.status(msg % rel)
3175 ui.status(msg % rel)
3174 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3176 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3175 if abs not in table:
3177 if abs not in table:
3176 continue
3178 continue
3177 # file has changed in dirstate
3179 # file has changed in dirstate
3178 if mfentry:
3180 if mfentry:
3179 handle(hitlist, backuphit)
3181 handle(hitlist, backuphit)
3180 elif misslist is not None:
3182 elif misslist is not None:
3181 handle(misslist, backupmiss)
3183 handle(misslist, backupmiss)
3182 break
3184 break
3183 else:
3185 else:
3184 if abs not in repo.dirstate:
3186 if abs not in repo.dirstate:
3185 if mfentry:
3187 if mfentry:
3186 handle(add, True)
3188 handle(add, True)
3187 elif exact:
3189 elif exact:
3188 ui.warn(_('file not managed: %s\n') % rel)
3190 ui.warn(_('file not managed: %s\n') % rel)
3189 continue
3191 continue
3190 # file has not changed in dirstate
3192 # file has not changed in dirstate
3191 if node == parent:
3193 if node == parent:
3192 if exact:
3194 if exact:
3193 ui.warn(_('no changes needed to %s\n') % rel)
3195 ui.warn(_('no changes needed to %s\n') % rel)
3194 continue
3196 continue
3195 if pmf is None:
3197 if pmf is None:
3196 # only need parent manifest in this unlikely case,
3198 # only need parent manifest in this unlikely case,
3197 # so do not read by default
3199 # so do not read by default
3198 pmf = repo[parent].manifest()
3200 pmf = repo[parent].manifest()
3199 if abs in pmf:
3201 if abs in pmf:
3200 if mfentry:
3202 if mfentry:
3201 # if version of file is same in parent and target
3203 # if version of file is same in parent and target
3202 # manifests, do nothing
3204 # manifests, do nothing
3203 if (pmf[abs] != mfentry or
3205 if (pmf[abs] != mfentry or
3204 pmf.flags(abs) != mf.flags(abs)):
3206 pmf.flags(abs) != mf.flags(abs)):
3205 handle(revert, False)
3207 handle(revert, False)
3206 else:
3208 else:
3207 handle(remove, False)
3209 handle(remove, False)
3208
3210
3209 if not opts.get('dry_run'):
3211 if not opts.get('dry_run'):
3210 def checkout(f):
3212 def checkout(f):
3211 fc = ctx[f]
3213 fc = ctx[f]
3212 repo.wwrite(f, fc.data(), fc.flags())
3214 repo.wwrite(f, fc.data(), fc.flags())
3213
3215
3214 audit_path = util.path_auditor(repo.root)
3216 audit_path = util.path_auditor(repo.root)
3215 for f in remove[0]:
3217 for f in remove[0]:
3216 if repo.dirstate[f] == 'a':
3218 if repo.dirstate[f] == 'a':
3217 repo.dirstate.forget(f)
3219 repo.dirstate.forget(f)
3218 continue
3220 continue
3219 audit_path(f)
3221 audit_path(f)
3220 try:
3222 try:
3221 util.unlink(repo.wjoin(f))
3223 util.unlink(repo.wjoin(f))
3222 except OSError:
3224 except OSError:
3223 pass
3225 pass
3224 repo.dirstate.remove(f)
3226 repo.dirstate.remove(f)
3225
3227
3226 normal = None
3228 normal = None
3227 if node == parent:
3229 if node == parent:
3228 # We're reverting to our parent. If possible, we'd like status
3230 # We're reverting to our parent. If possible, we'd like status
3229 # to report the file as clean. We have to use normallookup for
3231 # to report the file as clean. We have to use normallookup for
3230 # merges to avoid losing information about merged/dirty files.
3232 # merges to avoid losing information about merged/dirty files.
3231 if p2 != nullid:
3233 if p2 != nullid:
3232 normal = repo.dirstate.normallookup
3234 normal = repo.dirstate.normallookup
3233 else:
3235 else:
3234 normal = repo.dirstate.normal
3236 normal = repo.dirstate.normal
3235 for f in revert[0]:
3237 for f in revert[0]:
3236 checkout(f)
3238 checkout(f)
3237 if normal:
3239 if normal:
3238 normal(f)
3240 normal(f)
3239
3241
3240 for f in add[0]:
3242 for f in add[0]:
3241 checkout(f)
3243 checkout(f)
3242 repo.dirstate.add(f)
3244 repo.dirstate.add(f)
3243
3245
3244 normal = repo.dirstate.normallookup
3246 normal = repo.dirstate.normallookup
3245 if node == parent and p2 == nullid:
3247 if node == parent and p2 == nullid:
3246 normal = repo.dirstate.normal
3248 normal = repo.dirstate.normal
3247 for f in undelete[0]:
3249 for f in undelete[0]:
3248 checkout(f)
3250 checkout(f)
3249 normal(f)
3251 normal(f)
3250
3252
3251 finally:
3253 finally:
3252 wlock.release()
3254 wlock.release()
3253
3255
3254 def rollback(ui, repo, **opts):
3256 def rollback(ui, repo, **opts):
3255 """roll back the last transaction (dangerous)
3257 """roll back the last transaction (dangerous)
3256
3258
3257 This command should be used with care. There is only one level of
3259 This command should be used with care. There is only one level of
3258 rollback, and there is no way to undo a rollback. It will also
3260 rollback, and there is no way to undo a rollback. It will also
3259 restore the dirstate at the time of the last transaction, losing
3261 restore the dirstate at the time of the last transaction, losing
3260 any dirstate changes since that time. This command does not alter
3262 any dirstate changes since that time. This command does not alter
3261 the working directory.
3263 the working directory.
3262
3264
3263 Transactions are used to encapsulate the effects of all commands
3265 Transactions are used to encapsulate the effects of all commands
3264 that create new changesets or propagate existing changesets into a
3266 that create new changesets or propagate existing changesets into a
3265 repository. For example, the following commands are transactional,
3267 repository. For example, the following commands are transactional,
3266 and their effects can be rolled back:
3268 and their effects can be rolled back:
3267
3269
3268 - commit
3270 - commit
3269 - import
3271 - import
3270 - pull
3272 - pull
3271 - push (with this repository as the destination)
3273 - push (with this repository as the destination)
3272 - unbundle
3274 - unbundle
3273
3275
3274 This command is not intended for use on public repositories. Once
3276 This command is not intended for use on public repositories. Once
3275 changes are visible for pull by other users, rolling a transaction
3277 changes are visible for pull by other users, rolling a transaction
3276 back locally is ineffective (someone else may already have pulled
3278 back locally is ineffective (someone else may already have pulled
3277 the changes). Furthermore, a race is possible with readers of the
3279 the changes). Furthermore, a race is possible with readers of the
3278 repository; for example an in-progress pull from the repository
3280 repository; for example an in-progress pull from the repository
3279 may fail if a rollback is performed.
3281 may fail if a rollback is performed.
3280
3282
3281 Returns 0 on success, 1 if no rollback data is available.
3283 Returns 0 on success, 1 if no rollback data is available.
3282 """
3284 """
3283 return repo.rollback(opts.get('dry_run'))
3285 return repo.rollback(opts.get('dry_run'))
3284
3286
3285 def root(ui, repo):
3287 def root(ui, repo):
3286 """print the root (top) of the current working directory
3288 """print the root (top) of the current working directory
3287
3289
3288 Print the root directory of the current repository.
3290 Print the root directory of the current repository.
3289
3291
3290 Returns 0 on success.
3292 Returns 0 on success.
3291 """
3293 """
3292 ui.write(repo.root + "\n")
3294 ui.write(repo.root + "\n")
3293
3295
3294 def serve(ui, repo, **opts):
3296 def serve(ui, repo, **opts):
3295 """start stand-alone webserver
3297 """start stand-alone webserver
3296
3298
3297 Start a local HTTP repository browser and pull server. You can use
3299 Start a local HTTP repository browser and pull server. You can use
3298 this for ad-hoc sharing and browing of repositories. It is
3300 this for ad-hoc sharing and browing of repositories. It is
3299 recommended to use a real web server to serve a repository for
3301 recommended to use a real web server to serve a repository for
3300 longer periods of time.
3302 longer periods of time.
3301
3303
3302 Please note that the server does not implement access control.
3304 Please note that the server does not implement access control.
3303 This means that, by default, anybody can read from the server and
3305 This means that, by default, anybody can read from the server and
3304 nobody can write to it by default. Set the ``web.allow_push``
3306 nobody can write to it by default. Set the ``web.allow_push``
3305 option to ``*`` to allow everybody to push to the server. You
3307 option to ``*`` to allow everybody to push to the server. You
3306 should use a real web server if you need to authenticate users.
3308 should use a real web server if you need to authenticate users.
3307
3309
3308 By default, the server logs accesses to stdout and errors to
3310 By default, the server logs accesses to stdout and errors to
3309 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3311 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3310 files.
3312 files.
3311
3313
3312 To have the server choose a free port number to listen on, specify
3314 To have the server choose a free port number to listen on, specify
3313 a port number of 0; in this case, the server will print the port
3315 a port number of 0; in this case, the server will print the port
3314 number it uses.
3316 number it uses.
3315
3317
3316 Returns 0 on success.
3318 Returns 0 on success.
3317 """
3319 """
3318
3320
3319 if opts["stdio"]:
3321 if opts["stdio"]:
3320 if repo is None:
3322 if repo is None:
3321 raise error.RepoError(_("There is no Mercurial repository here"
3323 raise error.RepoError(_("There is no Mercurial repository here"
3322 " (.hg not found)"))
3324 " (.hg not found)"))
3323 s = sshserver.sshserver(ui, repo)
3325 s = sshserver.sshserver(ui, repo)
3324 s.serve_forever()
3326 s.serve_forever()
3325
3327
3326 # this way we can check if something was given in the command-line
3328 # this way we can check if something was given in the command-line
3327 if opts.get('port'):
3329 if opts.get('port'):
3328 opts['port'] = util.getport(opts.get('port'))
3330 opts['port'] = util.getport(opts.get('port'))
3329
3331
3330 baseui = repo and repo.baseui or ui
3332 baseui = repo and repo.baseui or ui
3331 optlist = ("name templates style address port prefix ipv6"
3333 optlist = ("name templates style address port prefix ipv6"
3332 " accesslog errorlog certificate encoding")
3334 " accesslog errorlog certificate encoding")
3333 for o in optlist.split():
3335 for o in optlist.split():
3334 val = opts.get(o, '')
3336 val = opts.get(o, '')
3335 if val in (None, ''): # should check against default options instead
3337 if val in (None, ''): # should check against default options instead
3336 continue
3338 continue
3337 baseui.setconfig("web", o, val)
3339 baseui.setconfig("web", o, val)
3338 if repo and repo.ui != baseui:
3340 if repo and repo.ui != baseui:
3339 repo.ui.setconfig("web", o, val)
3341 repo.ui.setconfig("web", o, val)
3340
3342
3341 o = opts.get('web_conf') or opts.get('webdir_conf')
3343 o = opts.get('web_conf') or opts.get('webdir_conf')
3342 if not o:
3344 if not o:
3343 if not repo:
3345 if not repo:
3344 raise error.RepoError(_("There is no Mercurial repository"
3346 raise error.RepoError(_("There is no Mercurial repository"
3345 " here (.hg not found)"))
3347 " here (.hg not found)"))
3346 o = repo.root
3348 o = repo.root
3347
3349
3348 app = hgweb.hgweb(o, baseui=ui)
3350 app = hgweb.hgweb(o, baseui=ui)
3349
3351
3350 class service(object):
3352 class service(object):
3351 def init(self):
3353 def init(self):
3352 util.set_signal_handler()
3354 util.set_signal_handler()
3353 self.httpd = hgweb.server.create_server(ui, app)
3355 self.httpd = hgweb.server.create_server(ui, app)
3354
3356
3355 if opts['port'] and not ui.verbose:
3357 if opts['port'] and not ui.verbose:
3356 return
3358 return
3357
3359
3358 if self.httpd.prefix:
3360 if self.httpd.prefix:
3359 prefix = self.httpd.prefix.strip('/') + '/'
3361 prefix = self.httpd.prefix.strip('/') + '/'
3360 else:
3362 else:
3361 prefix = ''
3363 prefix = ''
3362
3364
3363 port = ':%d' % self.httpd.port
3365 port = ':%d' % self.httpd.port
3364 if port == ':80':
3366 if port == ':80':
3365 port = ''
3367 port = ''
3366
3368
3367 bindaddr = self.httpd.addr
3369 bindaddr = self.httpd.addr
3368 if bindaddr == '0.0.0.0':
3370 if bindaddr == '0.0.0.0':
3369 bindaddr = '*'
3371 bindaddr = '*'
3370 elif ':' in bindaddr: # IPv6
3372 elif ':' in bindaddr: # IPv6
3371 bindaddr = '[%s]' % bindaddr
3373 bindaddr = '[%s]' % bindaddr
3372
3374
3373 fqaddr = self.httpd.fqaddr
3375 fqaddr = self.httpd.fqaddr
3374 if ':' in fqaddr:
3376 if ':' in fqaddr:
3375 fqaddr = '[%s]' % fqaddr
3377 fqaddr = '[%s]' % fqaddr
3376 if opts['port']:
3378 if opts['port']:
3377 write = ui.status
3379 write = ui.status
3378 else:
3380 else:
3379 write = ui.write
3381 write = ui.write
3380 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3382 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3381 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3383 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3382
3384
3383 def run(self):
3385 def run(self):
3384 self.httpd.serve_forever()
3386 self.httpd.serve_forever()
3385
3387
3386 service = service()
3388 service = service()
3387
3389
3388 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3390 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3389
3391
3390 def status(ui, repo, *pats, **opts):
3392 def status(ui, repo, *pats, **opts):
3391 """show changed files in the working directory
3393 """show changed files in the working directory
3392
3394
3393 Show status of files in the repository. If names are given, only
3395 Show status of files in the repository. If names are given, only
3394 files that match are shown. Files that are clean or ignored or
3396 files that match are shown. Files that are clean or ignored or
3395 the source of a copy/move operation, are not listed unless
3397 the source of a copy/move operation, are not listed unless
3396 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3398 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3397 Unless options described with "show only ..." are given, the
3399 Unless options described with "show only ..." are given, the
3398 options -mardu are used.
3400 options -mardu are used.
3399
3401
3400 Option -q/--quiet hides untracked (unknown and ignored) files
3402 Option -q/--quiet hides untracked (unknown and ignored) files
3401 unless explicitly requested with -u/--unknown or -i/--ignored.
3403 unless explicitly requested with -u/--unknown or -i/--ignored.
3402
3404
3403 .. note::
3405 .. note::
3404 status may appear to disagree with diff if permissions have
3406 status may appear to disagree with diff if permissions have
3405 changed or a merge has occurred. The standard diff format does
3407 changed or a merge has occurred. The standard diff format does
3406 not report permission changes and diff only reports changes
3408 not report permission changes and diff only reports changes
3407 relative to one merge parent.
3409 relative to one merge parent.
3408
3410
3409 If one revision is given, it is used as the base revision.
3411 If one revision is given, it is used as the base revision.
3410 If two revisions are given, the differences between them are
3412 If two revisions are given, the differences between them are
3411 shown. The --change option can also be used as a shortcut to list
3413 shown. The --change option can also be used as a shortcut to list
3412 the changed files of a revision from its first parent.
3414 the changed files of a revision from its first parent.
3413
3415
3414 The codes used to show the status of files are::
3416 The codes used to show the status of files are::
3415
3417
3416 M = modified
3418 M = modified
3417 A = added
3419 A = added
3418 R = removed
3420 R = removed
3419 C = clean
3421 C = clean
3420 ! = missing (deleted by non-hg command, but still tracked)
3422 ! = missing (deleted by non-hg command, but still tracked)
3421 ? = not tracked
3423 ? = not tracked
3422 I = ignored
3424 I = ignored
3423 = origin of the previous file listed as A (added)
3425 = origin of the previous file listed as A (added)
3424
3426
3425 Returns 0 on success.
3427 Returns 0 on success.
3426 """
3428 """
3427
3429
3428 revs = opts.get('rev')
3430 revs = opts.get('rev')
3429 change = opts.get('change')
3431 change = opts.get('change')
3430
3432
3431 if revs and change:
3433 if revs and change:
3432 msg = _('cannot specify --rev and --change at the same time')
3434 msg = _('cannot specify --rev and --change at the same time')
3433 raise util.Abort(msg)
3435 raise util.Abort(msg)
3434 elif change:
3436 elif change:
3435 node2 = repo.lookup(change)
3437 node2 = repo.lookup(change)
3436 node1 = repo[node2].parents()[0].node()
3438 node1 = repo[node2].parents()[0].node()
3437 else:
3439 else:
3438 node1, node2 = cmdutil.revpair(repo, revs)
3440 node1, node2 = cmdutil.revpair(repo, revs)
3439
3441
3440 cwd = (pats and repo.getcwd()) or ''
3442 cwd = (pats and repo.getcwd()) or ''
3441 end = opts.get('print0') and '\0' or '\n'
3443 end = opts.get('print0') and '\0' or '\n'
3442 copy = {}
3444 copy = {}
3443 states = 'modified added removed deleted unknown ignored clean'.split()
3445 states = 'modified added removed deleted unknown ignored clean'.split()
3444 show = [k for k in states if opts.get(k)]
3446 show = [k for k in states if opts.get(k)]
3445 if opts.get('all'):
3447 if opts.get('all'):
3446 show += ui.quiet and (states[:4] + ['clean']) or states
3448 show += ui.quiet and (states[:4] + ['clean']) or states
3447 if not show:
3449 if not show:
3448 show = ui.quiet and states[:4] or states[:5]
3450 show = ui.quiet and states[:4] or states[:5]
3449
3451
3450 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3452 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3451 'ignored' in show, 'clean' in show, 'unknown' in show,
3453 'ignored' in show, 'clean' in show, 'unknown' in show,
3452 opts.get('subrepos'))
3454 opts.get('subrepos'))
3453 changestates = zip(states, 'MAR!?IC', stat)
3455 changestates = zip(states, 'MAR!?IC', stat)
3454
3456
3455 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3457 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3456 ctxn = repo[nullid]
3458 ctxn = repo[nullid]
3457 ctx1 = repo[node1]
3459 ctx1 = repo[node1]
3458 ctx2 = repo[node2]
3460 ctx2 = repo[node2]
3459 added = stat[1]
3461 added = stat[1]
3460 if node2 is None:
3462 if node2 is None:
3461 added = stat[0] + stat[1] # merged?
3463 added = stat[0] + stat[1] # merged?
3462
3464
3463 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3465 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3464 if k in added:
3466 if k in added:
3465 copy[k] = v
3467 copy[k] = v
3466 elif v in added:
3468 elif v in added:
3467 copy[v] = k
3469 copy[v] = k
3468
3470
3469 for state, char, files in changestates:
3471 for state, char, files in changestates:
3470 if state in show:
3472 if state in show:
3471 format = "%s %%s%s" % (char, end)
3473 format = "%s %%s%s" % (char, end)
3472 if opts.get('no_status'):
3474 if opts.get('no_status'):
3473 format = "%%s%s" % end
3475 format = "%%s%s" % end
3474
3476
3475 for f in files:
3477 for f in files:
3476 ui.write(format % repo.pathto(f, cwd),
3478 ui.write(format % repo.pathto(f, cwd),
3477 label='status.' + state)
3479 label='status.' + state)
3478 if f in copy:
3480 if f in copy:
3479 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3481 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3480 label='status.copied')
3482 label='status.copied')
3481
3483
3482 def summary(ui, repo, **opts):
3484 def summary(ui, repo, **opts):
3483 """summarize working directory state
3485 """summarize working directory state
3484
3486
3485 This generates a brief summary of the working directory state,
3487 This generates a brief summary of the working directory state,
3486 including parents, branch, commit status, and available updates.
3488 including parents, branch, commit status, and available updates.
3487
3489
3488 With the --remote option, this will check the default paths for
3490 With the --remote option, this will check the default paths for
3489 incoming and outgoing changes. This can be time-consuming.
3491 incoming and outgoing changes. This can be time-consuming.
3490
3492
3491 Returns 0 on success.
3493 Returns 0 on success.
3492 """
3494 """
3493
3495
3494 ctx = repo[None]
3496 ctx = repo[None]
3495 parents = ctx.parents()
3497 parents = ctx.parents()
3496 pnode = parents[0].node()
3498 pnode = parents[0].node()
3497
3499
3498 for p in parents:
3500 for p in parents:
3499 # label with log.changeset (instead of log.parent) since this
3501 # label with log.changeset (instead of log.parent) since this
3500 # shows a working directory parent *changeset*:
3502 # shows a working directory parent *changeset*:
3501 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3503 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3502 label='log.changeset')
3504 label='log.changeset')
3503 ui.write(' '.join(p.tags()), label='log.tag')
3505 ui.write(' '.join(p.tags()), label='log.tag')
3504 if p.rev() == -1:
3506 if p.rev() == -1:
3505 if not len(repo):
3507 if not len(repo):
3506 ui.write(_(' (empty repository)'))
3508 ui.write(_(' (empty repository)'))
3507 else:
3509 else:
3508 ui.write(_(' (no revision checked out)'))
3510 ui.write(_(' (no revision checked out)'))
3509 ui.write('\n')
3511 ui.write('\n')
3510 if p.description():
3512 if p.description():
3511 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3513 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3512 label='log.summary')
3514 label='log.summary')
3513
3515
3514 branch = ctx.branch()
3516 branch = ctx.branch()
3515 bheads = repo.branchheads(branch)
3517 bheads = repo.branchheads(branch)
3516 m = _('branch: %s\n') % branch
3518 m = _('branch: %s\n') % branch
3517 if branch != 'default':
3519 if branch != 'default':
3518 ui.write(m, label='log.branch')
3520 ui.write(m, label='log.branch')
3519 else:
3521 else:
3520 ui.status(m, label='log.branch')
3522 ui.status(m, label='log.branch')
3521
3523
3522 st = list(repo.status(unknown=True))[:6]
3524 st = list(repo.status(unknown=True))[:6]
3523
3525
3524 c = repo.dirstate.copies()
3526 c = repo.dirstate.copies()
3525 copied, renamed = [], []
3527 copied, renamed = [], []
3526 for d, s in c.iteritems():
3528 for d, s in c.iteritems():
3527 if s in st[2]:
3529 if s in st[2]:
3528 st[2].remove(s)
3530 st[2].remove(s)
3529 renamed.append(d)
3531 renamed.append(d)
3530 else:
3532 else:
3531 copied.append(d)
3533 copied.append(d)
3532 if d in st[1]:
3534 if d in st[1]:
3533 st[1].remove(d)
3535 st[1].remove(d)
3534 st.insert(3, renamed)
3536 st.insert(3, renamed)
3535 st.insert(4, copied)
3537 st.insert(4, copied)
3536
3538
3537 ms = mergemod.mergestate(repo)
3539 ms = mergemod.mergestate(repo)
3538 st.append([f for f in ms if ms[f] == 'u'])
3540 st.append([f for f in ms if ms[f] == 'u'])
3539
3541
3540 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3542 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3541 st.append(subs)
3543 st.append(subs)
3542
3544
3543 labels = [ui.label(_('%d modified'), 'status.modified'),
3545 labels = [ui.label(_('%d modified'), 'status.modified'),
3544 ui.label(_('%d added'), 'status.added'),
3546 ui.label(_('%d added'), 'status.added'),
3545 ui.label(_('%d removed'), 'status.removed'),
3547 ui.label(_('%d removed'), 'status.removed'),
3546 ui.label(_('%d renamed'), 'status.copied'),
3548 ui.label(_('%d renamed'), 'status.copied'),
3547 ui.label(_('%d copied'), 'status.copied'),
3549 ui.label(_('%d copied'), 'status.copied'),
3548 ui.label(_('%d deleted'), 'status.deleted'),
3550 ui.label(_('%d deleted'), 'status.deleted'),
3549 ui.label(_('%d unknown'), 'status.unknown'),
3551 ui.label(_('%d unknown'), 'status.unknown'),
3550 ui.label(_('%d ignored'), 'status.ignored'),
3552 ui.label(_('%d ignored'), 'status.ignored'),
3551 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3553 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3552 ui.label(_('%d subrepos'), 'status.modified')]
3554 ui.label(_('%d subrepos'), 'status.modified')]
3553 t = []
3555 t = []
3554 for s, l in zip(st, labels):
3556 for s, l in zip(st, labels):
3555 if s:
3557 if s:
3556 t.append(l % len(s))
3558 t.append(l % len(s))
3557
3559
3558 t = ', '.join(t)
3560 t = ', '.join(t)
3559 cleanworkdir = False
3561 cleanworkdir = False
3560
3562
3561 if len(parents) > 1:
3563 if len(parents) > 1:
3562 t += _(' (merge)')
3564 t += _(' (merge)')
3563 elif branch != parents[0].branch():
3565 elif branch != parents[0].branch():
3564 t += _(' (new branch)')
3566 t += _(' (new branch)')
3565 elif (parents[0].extra().get('close') and
3567 elif (parents[0].extra().get('close') and
3566 pnode in repo.branchheads(branch, closed=True)):
3568 pnode in repo.branchheads(branch, closed=True)):
3567 t += _(' (head closed)')
3569 t += _(' (head closed)')
3568 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3570 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3569 t += _(' (clean)')
3571 t += _(' (clean)')
3570 cleanworkdir = True
3572 cleanworkdir = True
3571 elif pnode not in bheads:
3573 elif pnode not in bheads:
3572 t += _(' (new branch head)')
3574 t += _(' (new branch head)')
3573
3575
3574 if cleanworkdir:
3576 if cleanworkdir:
3575 ui.status(_('commit: %s\n') % t.strip())
3577 ui.status(_('commit: %s\n') % t.strip())
3576 else:
3578 else:
3577 ui.write(_('commit: %s\n') % t.strip())
3579 ui.write(_('commit: %s\n') % t.strip())
3578
3580
3579 # all ancestors of branch heads - all ancestors of parent = new csets
3581 # all ancestors of branch heads - all ancestors of parent = new csets
3580 new = [0] * len(repo)
3582 new = [0] * len(repo)
3581 cl = repo.changelog
3583 cl = repo.changelog
3582 for a in [cl.rev(n) for n in bheads]:
3584 for a in [cl.rev(n) for n in bheads]:
3583 new[a] = 1
3585 new[a] = 1
3584 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3586 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3585 new[a] = 1
3587 new[a] = 1
3586 for a in [p.rev() for p in parents]:
3588 for a in [p.rev() for p in parents]:
3587 if a >= 0:
3589 if a >= 0:
3588 new[a] = 0
3590 new[a] = 0
3589 for a in cl.ancestors(*[p.rev() for p in parents]):
3591 for a in cl.ancestors(*[p.rev() for p in parents]):
3590 new[a] = 0
3592 new[a] = 0
3591 new = sum(new)
3593 new = sum(new)
3592
3594
3593 if new == 0:
3595 if new == 0:
3594 ui.status(_('update: (current)\n'))
3596 ui.status(_('update: (current)\n'))
3595 elif pnode not in bheads:
3597 elif pnode not in bheads:
3596 ui.write(_('update: %d new changesets (update)\n') % new)
3598 ui.write(_('update: %d new changesets (update)\n') % new)
3597 else:
3599 else:
3598 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3600 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3599 (new, len(bheads)))
3601 (new, len(bheads)))
3600
3602
3601 if opts.get('remote'):
3603 if opts.get('remote'):
3602 t = []
3604 t = []
3603 source, branches = hg.parseurl(ui.expandpath('default'))
3605 source, branches = hg.parseurl(ui.expandpath('default'))
3604 other = hg.repository(hg.remoteui(repo, {}), source)
3606 other = hg.repository(hg.remoteui(repo, {}), source)
3605 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3607 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3606 ui.debug('comparing with %s\n' % url.hidepassword(source))
3608 ui.debug('comparing with %s\n' % url.hidepassword(source))
3607 repo.ui.pushbuffer()
3609 repo.ui.pushbuffer()
3608 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3610 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3609 repo.ui.popbuffer()
3611 repo.ui.popbuffer()
3610 if incoming:
3612 if incoming:
3611 t.append(_('1 or more incoming'))
3613 t.append(_('1 or more incoming'))
3612
3614
3613 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3615 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3614 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3616 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3615 other = hg.repository(hg.remoteui(repo, {}), dest)
3617 other = hg.repository(hg.remoteui(repo, {}), dest)
3616 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3618 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3617 repo.ui.pushbuffer()
3619 repo.ui.pushbuffer()
3618 o = discovery.findoutgoing(repo, other)
3620 o = discovery.findoutgoing(repo, other)
3619 repo.ui.popbuffer()
3621 repo.ui.popbuffer()
3620 o = repo.changelog.nodesbetween(o, None)[0]
3622 o = repo.changelog.nodesbetween(o, None)[0]
3621 if o:
3623 if o:
3622 t.append(_('%d outgoing') % len(o))
3624 t.append(_('%d outgoing') % len(o))
3623
3625
3624 if t:
3626 if t:
3625 ui.write(_('remote: %s\n') % (', '.join(t)))
3627 ui.write(_('remote: %s\n') % (', '.join(t)))
3626 else:
3628 else:
3627 ui.status(_('remote: (synced)\n'))
3629 ui.status(_('remote: (synced)\n'))
3628
3630
3629 def tag(ui, repo, name1, *names, **opts):
3631 def tag(ui, repo, name1, *names, **opts):
3630 """add one or more tags for the current or given revision
3632 """add one or more tags for the current or given revision
3631
3633
3632 Name a particular revision using <name>.
3634 Name a particular revision using <name>.
3633
3635
3634 Tags are used to name particular revisions of the repository and are
3636 Tags are used to name particular revisions of the repository and are
3635 very useful to compare different revisions, to go back to significant
3637 very useful to compare different revisions, to go back to significant
3636 earlier versions or to mark branch points as releases, etc.
3638 earlier versions or to mark branch points as releases, etc.
3637
3639
3638 If no revision is given, the parent of the working directory is
3640 If no revision is given, the parent of the working directory is
3639 used, or tip if no revision is checked out.
3641 used, or tip if no revision is checked out.
3640
3642
3641 To facilitate version control, distribution, and merging of tags,
3643 To facilitate version control, distribution, and merging of tags,
3642 they are stored as a file named ".hgtags" which is managed
3644 they are stored as a file named ".hgtags" which is managed
3643 similarly to other project files and can be hand-edited if
3645 similarly to other project files and can be hand-edited if
3644 necessary. The file '.hg/localtags' is used for local tags (not
3646 necessary. The file '.hg/localtags' is used for local tags (not
3645 shared among repositories).
3647 shared among repositories).
3646
3648
3647 See :hg:`help dates` for a list of formats valid for -d/--date.
3649 See :hg:`help dates` for a list of formats valid for -d/--date.
3648
3650
3649 Since tag names have priority over branch names during revision
3651 Since tag names have priority over branch names during revision
3650 lookup, using an existing branch name as a tag name is discouraged.
3652 lookup, using an existing branch name as a tag name is discouraged.
3651
3653
3652 Returns 0 on success.
3654 Returns 0 on success.
3653 """
3655 """
3654
3656
3655 rev_ = "."
3657 rev_ = "."
3656 names = [t.strip() for t in (name1,) + names]
3658 names = [t.strip() for t in (name1,) + names]
3657 if len(names) != len(set(names)):
3659 if len(names) != len(set(names)):
3658 raise util.Abort(_('tag names must be unique'))
3660 raise util.Abort(_('tag names must be unique'))
3659 for n in names:
3661 for n in names:
3660 if n in ['tip', '.', 'null']:
3662 if n in ['tip', '.', 'null']:
3661 raise util.Abort(_('the name \'%s\' is reserved') % n)
3663 raise util.Abort(_('the name \'%s\' is reserved') % n)
3662 if not n:
3664 if not n:
3663 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3665 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3664 if opts.get('rev') and opts.get('remove'):
3666 if opts.get('rev') and opts.get('remove'):
3665 raise util.Abort(_("--rev and --remove are incompatible"))
3667 raise util.Abort(_("--rev and --remove are incompatible"))
3666 if opts.get('rev'):
3668 if opts.get('rev'):
3667 rev_ = opts['rev']
3669 rev_ = opts['rev']
3668 message = opts.get('message')
3670 message = opts.get('message')
3669 if opts.get('remove'):
3671 if opts.get('remove'):
3670 expectedtype = opts.get('local') and 'local' or 'global'
3672 expectedtype = opts.get('local') and 'local' or 'global'
3671 for n in names:
3673 for n in names:
3672 if not repo.tagtype(n):
3674 if not repo.tagtype(n):
3673 raise util.Abort(_('tag \'%s\' does not exist') % n)
3675 raise util.Abort(_('tag \'%s\' does not exist') % n)
3674 if repo.tagtype(n) != expectedtype:
3676 if repo.tagtype(n) != expectedtype:
3675 if expectedtype == 'global':
3677 if expectedtype == 'global':
3676 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3678 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3677 else:
3679 else:
3678 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3680 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3679 rev_ = nullid
3681 rev_ = nullid
3680 if not message:
3682 if not message:
3681 # we don't translate commit messages
3683 # we don't translate commit messages
3682 message = 'Removed tag %s' % ', '.join(names)
3684 message = 'Removed tag %s' % ', '.join(names)
3683 elif not opts.get('force'):
3685 elif not opts.get('force'):
3684 for n in names:
3686 for n in names:
3685 if n in repo.tags():
3687 if n in repo.tags():
3686 raise util.Abort(_('tag \'%s\' already exists '
3688 raise util.Abort(_('tag \'%s\' already exists '
3687 '(use -f to force)') % n)
3689 '(use -f to force)') % n)
3688 if not rev_ and repo.dirstate.parents()[1] != nullid:
3690 if not rev_ and repo.dirstate.parents()[1] != nullid:
3689 raise util.Abort(_('uncommitted merge - please provide a '
3691 raise util.Abort(_('uncommitted merge - please provide a '
3690 'specific revision'))
3692 'specific revision'))
3691 r = repo[rev_].node()
3693 r = repo[rev_].node()
3692
3694
3693 if not message:
3695 if not message:
3694 # we don't translate commit messages
3696 # we don't translate commit messages
3695 message = ('Added tag %s for changeset %s' %
3697 message = ('Added tag %s for changeset %s' %
3696 (', '.join(names), short(r)))
3698 (', '.join(names), short(r)))
3697
3699
3698 date = opts.get('date')
3700 date = opts.get('date')
3699 if date:
3701 if date:
3700 date = util.parsedate(date)
3702 date = util.parsedate(date)
3701
3703
3702 if opts.get('edit'):
3704 if opts.get('edit'):
3703 message = ui.edit(message, ui.username())
3705 message = ui.edit(message, ui.username())
3704
3706
3705 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3707 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3706
3708
3707 def tags(ui, repo):
3709 def tags(ui, repo):
3708 """list repository tags
3710 """list repository tags
3709
3711
3710 This lists both regular and local tags. When the -v/--verbose
3712 This lists both regular and local tags. When the -v/--verbose
3711 switch is used, a third column "local" is printed for local tags.
3713 switch is used, a third column "local" is printed for local tags.
3712
3714
3713 Returns 0 on success.
3715 Returns 0 on success.
3714 """
3716 """
3715
3717
3716 hexfunc = ui.debugflag and hex or short
3718 hexfunc = ui.debugflag and hex or short
3717 tagtype = ""
3719 tagtype = ""
3718
3720
3719 for t, n in reversed(repo.tagslist()):
3721 for t, n in reversed(repo.tagslist()):
3720 if ui.quiet:
3722 if ui.quiet:
3721 ui.write("%s\n" % t)
3723 ui.write("%s\n" % t)
3722 continue
3724 continue
3723
3725
3724 try:
3726 try:
3725 hn = hexfunc(n)
3727 hn = hexfunc(n)
3726 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3728 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3727 except error.LookupError:
3729 except error.LookupError:
3728 r = " ?:%s" % hn
3730 r = " ?:%s" % hn
3729 else:
3731 else:
3730 spaces = " " * (30 - encoding.colwidth(t))
3732 spaces = " " * (30 - encoding.colwidth(t))
3731 if ui.verbose:
3733 if ui.verbose:
3732 if repo.tagtype(t) == 'local':
3734 if repo.tagtype(t) == 'local':
3733 tagtype = " local"
3735 tagtype = " local"
3734 else:
3736 else:
3735 tagtype = ""
3737 tagtype = ""
3736 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3738 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3737
3739
3738 def tip(ui, repo, **opts):
3740 def tip(ui, repo, **opts):
3739 """show the tip revision
3741 """show the tip revision
3740
3742
3741 The tip revision (usually just called the tip) is the changeset
3743 The tip revision (usually just called the tip) is the changeset
3742 most recently added to the repository (and therefore the most
3744 most recently added to the repository (and therefore the most
3743 recently changed head).
3745 recently changed head).
3744
3746
3745 If you have just made a commit, that commit will be the tip. If
3747 If you have just made a commit, that commit will be the tip. If
3746 you have just pulled changes from another repository, the tip of
3748 you have just pulled changes from another repository, the tip of
3747 that repository becomes the current tip. The "tip" tag is special
3749 that repository becomes the current tip. The "tip" tag is special
3748 and cannot be renamed or assigned to a different changeset.
3750 and cannot be renamed or assigned to a different changeset.
3749
3751
3750 Returns 0 on success.
3752 Returns 0 on success.
3751 """
3753 """
3752 displayer = cmdutil.show_changeset(ui, repo, opts)
3754 displayer = cmdutil.show_changeset(ui, repo, opts)
3753 displayer.show(repo[len(repo) - 1])
3755 displayer.show(repo[len(repo) - 1])
3754 displayer.close()
3756 displayer.close()
3755
3757
3756 def unbundle(ui, repo, fname1, *fnames, **opts):
3758 def unbundle(ui, repo, fname1, *fnames, **opts):
3757 """apply one or more changegroup files
3759 """apply one or more changegroup files
3758
3760
3759 Apply one or more compressed changegroup files generated by the
3761 Apply one or more compressed changegroup files generated by the
3760 bundle command.
3762 bundle command.
3761
3763
3762 Returns 0 on success, 1 if an update has unresolved files.
3764 Returns 0 on success, 1 if an update has unresolved files.
3763 """
3765 """
3764 fnames = (fname1,) + fnames
3766 fnames = (fname1,) + fnames
3765
3767
3766 lock = repo.lock()
3768 lock = repo.lock()
3767 try:
3769 try:
3768 for fname in fnames:
3770 for fname in fnames:
3769 f = url.open(ui, fname)
3771 f = url.open(ui, fname)
3770 gen = changegroup.readbundle(f, fname)
3772 gen = changegroup.readbundle(f, fname)
3771 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3773 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3772 lock=lock)
3774 lock=lock)
3773 finally:
3775 finally:
3774 lock.release()
3776 lock.release()
3775
3777
3776 return postincoming(ui, repo, modheads, opts.get('update'), None)
3778 return postincoming(ui, repo, modheads, opts.get('update'), None)
3777
3779
3778 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3780 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3779 """update working directory (or switch revisions)
3781 """update working directory (or switch revisions)
3780
3782
3781 Update the repository's working directory to the specified
3783 Update the repository's working directory to the specified
3782 changeset. If no changeset is specified, update to the tip of the
3784 changeset. If no changeset is specified, update to the tip of the
3783 current named branch.
3785 current named branch.
3784
3786
3785 If the changeset is not a descendant of the working directory's
3787 If the changeset is not a descendant of the working directory's
3786 parent, the update is aborted. With the -c/--check option, the
3788 parent, the update is aborted. With the -c/--check option, the
3787 working directory is checked for uncommitted changes; if none are
3789 working directory is checked for uncommitted changes; if none are
3788 found, the working directory is updated to the specified
3790 found, the working directory is updated to the specified
3789 changeset.
3791 changeset.
3790
3792
3791 The following rules apply when the working directory contains
3793 The following rules apply when the working directory contains
3792 uncommitted changes:
3794 uncommitted changes:
3793
3795
3794 1. If neither -c/--check nor -C/--clean is specified, and if
3796 1. If neither -c/--check nor -C/--clean is specified, and if
3795 the requested changeset is an ancestor or descendant of
3797 the requested changeset is an ancestor or descendant of
3796 the working directory's parent, the uncommitted changes
3798 the working directory's parent, the uncommitted changes
3797 are merged into the requested changeset and the merged
3799 are merged into the requested changeset and the merged
3798 result is left uncommitted. If the requested changeset is
3800 result is left uncommitted. If the requested changeset is
3799 not an ancestor or descendant (that is, it is on another
3801 not an ancestor or descendant (that is, it is on another
3800 branch), the update is aborted and the uncommitted changes
3802 branch), the update is aborted and the uncommitted changes
3801 are preserved.
3803 are preserved.
3802
3804
3803 2. With the -c/--check option, the update is aborted and the
3805 2. With the -c/--check option, the update is aborted and the
3804 uncommitted changes are preserved.
3806 uncommitted changes are preserved.
3805
3807
3806 3. With the -C/--clean option, uncommitted changes are discarded and
3808 3. With the -C/--clean option, uncommitted changes are discarded and
3807 the working directory is updated to the requested changeset.
3809 the working directory is updated to the requested changeset.
3808
3810
3809 Use null as the changeset to remove the working directory (like
3811 Use null as the changeset to remove the working directory (like
3810 :hg:`clone -U`).
3812 :hg:`clone -U`).
3811
3813
3812 If you want to update just one file to an older changeset, use
3814 If you want to update just one file to an older changeset, use
3813 :hg:`revert`.
3815 :hg:`revert`.
3814
3816
3815 See :hg:`help dates` for a list of formats valid for -d/--date.
3817 See :hg:`help dates` for a list of formats valid for -d/--date.
3816
3818
3817 Returns 0 on success, 1 if there are unresolved files.
3819 Returns 0 on success, 1 if there are unresolved files.
3818 """
3820 """
3819 if rev and node:
3821 if rev and node:
3820 raise util.Abort(_("please specify just one revision"))
3822 raise util.Abort(_("please specify just one revision"))
3821
3823
3822 if not rev:
3824 if not rev:
3823 rev = node
3825 rev = node
3824
3826
3825 rev = cmdutil.revsingle(repo, rev, rev).rev()
3827 rev = cmdutil.revsingle(repo, rev, rev).rev()
3826
3828
3827 if check and clean:
3829 if check and clean:
3828 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3830 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3829
3831
3830 if check:
3832 if check:
3831 # we could use dirty() but we can ignore merge and branch trivia
3833 # we could use dirty() but we can ignore merge and branch trivia
3832 c = repo[None]
3834 c = repo[None]
3833 if c.modified() or c.added() or c.removed():
3835 if c.modified() or c.added() or c.removed():
3834 raise util.Abort(_("uncommitted local changes"))
3836 raise util.Abort(_("uncommitted local changes"))
3835
3837
3836 if date:
3838 if date:
3837 if rev:
3839 if rev:
3838 raise util.Abort(_("you can't specify a revision and a date"))
3840 raise util.Abort(_("you can't specify a revision and a date"))
3839 rev = cmdutil.finddate(ui, repo, date)
3841 rev = cmdutil.finddate(ui, repo, date)
3840
3842
3841 if clean or check:
3843 if clean or check:
3842 return hg.clean(repo, rev)
3844 return hg.clean(repo, rev)
3843 else:
3845 else:
3844 return hg.update(repo, rev)
3846 return hg.update(repo, rev)
3845
3847
3846 def verify(ui, repo):
3848 def verify(ui, repo):
3847 """verify the integrity of the repository
3849 """verify the integrity of the repository
3848
3850
3849 Verify the integrity of the current repository.
3851 Verify the integrity of the current repository.
3850
3852
3851 This will perform an extensive check of the repository's
3853 This will perform an extensive check of the repository's
3852 integrity, validating the hashes and checksums of each entry in
3854 integrity, validating the hashes and checksums of each entry in
3853 the changelog, manifest, and tracked files, as well as the
3855 the changelog, manifest, and tracked files, as well as the
3854 integrity of their crosslinks and indices.
3856 integrity of their crosslinks and indices.
3855
3857
3856 Returns 0 on success, 1 if errors are encountered.
3858 Returns 0 on success, 1 if errors are encountered.
3857 """
3859 """
3858 return hg.verify(repo)
3860 return hg.verify(repo)
3859
3861
3860 def version_(ui):
3862 def version_(ui):
3861 """output version and copyright information"""
3863 """output version and copyright information"""
3862 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3864 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3863 % util.version())
3865 % util.version())
3864 ui.status(_(
3866 ui.status(_(
3865 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3867 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3866 "This is free software; see the source for copying conditions. "
3868 "This is free software; see the source for copying conditions. "
3867 "There is NO\nwarranty; "
3869 "There is NO\nwarranty; "
3868 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3870 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3869 ))
3871 ))
3870
3872
3871 # Command options and aliases are listed here, alphabetically
3873 # Command options and aliases are listed here, alphabetically
3872
3874
3873 globalopts = [
3875 globalopts = [
3874 ('R', 'repository', '',
3876 ('R', 'repository', '',
3875 _('repository root directory or name of overlay bundle file'),
3877 _('repository root directory or name of overlay bundle file'),
3876 _('REPO')),
3878 _('REPO')),
3877 ('', 'cwd', '',
3879 ('', 'cwd', '',
3878 _('change working directory'), _('DIR')),
3880 _('change working directory'), _('DIR')),
3879 ('y', 'noninteractive', None,
3881 ('y', 'noninteractive', None,
3880 _('do not prompt, assume \'yes\' for any required answers')),
3882 _('do not prompt, assume \'yes\' for any required answers')),
3881 ('q', 'quiet', None, _('suppress output')),
3883 ('q', 'quiet', None, _('suppress output')),
3882 ('v', 'verbose', None, _('enable additional output')),
3884 ('v', 'verbose', None, _('enable additional output')),
3883 ('', 'config', [],
3885 ('', 'config', [],
3884 _('set/override config option (use \'section.name=value\')'),
3886 _('set/override config option (use \'section.name=value\')'),
3885 _('CONFIG')),
3887 _('CONFIG')),
3886 ('', 'debug', None, _('enable debugging output')),
3888 ('', 'debug', None, _('enable debugging output')),
3887 ('', 'debugger', None, _('start debugger')),
3889 ('', 'debugger', None, _('start debugger')),
3888 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3890 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3889 _('ENCODE')),
3891 _('ENCODE')),
3890 ('', 'encodingmode', encoding.encodingmode,
3892 ('', 'encodingmode', encoding.encodingmode,
3891 _('set the charset encoding mode'), _('MODE')),
3893 _('set the charset encoding mode'), _('MODE')),
3892 ('', 'traceback', None, _('always print a traceback on exception')),
3894 ('', 'traceback', None, _('always print a traceback on exception')),
3893 ('', 'time', None, _('time how long the command takes')),
3895 ('', 'time', None, _('time how long the command takes')),
3894 ('', 'profile', None, _('print command execution profile')),
3896 ('', 'profile', None, _('print command execution profile')),
3895 ('', 'version', None, _('output version information and exit')),
3897 ('', 'version', None, _('output version information and exit')),
3896 ('h', 'help', None, _('display help and exit')),
3898 ('h', 'help', None, _('display help and exit')),
3897 ]
3899 ]
3898
3900
3899 dryrunopts = [('n', 'dry-run', None,
3901 dryrunopts = [('n', 'dry-run', None,
3900 _('do not perform actions, just print output'))]
3902 _('do not perform actions, just print output'))]
3901
3903
3902 remoteopts = [
3904 remoteopts = [
3903 ('e', 'ssh', '',
3905 ('e', 'ssh', '',
3904 _('specify ssh command to use'), _('CMD')),
3906 _('specify ssh command to use'), _('CMD')),
3905 ('', 'remotecmd', '',
3907 ('', 'remotecmd', '',
3906 _('specify hg command to run on the remote side'), _('CMD')),
3908 _('specify hg command to run on the remote side'), _('CMD')),
3907 ]
3909 ]
3908
3910
3909 walkopts = [
3911 walkopts = [
3910 ('I', 'include', [],
3912 ('I', 'include', [],
3911 _('include names matching the given patterns'), _('PATTERN')),
3913 _('include names matching the given patterns'), _('PATTERN')),
3912 ('X', 'exclude', [],
3914 ('X', 'exclude', [],
3913 _('exclude names matching the given patterns'), _('PATTERN')),
3915 _('exclude names matching the given patterns'), _('PATTERN')),
3914 ]
3916 ]
3915
3917
3916 commitopts = [
3918 commitopts = [
3917 ('m', 'message', '',
3919 ('m', 'message', '',
3918 _('use text as commit message'), _('TEXT')),
3920 _('use text as commit message'), _('TEXT')),
3919 ('l', 'logfile', '',
3921 ('l', 'logfile', '',
3920 _('read commit message from file'), _('FILE')),
3922 _('read commit message from file'), _('FILE')),
3921 ]
3923 ]
3922
3924
3923 commitopts2 = [
3925 commitopts2 = [
3924 ('d', 'date', '',
3926 ('d', 'date', '',
3925 _('record datecode as commit date'), _('DATE')),
3927 _('record datecode as commit date'), _('DATE')),
3926 ('u', 'user', '',
3928 ('u', 'user', '',
3927 _('record the specified user as committer'), _('USER')),
3929 _('record the specified user as committer'), _('USER')),
3928 ]
3930 ]
3929
3931
3930 templateopts = [
3932 templateopts = [
3931 ('', 'style', '',
3933 ('', 'style', '',
3932 _('display using template map file'), _('STYLE')),
3934 _('display using template map file'), _('STYLE')),
3933 ('', 'template', '',
3935 ('', 'template', '',
3934 _('display with template'), _('TEMPLATE')),
3936 _('display with template'), _('TEMPLATE')),
3935 ]
3937 ]
3936
3938
3937 logopts = [
3939 logopts = [
3938 ('p', 'patch', None, _('show patch')),
3940 ('p', 'patch', None, _('show patch')),
3939 ('g', 'git', None, _('use git extended diff format')),
3941 ('g', 'git', None, _('use git extended diff format')),
3940 ('l', 'limit', '',
3942 ('l', 'limit', '',
3941 _('limit number of changes displayed'), _('NUM')),
3943 _('limit number of changes displayed'), _('NUM')),
3942 ('M', 'no-merges', None, _('do not show merges')),
3944 ('M', 'no-merges', None, _('do not show merges')),
3943 ('', 'stat', None, _('output diffstat-style summary of changes')),
3945 ('', 'stat', None, _('output diffstat-style summary of changes')),
3944 ] + templateopts
3946 ] + templateopts
3945
3947
3946 diffopts = [
3948 diffopts = [
3947 ('a', 'text', None, _('treat all files as text')),
3949 ('a', 'text', None, _('treat all files as text')),
3948 ('g', 'git', None, _('use git extended diff format')),
3950 ('g', 'git', None, _('use git extended diff format')),
3949 ('', 'nodates', None, _('omit dates from diff headers'))
3951 ('', 'nodates', None, _('omit dates from diff headers'))
3950 ]
3952 ]
3951
3953
3952 diffopts2 = [
3954 diffopts2 = [
3953 ('p', 'show-function', None, _('show which function each change is in')),
3955 ('p', 'show-function', None, _('show which function each change is in')),
3954 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3956 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3955 ('w', 'ignore-all-space', None,
3957 ('w', 'ignore-all-space', None,
3956 _('ignore white space when comparing lines')),
3958 _('ignore white space when comparing lines')),
3957 ('b', 'ignore-space-change', None,
3959 ('b', 'ignore-space-change', None,
3958 _('ignore changes in the amount of white space')),
3960 _('ignore changes in the amount of white space')),
3959 ('B', 'ignore-blank-lines', None,
3961 ('B', 'ignore-blank-lines', None,
3960 _('ignore changes whose lines are all blank')),
3962 _('ignore changes whose lines are all blank')),
3961 ('U', 'unified', '',
3963 ('U', 'unified', '',
3962 _('number of lines of context to show'), _('NUM')),
3964 _('number of lines of context to show'), _('NUM')),
3963 ('', 'stat', None, _('output diffstat-style summary of changes')),
3965 ('', 'stat', None, _('output diffstat-style summary of changes')),
3964 ]
3966 ]
3965
3967
3966 similarityopts = [
3968 similarityopts = [
3967 ('s', 'similarity', '',
3969 ('s', 'similarity', '',
3968 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3970 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3969 ]
3971 ]
3970
3972
3971 subrepoopts = [
3973 subrepoopts = [
3972 ('S', 'subrepos', None,
3974 ('S', 'subrepos', None,
3973 _('recurse into subrepositories'))
3975 _('recurse into subrepositories'))
3974 ]
3976 ]
3975
3977
3976 table = {
3978 table = {
3977 "^add": (add, walkopts + subrepoopts + dryrunopts,
3979 "^add": (add, walkopts + subrepoopts + dryrunopts,
3978 _('[OPTION]... [FILE]...')),
3980 _('[OPTION]... [FILE]...')),
3979 "addremove":
3981 "addremove":
3980 (addremove, similarityopts + walkopts + dryrunopts,
3982 (addremove, similarityopts + walkopts + dryrunopts,
3981 _('[OPTION]... [FILE]...')),
3983 _('[OPTION]... [FILE]...')),
3982 "^annotate|blame":
3984 "^annotate|blame":
3983 (annotate,
3985 (annotate,
3984 [('r', 'rev', '',
3986 [('r', 'rev', '',
3985 _('annotate the specified revision'), _('REV')),
3987 _('annotate the specified revision'), _('REV')),
3986 ('', 'follow', None,
3988 ('', 'follow', None,
3987 _('follow copies/renames and list the filename (DEPRECATED)')),
3989 _('follow copies/renames and list the filename (DEPRECATED)')),
3988 ('', 'no-follow', None, _("don't follow copies and renames")),
3990 ('', 'no-follow', None, _("don't follow copies and renames")),
3989 ('a', 'text', None, _('treat all files as text')),
3991 ('a', 'text', None, _('treat all files as text')),
3990 ('u', 'user', None, _('list the author (long with -v)')),
3992 ('u', 'user', None, _('list the author (long with -v)')),
3991 ('f', 'file', None, _('list the filename')),
3993 ('f', 'file', None, _('list the filename')),
3992 ('d', 'date', None, _('list the date (short with -q)')),
3994 ('d', 'date', None, _('list the date (short with -q)')),
3993 ('n', 'number', None, _('list the revision number (default)')),
3995 ('n', 'number', None, _('list the revision number (default)')),
3994 ('c', 'changeset', None, _('list the changeset')),
3996 ('c', 'changeset', None, _('list the changeset')),
3995 ('l', 'line-number', None,
3997 ('l', 'line-number', None,
3996 _('show line number at the first appearance'))
3998 _('show line number at the first appearance'))
3997 ] + walkopts,
3999 ] + walkopts,
3998 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4000 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3999 "archive":
4001 "archive":
4000 (archive,
4002 (archive,
4001 [('', 'no-decode', None, _('do not pass files through decoders')),
4003 [('', 'no-decode', None, _('do not pass files through decoders')),
4002 ('p', 'prefix', '',
4004 ('p', 'prefix', '',
4003 _('directory prefix for files in archive'), _('PREFIX')),
4005 _('directory prefix for files in archive'), _('PREFIX')),
4004 ('r', 'rev', '',
4006 ('r', 'rev', '',
4005 _('revision to distribute'), _('REV')),
4007 _('revision to distribute'), _('REV')),
4006 ('t', 'type', '',
4008 ('t', 'type', '',
4007 _('type of distribution to create'), _('TYPE')),
4009 _('type of distribution to create'), _('TYPE')),
4008 ] + subrepoopts + walkopts,
4010 ] + subrepoopts + walkopts,
4009 _('[OPTION]... DEST')),
4011 _('[OPTION]... DEST')),
4010 "backout":
4012 "backout":
4011 (backout,
4013 (backout,
4012 [('', 'merge', None,
4014 [('', 'merge', None,
4013 _('merge with old dirstate parent after backout')),
4015 _('merge with old dirstate parent after backout')),
4014 ('', 'parent', '',
4016 ('', 'parent', '',
4015 _('parent to choose when backing out merge'), _('REV')),
4017 _('parent to choose when backing out merge'), _('REV')),
4016 ('t', 'tool', '',
4018 ('t', 'tool', '',
4017 _('specify merge tool')),
4019 _('specify merge tool')),
4018 ('r', 'rev', '',
4020 ('r', 'rev', '',
4019 _('revision to backout'), _('REV')),
4021 _('revision to backout'), _('REV')),
4020 ] + walkopts + commitopts + commitopts2,
4022 ] + walkopts + commitopts + commitopts2,
4021 _('[OPTION]... [-r] REV')),
4023 _('[OPTION]... [-r] REV')),
4022 "bisect":
4024 "bisect":
4023 (bisect,
4025 (bisect,
4024 [('r', 'reset', False, _('reset bisect state')),
4026 [('r', 'reset', False, _('reset bisect state')),
4025 ('g', 'good', False, _('mark changeset good')),
4027 ('g', 'good', False, _('mark changeset good')),
4026 ('b', 'bad', False, _('mark changeset bad')),
4028 ('b', 'bad', False, _('mark changeset bad')),
4027 ('s', 'skip', False, _('skip testing changeset')),
4029 ('s', 'skip', False, _('skip testing changeset')),
4028 ('c', 'command', '',
4030 ('c', 'command', '',
4029 _('use command to check changeset state'), _('CMD')),
4031 _('use command to check changeset state'), _('CMD')),
4030 ('U', 'noupdate', False, _('do not update to target'))],
4032 ('U', 'noupdate', False, _('do not update to target'))],
4031 _("[-gbsr] [-U] [-c CMD] [REV]")),
4033 _("[-gbsr] [-U] [-c CMD] [REV]")),
4032 "branch":
4034 "branch":
4033 (branch,
4035 (branch,
4034 [('f', 'force', None,
4036 [('f', 'force', None,
4035 _('set branch name even if it shadows an existing branch')),
4037 _('set branch name even if it shadows an existing branch')),
4036 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4038 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4037 _('[-fC] [NAME]')),
4039 _('[-fC] [NAME]')),
4038 "branches":
4040 "branches":
4039 (branches,
4041 (branches,
4040 [('a', 'active', False,
4042 [('a', 'active', False,
4041 _('show only branches that have unmerged heads')),
4043 _('show only branches that have unmerged heads')),
4042 ('c', 'closed', False,
4044 ('c', 'closed', False,
4043 _('show normal and closed branches'))],
4045 _('show normal and closed branches'))],
4044 _('[-ac]')),
4046 _('[-ac]')),
4045 "bundle":
4047 "bundle":
4046 (bundle,
4048 (bundle,
4047 [('f', 'force', None,
4049 [('f', 'force', None,
4048 _('run even when the destination is unrelated')),
4050 _('run even when the destination is unrelated')),
4049 ('r', 'rev', [],
4051 ('r', 'rev', [],
4050 _('a changeset intended to be added to the destination'),
4052 _('a changeset intended to be added to the destination'),
4051 _('REV')),
4053 _('REV')),
4052 ('b', 'branch', [],
4054 ('b', 'branch', [],
4053 _('a specific branch you would like to bundle'),
4055 _('a specific branch you would like to bundle'),
4054 _('BRANCH')),
4056 _('BRANCH')),
4055 ('', 'base', [],
4057 ('', 'base', [],
4056 _('a base changeset assumed to be available at the destination'),
4058 _('a base changeset assumed to be available at the destination'),
4057 _('REV')),
4059 _('REV')),
4058 ('a', 'all', None, _('bundle all changesets in the repository')),
4060 ('a', 'all', None, _('bundle all changesets in the repository')),
4059 ('t', 'type', 'bzip2',
4061 ('t', 'type', 'bzip2',
4060 _('bundle compression type to use'), _('TYPE')),
4062 _('bundle compression type to use'), _('TYPE')),
4061 ] + remoteopts,
4063 ] + remoteopts,
4062 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4064 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4063 "cat":
4065 "cat":
4064 (cat,
4066 (cat,
4065 [('o', 'output', '',
4067 [('o', 'output', '',
4066 _('print output to file with formatted name'), _('FORMAT')),
4068 _('print output to file with formatted name'), _('FORMAT')),
4067 ('r', 'rev', '',
4069 ('r', 'rev', '',
4068 _('print the given revision'), _('REV')),
4070 _('print the given revision'), _('REV')),
4069 ('', 'decode', None, _('apply any matching decode filter')),
4071 ('', 'decode', None, _('apply any matching decode filter')),
4070 ] + walkopts,
4072 ] + walkopts,
4071 _('[OPTION]... FILE...')),
4073 _('[OPTION]... FILE...')),
4072 "^clone":
4074 "^clone":
4073 (clone,
4075 (clone,
4074 [('U', 'noupdate', None,
4076 [('U', 'noupdate', None,
4075 _('the clone will include an empty working copy (only a repository)')),
4077 _('the clone will include an empty working copy (only a repository)')),
4076 ('u', 'updaterev', '',
4078 ('u', 'updaterev', '',
4077 _('revision, tag or branch to check out'), _('REV')),
4079 _('revision, tag or branch to check out'), _('REV')),
4078 ('r', 'rev', [],
4080 ('r', 'rev', [],
4079 _('include the specified changeset'), _('REV')),
4081 _('include the specified changeset'), _('REV')),
4080 ('b', 'branch', [],
4082 ('b', 'branch', [],
4081 _('clone only the specified branch'), _('BRANCH')),
4083 _('clone only the specified branch'), _('BRANCH')),
4082 ('', 'pull', None, _('use pull protocol to copy metadata')),
4084 ('', 'pull', None, _('use pull protocol to copy metadata')),
4083 ('', 'uncompressed', None,
4085 ('', 'uncompressed', None,
4084 _('use uncompressed transfer (fast over LAN)')),
4086 _('use uncompressed transfer (fast over LAN)')),
4085 ] + remoteopts,
4087 ] + remoteopts,
4086 _('[OPTION]... SOURCE [DEST]')),
4088 _('[OPTION]... SOURCE [DEST]')),
4087 "^commit|ci":
4089 "^commit|ci":
4088 (commit,
4090 (commit,
4089 [('A', 'addremove', None,
4091 [('A', 'addremove', None,
4090 _('mark new/missing files as added/removed before committing')),
4092 _('mark new/missing files as added/removed before committing')),
4091 ('', 'close-branch', None,
4093 ('', 'close-branch', None,
4092 _('mark a branch as closed, hiding it from the branch list')),
4094 _('mark a branch as closed, hiding it from the branch list')),
4093 ] + walkopts + commitopts + commitopts2,
4095 ] + walkopts + commitopts + commitopts2,
4094 _('[OPTION]... [FILE]...')),
4096 _('[OPTION]... [FILE]...')),
4095 "copy|cp":
4097 "copy|cp":
4096 (copy,
4098 (copy,
4097 [('A', 'after', None, _('record a copy that has already occurred')),
4099 [('A', 'after', None, _('record a copy that has already occurred')),
4098 ('f', 'force', None,
4100 ('f', 'force', None,
4099 _('forcibly copy over an existing managed file')),
4101 _('forcibly copy over an existing managed file')),
4100 ] + walkopts + dryrunopts,
4102 ] + walkopts + dryrunopts,
4101 _('[OPTION]... [SOURCE]... DEST')),
4103 _('[OPTION]... [SOURCE]... DEST')),
4102 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4104 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4103 "debugbuilddag":
4105 "debugbuilddag":
4104 (debugbuilddag,
4106 (debugbuilddag,
4105 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4107 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4106 ('a', 'appended-file', None, _('add single file all revs append to')),
4108 ('a', 'appended-file', None, _('add single file all revs append to')),
4107 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4109 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4108 ('n', 'new-file', None, _('add new file at each rev')),
4110 ('n', 'new-file', None, _('add new file at each rev')),
4109 ],
4111 ],
4110 _('[OPTION]... TEXT')),
4112 _('[OPTION]... TEXT')),
4111 "debugcheckstate": (debugcheckstate, [], ''),
4113 "debugcheckstate": (debugcheckstate, [], ''),
4112 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4114 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4113 "debugcomplete":
4115 "debugcomplete":
4114 (debugcomplete,
4116 (debugcomplete,
4115 [('o', 'options', None, _('show the command options'))],
4117 [('o', 'options', None, _('show the command options'))],
4116 _('[-o] CMD')),
4118 _('[-o] CMD')),
4117 "debugdag":
4119 "debugdag":
4118 (debugdag,
4120 (debugdag,
4119 [('t', 'tags', None, _('use tags as labels')),
4121 [('t', 'tags', None, _('use tags as labels')),
4120 ('b', 'branches', None, _('annotate with branch names')),
4122 ('b', 'branches', None, _('annotate with branch names')),
4121 ('', 'dots', None, _('use dots for runs')),
4123 ('', 'dots', None, _('use dots for runs')),
4122 ('s', 'spaces', None, _('separate elements by spaces')),
4124 ('s', 'spaces', None, _('separate elements by spaces')),
4123 ],
4125 ],
4124 _('[OPTION]... [FILE [REV]...]')),
4126 _('[OPTION]... [FILE [REV]...]')),
4125 "debugdate":
4127 "debugdate":
4126 (debugdate,
4128 (debugdate,
4127 [('e', 'extended', None, _('try extended date formats'))],
4129 [('e', 'extended', None, _('try extended date formats'))],
4128 _('[-e] DATE [RANGE]')),
4130 _('[-e] DATE [RANGE]')),
4129 "debugdata": (debugdata, [], _('FILE REV')),
4131 "debugdata": (debugdata, [], _('FILE REV')),
4130 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4132 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4131 "debugindex": (debugindex, [], _('FILE')),
4133 "debugindex": (debugindex, [], _('FILE')),
4132 "debugindexdot": (debugindexdot, [], _('FILE')),
4134 "debugindexdot": (debugindexdot, [], _('FILE')),
4133 "debuginstall": (debuginstall, [], ''),
4135 "debuginstall": (debuginstall, [], ''),
4134 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4136 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4135 "debugrebuildstate":
4137 "debugrebuildstate":
4136 (debugrebuildstate,
4138 (debugrebuildstate,
4137 [('r', 'rev', '',
4139 [('r', 'rev', '',
4138 _('revision to rebuild to'), _('REV'))],
4140 _('revision to rebuild to'), _('REV'))],
4139 _('[-r REV] [REV]')),
4141 _('[-r REV] [REV]')),
4140 "debugrename":
4142 "debugrename":
4141 (debugrename,
4143 (debugrename,
4142 [('r', 'rev', '',
4144 [('r', 'rev', '',
4143 _('revision to debug'), _('REV'))],
4145 _('revision to debug'), _('REV'))],
4144 _('[-r REV] FILE')),
4146 _('[-r REV] FILE')),
4145 "debugrevspec":
4147 "debugrevspec":
4146 (debugrevspec, [], ('REVSPEC')),
4148 (debugrevspec, [], ('REVSPEC')),
4147 "debugsetparents":
4149 "debugsetparents":
4148 (debugsetparents, [], _('REV1 [REV2]')),
4150 (debugsetparents, [], _('REV1 [REV2]')),
4149 "debugstate":
4151 "debugstate":
4150 (debugstate,
4152 (debugstate,
4151 [('', 'nodates', None, _('do not display the saved mtime'))],
4153 [('', 'nodates', None, _('do not display the saved mtime'))],
4152 _('[OPTION]...')),
4154 _('[OPTION]...')),
4153 "debugsub":
4155 "debugsub":
4154 (debugsub,
4156 (debugsub,
4155 [('r', 'rev', '',
4157 [('r', 'rev', '',
4156 _('revision to check'), _('REV'))],
4158 _('revision to check'), _('REV'))],
4157 _('[-r REV] [REV]')),
4159 _('[-r REV] [REV]')),
4158 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4160 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4159 "^diff":
4161 "^diff":
4160 (diff,
4162 (diff,
4161 [('r', 'rev', [],
4163 [('r', 'rev', [],
4162 _('revision'), _('REV')),
4164 _('revision'), _('REV')),
4163 ('c', 'change', '',
4165 ('c', 'change', '',
4164 _('change made by revision'), _('REV'))
4166 _('change made by revision'), _('REV'))
4165 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4167 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4166 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4168 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4167 "^export":
4169 "^export":
4168 (export,
4170 (export,
4169 [('o', 'output', '',
4171 [('o', 'output', '',
4170 _('print output to file with formatted name'), _('FORMAT')),
4172 _('print output to file with formatted name'), _('FORMAT')),
4171 ('', 'switch-parent', None, _('diff against the second parent')),
4173 ('', 'switch-parent', None, _('diff against the second parent')),
4172 ('r', 'rev', [],
4174 ('r', 'rev', [],
4173 _('revisions to export'), _('REV')),
4175 _('revisions to export'), _('REV')),
4174 ] + diffopts,
4176 ] + diffopts,
4175 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4177 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4176 "^forget":
4178 "^forget":
4177 (forget,
4179 (forget,
4178 [] + walkopts,
4180 [] + walkopts,
4179 _('[OPTION]... FILE...')),
4181 _('[OPTION]... FILE...')),
4180 "grep":
4182 "grep":
4181 (grep,
4183 (grep,
4182 [('0', 'print0', None, _('end fields with NUL')),
4184 [('0', 'print0', None, _('end fields with NUL')),
4183 ('', 'all', None, _('print all revisions that match')),
4185 ('', 'all', None, _('print all revisions that match')),
4184 ('f', 'follow', None,
4186 ('f', 'follow', None,
4185 _('follow changeset history,'
4187 _('follow changeset history,'
4186 ' or file history across copies and renames')),
4188 ' or file history across copies and renames')),
4187 ('i', 'ignore-case', None, _('ignore case when matching')),
4189 ('i', 'ignore-case', None, _('ignore case when matching')),
4188 ('l', 'files-with-matches', None,
4190 ('l', 'files-with-matches', None,
4189 _('print only filenames and revisions that match')),
4191 _('print only filenames and revisions that match')),
4190 ('n', 'line-number', None, _('print matching line numbers')),
4192 ('n', 'line-number', None, _('print matching line numbers')),
4191 ('r', 'rev', [],
4193 ('r', 'rev', [],
4192 _('only search files changed within revision range'), _('REV')),
4194 _('only search files changed within revision range'), _('REV')),
4193 ('u', 'user', None, _('list the author (long with -v)')),
4195 ('u', 'user', None, _('list the author (long with -v)')),
4194 ('d', 'date', None, _('list the date (short with -q)')),
4196 ('d', 'date', None, _('list the date (short with -q)')),
4195 ] + walkopts,
4197 ] + walkopts,
4196 _('[OPTION]... PATTERN [FILE]...')),
4198 _('[OPTION]... PATTERN [FILE]...')),
4197 "heads":
4199 "heads":
4198 (heads,
4200 (heads,
4199 [('r', 'rev', '',
4201 [('r', 'rev', '',
4200 _('show only heads which are descendants of STARTREV'),
4202 _('show only heads which are descendants of STARTREV'),
4201 _('STARTREV')),
4203 _('STARTREV')),
4202 ('t', 'topo', False, _('show topological heads only')),
4204 ('t', 'topo', False, _('show topological heads only')),
4203 ('a', 'active', False,
4205 ('a', 'active', False,
4204 _('show active branchheads only (DEPRECATED)')),
4206 _('show active branchheads only (DEPRECATED)')),
4205 ('c', 'closed', False,
4207 ('c', 'closed', False,
4206 _('show normal and closed branch heads')),
4208 _('show normal and closed branch heads')),
4207 ] + templateopts,
4209 ] + templateopts,
4208 _('[-ac] [-r STARTREV] [REV]...')),
4210 _('[-ac] [-r STARTREV] [REV]...')),
4209 "help": (help_, [], _('[TOPIC]')),
4211 "help": (help_, [], _('[TOPIC]')),
4210 "identify|id":
4212 "identify|id":
4211 (identify,
4213 (identify,
4212 [('r', 'rev', '',
4214 [('r', 'rev', '',
4213 _('identify the specified revision'), _('REV')),
4215 _('identify the specified revision'), _('REV')),
4214 ('n', 'num', None, _('show local revision number')),
4216 ('n', 'num', None, _('show local revision number')),
4215 ('i', 'id', None, _('show global revision id')),
4217 ('i', 'id', None, _('show global revision id')),
4216 ('b', 'branch', None, _('show branch')),
4218 ('b', 'branch', None, _('show branch')),
4217 ('t', 'tags', None, _('show tags'))],
4219 ('t', 'tags', None, _('show tags'))],
4218 _('[-nibt] [-r REV] [SOURCE]')),
4220 _('[-nibt] [-r REV] [SOURCE]')),
4219 "import|patch":
4221 "import|patch":
4220 (import_,
4222 (import_,
4221 [('p', 'strip', 1,
4223 [('p', 'strip', 1,
4222 _('directory strip option for patch. This has the same '
4224 _('directory strip option for patch. This has the same '
4223 'meaning as the corresponding patch option'),
4225 'meaning as the corresponding patch option'),
4224 _('NUM')),
4226 _('NUM')),
4225 ('b', 'base', '',
4227 ('b', 'base', '',
4226 _('base path'), _('PATH')),
4228 _('base path'), _('PATH')),
4227 ('f', 'force', None,
4229 ('f', 'force', None,
4228 _('skip check for outstanding uncommitted changes')),
4230 _('skip check for outstanding uncommitted changes')),
4229 ('', 'no-commit', None,
4231 ('', 'no-commit', None,
4230 _("don't commit, just update the working directory")),
4232 _("don't commit, just update the working directory")),
4231 ('', 'exact', None,
4233 ('', 'exact', None,
4232 _('apply patch to the nodes from which it was generated')),
4234 _('apply patch to the nodes from which it was generated')),
4233 ('', 'import-branch', None,
4235 ('', 'import-branch', None,
4234 _('use any branch information in patch (implied by --exact)'))] +
4236 _('use any branch information in patch (implied by --exact)'))] +
4235 commitopts + commitopts2 + similarityopts,
4237 commitopts + commitopts2 + similarityopts,
4236 _('[OPTION]... PATCH...')),
4238 _('[OPTION]... PATCH...')),
4237 "incoming|in":
4239 "incoming|in":
4238 (incoming,
4240 (incoming,
4239 [('f', 'force', None,
4241 [('f', 'force', None,
4240 _('run even if remote repository is unrelated')),
4242 _('run even if remote repository is unrelated')),
4241 ('n', 'newest-first', None, _('show newest record first')),
4243 ('n', 'newest-first', None, _('show newest record first')),
4242 ('', 'bundle', '',
4244 ('', 'bundle', '',
4243 _('file to store the bundles into'), _('FILE')),
4245 _('file to store the bundles into'), _('FILE')),
4244 ('r', 'rev', [],
4246 ('r', 'rev', [],
4245 _('a remote changeset intended to be added'), _('REV')),
4247 _('a remote changeset intended to be added'), _('REV')),
4246 ('b', 'branch', [],
4248 ('b', 'branch', [],
4247 _('a specific branch you would like to pull'), _('BRANCH')),
4249 _('a specific branch you would like to pull'), _('BRANCH')),
4248 ] + logopts + remoteopts + subrepoopts,
4250 ] + logopts + remoteopts + subrepoopts,
4249 _('[-p] [-n] [-M] [-f] [-r REV]...'
4251 _('[-p] [-n] [-M] [-f] [-r REV]...'
4250 ' [--bundle FILENAME] [SOURCE]')),
4252 ' [--bundle FILENAME] [SOURCE]')),
4251 "^init":
4253 "^init":
4252 (init,
4254 (init,
4253 remoteopts,
4255 remoteopts,
4254 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4256 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4255 "locate":
4257 "locate":
4256 (locate,
4258 (locate,
4257 [('r', 'rev', '',
4259 [('r', 'rev', '',
4258 _('search the repository as it is in REV'), _('REV')),
4260 _('search the repository as it is in REV'), _('REV')),
4259 ('0', 'print0', None,
4261 ('0', 'print0', None,
4260 _('end filenames with NUL, for use with xargs')),
4262 _('end filenames with NUL, for use with xargs')),
4261 ('f', 'fullpath', None,
4263 ('f', 'fullpath', None,
4262 _('print complete paths from the filesystem root')),
4264 _('print complete paths from the filesystem root')),
4263 ] + walkopts,
4265 ] + walkopts,
4264 _('[OPTION]... [PATTERN]...')),
4266 _('[OPTION]... [PATTERN]...')),
4265 "^log|history":
4267 "^log|history":
4266 (log,
4268 (log,
4267 [('f', 'follow', None,
4269 [('f', 'follow', None,
4268 _('follow changeset history,'
4270 _('follow changeset history,'
4269 ' or file history across copies and renames')),
4271 ' or file history across copies and renames')),
4270 ('', 'follow-first', None,
4272 ('', 'follow-first', None,
4271 _('only follow the first parent of merge changesets')),
4273 _('only follow the first parent of merge changesets')),
4272 ('d', 'date', '',
4274 ('d', 'date', '',
4273 _('show revisions matching date spec'), _('DATE')),
4275 _('show revisions matching date spec'), _('DATE')),
4274 ('C', 'copies', None, _('show copied files')),
4276 ('C', 'copies', None, _('show copied files')),
4275 ('k', 'keyword', [],
4277 ('k', 'keyword', [],
4276 _('do case-insensitive search for a given text'), _('TEXT')),
4278 _('do case-insensitive search for a given text'), _('TEXT')),
4277 ('r', 'rev', [],
4279 ('r', 'rev', [],
4278 _('show the specified revision or range'), _('REV')),
4280 _('show the specified revision or range'), _('REV')),
4279 ('', 'removed', None, _('include revisions where files were removed')),
4281 ('', 'removed', None, _('include revisions where files were removed')),
4280 ('m', 'only-merges', None, _('show only merges')),
4282 ('m', 'only-merges', None, _('show only merges')),
4281 ('u', 'user', [],
4283 ('u', 'user', [],
4282 _('revisions committed by user'), _('USER')),
4284 _('revisions committed by user'), _('USER')),
4283 ('', 'only-branch', [],
4285 ('', 'only-branch', [],
4284 _('show only changesets within the given named branch (DEPRECATED)'),
4286 _('show only changesets within the given named branch (DEPRECATED)'),
4285 _('BRANCH')),
4287 _('BRANCH')),
4286 ('b', 'branch', [],
4288 ('b', 'branch', [],
4287 _('show changesets within the given named branch'), _('BRANCH')),
4289 _('show changesets within the given named branch'), _('BRANCH')),
4288 ('P', 'prune', [],
4290 ('P', 'prune', [],
4289 _('do not display revision or any of its ancestors'), _('REV')),
4291 _('do not display revision or any of its ancestors'), _('REV')),
4290 ] + logopts + walkopts,
4292 ] + logopts + walkopts,
4291 _('[OPTION]... [FILE]')),
4293 _('[OPTION]... [FILE]')),
4292 "manifest":
4294 "manifest":
4293 (manifest,
4295 (manifest,
4294 [('r', 'rev', '',
4296 [('r', 'rev', '',
4295 _('revision to display'), _('REV'))],
4297 _('revision to display'), _('REV'))],
4296 _('[-r REV]')),
4298 _('[-r REV]')),
4297 "^merge":
4299 "^merge":
4298 (merge,
4300 (merge,
4299 [('f', 'force', None, _('force a merge with outstanding changes')),
4301 [('f', 'force', None, _('force a merge with outstanding changes')),
4300 ('t', 'tool', '', _('specify merge tool')),
4302 ('t', 'tool', '', _('specify merge tool')),
4301 ('r', 'rev', '',
4303 ('r', 'rev', '',
4302 _('revision to merge'), _('REV')),
4304 _('revision to merge'), _('REV')),
4303 ('P', 'preview', None,
4305 ('P', 'preview', None,
4304 _('review revisions to merge (no merge is performed)'))],
4306 _('review revisions to merge (no merge is performed)'))],
4305 _('[-P] [-f] [[-r] REV]')),
4307 _('[-P] [-f] [[-r] REV]')),
4306 "outgoing|out":
4308 "outgoing|out":
4307 (outgoing,
4309 (outgoing,
4308 [('f', 'force', None,
4310 [('f', 'force', None,
4309 _('run even when the destination is unrelated')),
4311 _('run even when the destination is unrelated')),
4310 ('r', 'rev', [],
4312 ('r', 'rev', [],
4311 _('a changeset intended to be included in the destination'),
4313 _('a changeset intended to be included in the destination'),
4312 _('REV')),
4314 _('REV')),
4313 ('n', 'newest-first', None, _('show newest record first')),
4315 ('n', 'newest-first', None, _('show newest record first')),
4314 ('b', 'branch', [],
4316 ('b', 'branch', [],
4315 _('a specific branch you would like to push'), _('BRANCH')),
4317 _('a specific branch you would like to push'), _('BRANCH')),
4316 ] + logopts + remoteopts + subrepoopts,
4318 ] + logopts + remoteopts + subrepoopts,
4317 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4319 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4318 "parents":
4320 "parents":
4319 (parents,
4321 (parents,
4320 [('r', 'rev', '',
4322 [('r', 'rev', '',
4321 _('show parents of the specified revision'), _('REV')),
4323 _('show parents of the specified revision'), _('REV')),
4322 ] + templateopts,
4324 ] + templateopts,
4323 _('[-r REV] [FILE]')),
4325 _('[-r REV] [FILE]')),
4324 "paths": (paths, [], _('[NAME]')),
4326 "paths": (paths, [], _('[NAME]')),
4325 "^pull":
4327 "^pull":
4326 (pull,
4328 (pull,
4327 [('u', 'update', None,
4329 [('u', 'update', None,
4328 _('update to new branch head if changesets were pulled')),
4330 _('update to new branch head if changesets were pulled')),
4329 ('f', 'force', None,
4331 ('f', 'force', None,
4330 _('run even when remote repository is unrelated')),
4332 _('run even when remote repository is unrelated')),
4331 ('r', 'rev', [],
4333 ('r', 'rev', [],
4332 _('a remote changeset intended to be added'), _('REV')),
4334 _('a remote changeset intended to be added'), _('REV')),
4333 ('b', 'branch', [],
4335 ('b', 'branch', [],
4334 _('a specific branch you would like to pull'), _('BRANCH')),
4336 _('a specific branch you would like to pull'), _('BRANCH')),
4335 ] + remoteopts,
4337 ] + remoteopts,
4336 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4338 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4337 "^push":
4339 "^push":
4338 (push,
4340 (push,
4339 [('f', 'force', None, _('force push')),
4341 [('f', 'force', None, _('force push')),
4340 ('r', 'rev', [],
4342 ('r', 'rev', [],
4341 _('a changeset intended to be included in the destination'),
4343 _('a changeset intended to be included in the destination'),
4342 _('REV')),
4344 _('REV')),
4343 ('b', 'branch', [],
4345 ('b', 'branch', [],
4344 _('a specific branch you would like to push'), _('BRANCH')),
4346 _('a specific branch you would like to push'), _('BRANCH')),
4345 ('', 'new-branch', False, _('allow pushing a new branch')),
4347 ('', 'new-branch', False, _('allow pushing a new branch')),
4346 ] + remoteopts,
4348 ] + remoteopts,
4347 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4349 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4348 "recover": (recover, []),
4350 "recover": (recover, []),
4349 "^remove|rm":
4351 "^remove|rm":
4350 (remove,
4352 (remove,
4351 [('A', 'after', None, _('record delete for missing files')),
4353 [('A', 'after', None, _('record delete for missing files')),
4352 ('f', 'force', None,
4354 ('f', 'force', None,
4353 _('remove (and delete) file even if added or modified')),
4355 _('remove (and delete) file even if added or modified')),
4354 ] + walkopts,
4356 ] + walkopts,
4355 _('[OPTION]... FILE...')),
4357 _('[OPTION]... FILE...')),
4356 "rename|move|mv":
4358 "rename|move|mv":
4357 (rename,
4359 (rename,
4358 [('A', 'after', None, _('record a rename that has already occurred')),
4360 [('A', 'after', None, _('record a rename that has already occurred')),
4359 ('f', 'force', None,
4361 ('f', 'force', None,
4360 _('forcibly copy over an existing managed file')),
4362 _('forcibly copy over an existing managed file')),
4361 ] + walkopts + dryrunopts,
4363 ] + walkopts + dryrunopts,
4362 _('[OPTION]... SOURCE... DEST')),
4364 _('[OPTION]... SOURCE... DEST')),
4363 "resolve":
4365 "resolve":
4364 (resolve,
4366 (resolve,
4365 [('a', 'all', None, _('select all unresolved files')),
4367 [('a', 'all', None, _('select all unresolved files')),
4366 ('l', 'list', None, _('list state of files needing merge')),
4368 ('l', 'list', None, _('list state of files needing merge')),
4367 ('m', 'mark', None, _('mark files as resolved')),
4369 ('m', 'mark', None, _('mark files as resolved')),
4368 ('u', 'unmark', None, _('mark files as unresolved')),
4370 ('u', 'unmark', None, _('mark files as unresolved')),
4369 ('t', 'tool', '', _('specify merge tool')),
4371 ('t', 'tool', '', _('specify merge tool')),
4370 ('n', 'no-status', None, _('hide status prefix'))]
4372 ('n', 'no-status', None, _('hide status prefix'))]
4371 + walkopts,
4373 + walkopts,
4372 _('[OPTION]... [FILE]...')),
4374 _('[OPTION]... [FILE]...')),
4373 "revert":
4375 "revert":
4374 (revert,
4376 (revert,
4375 [('a', 'all', None, _('revert all changes when no arguments given')),
4377 [('a', 'all', None, _('revert all changes when no arguments given')),
4376 ('d', 'date', '',
4378 ('d', 'date', '',
4377 _('tipmost revision matching date'), _('DATE')),
4379 _('tipmost revision matching date'), _('DATE')),
4378 ('r', 'rev', '',
4380 ('r', 'rev', '',
4379 _('revert to the specified revision'), _('REV')),
4381 _('revert to the specified revision'), _('REV')),
4380 ('', 'no-backup', None, _('do not save backup copies of files')),
4382 ('', 'no-backup', None, _('do not save backup copies of files')),
4381 ] + walkopts + dryrunopts,
4383 ] + walkopts + dryrunopts,
4382 _('[OPTION]... [-r REV] [NAME]...')),
4384 _('[OPTION]... [-r REV] [NAME]...')),
4383 "rollback": (rollback, dryrunopts),
4385 "rollback": (rollback, dryrunopts),
4384 "root": (root, []),
4386 "root": (root, []),
4385 "^serve":
4387 "^serve":
4386 (serve,
4388 (serve,
4387 [('A', 'accesslog', '',
4389 [('A', 'accesslog', '',
4388 _('name of access log file to write to'), _('FILE')),
4390 _('name of access log file to write to'), _('FILE')),
4389 ('d', 'daemon', None, _('run server in background')),
4391 ('d', 'daemon', None, _('run server in background')),
4390 ('', 'daemon-pipefds', '',
4392 ('', 'daemon-pipefds', '',
4391 _('used internally by daemon mode'), _('NUM')),
4393 _('used internally by daemon mode'), _('NUM')),
4392 ('E', 'errorlog', '',
4394 ('E', 'errorlog', '',
4393 _('name of error log file to write to'), _('FILE')),
4395 _('name of error log file to write to'), _('FILE')),
4394 # use string type, then we can check if something was passed
4396 # use string type, then we can check if something was passed
4395 ('p', 'port', '',
4397 ('p', 'port', '',
4396 _('port to listen on (default: 8000)'), _('PORT')),
4398 _('port to listen on (default: 8000)'), _('PORT')),
4397 ('a', 'address', '',
4399 ('a', 'address', '',
4398 _('address to listen on (default: all interfaces)'), _('ADDR')),
4400 _('address to listen on (default: all interfaces)'), _('ADDR')),
4399 ('', 'prefix', '',
4401 ('', 'prefix', '',
4400 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4402 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4401 ('n', 'name', '',
4403 ('n', 'name', '',
4402 _('name to show in web pages (default: working directory)'),
4404 _('name to show in web pages (default: working directory)'),
4403 _('NAME')),
4405 _('NAME')),
4404 ('', 'web-conf', '',
4406 ('', 'web-conf', '',
4405 _('name of the hgweb config file (see "hg help hgweb")'),
4407 _('name of the hgweb config file (see "hg help hgweb")'),
4406 _('FILE')),
4408 _('FILE')),
4407 ('', 'webdir-conf', '',
4409 ('', 'webdir-conf', '',
4408 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4410 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4409 ('', 'pid-file', '',
4411 ('', 'pid-file', '',
4410 _('name of file to write process ID to'), _('FILE')),
4412 _('name of file to write process ID to'), _('FILE')),
4411 ('', 'stdio', None, _('for remote clients')),
4413 ('', 'stdio', None, _('for remote clients')),
4412 ('t', 'templates', '',
4414 ('t', 'templates', '',
4413 _('web templates to use'), _('TEMPLATE')),
4415 _('web templates to use'), _('TEMPLATE')),
4414 ('', 'style', '',
4416 ('', 'style', '',
4415 _('template style to use'), _('STYLE')),
4417 _('template style to use'), _('STYLE')),
4416 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4418 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4417 ('', 'certificate', '',
4419 ('', 'certificate', '',
4418 _('SSL certificate file'), _('FILE'))],
4420 _('SSL certificate file'), _('FILE'))],
4419 _('[OPTION]...')),
4421 _('[OPTION]...')),
4420 "showconfig|debugconfig":
4422 "showconfig|debugconfig":
4421 (showconfig,
4423 (showconfig,
4422 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4424 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4423 _('[-u] [NAME]...')),
4425 _('[-u] [NAME]...')),
4424 "^summary|sum":
4426 "^summary|sum":
4425 (summary,
4427 (summary,
4426 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4428 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4427 "^status|st":
4429 "^status|st":
4428 (status,
4430 (status,
4429 [('A', 'all', None, _('show status of all files')),
4431 [('A', 'all', None, _('show status of all files')),
4430 ('m', 'modified', None, _('show only modified files')),
4432 ('m', 'modified', None, _('show only modified files')),
4431 ('a', 'added', None, _('show only added files')),
4433 ('a', 'added', None, _('show only added files')),
4432 ('r', 'removed', None, _('show only removed files')),
4434 ('r', 'removed', None, _('show only removed files')),
4433 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4435 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4434 ('c', 'clean', None, _('show only files without changes')),
4436 ('c', 'clean', None, _('show only files without changes')),
4435 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4437 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4436 ('i', 'ignored', None, _('show only ignored files')),
4438 ('i', 'ignored', None, _('show only ignored files')),
4437 ('n', 'no-status', None, _('hide status prefix')),
4439 ('n', 'no-status', None, _('hide status prefix')),
4438 ('C', 'copies', None, _('show source of copied files')),
4440 ('C', 'copies', None, _('show source of copied files')),
4439 ('0', 'print0', None,
4441 ('0', 'print0', None,
4440 _('end filenames with NUL, for use with xargs')),
4442 _('end filenames with NUL, for use with xargs')),
4441 ('', 'rev', [],
4443 ('', 'rev', [],
4442 _('show difference from revision'), _('REV')),
4444 _('show difference from revision'), _('REV')),
4443 ('', 'change', '',
4445 ('', 'change', '',
4444 _('list the changed files of a revision'), _('REV')),
4446 _('list the changed files of a revision'), _('REV')),
4445 ] + walkopts + subrepoopts,
4447 ] + walkopts + subrepoopts,
4446 _('[OPTION]... [FILE]...')),
4448 _('[OPTION]... [FILE]...')),
4447 "tag":
4449 "tag":
4448 (tag,
4450 (tag,
4449 [('f', 'force', None, _('replace existing tag')),
4451 [('f', 'force', None, _('replace existing tag')),
4450 ('l', 'local', None, _('make the tag local')),
4452 ('l', 'local', None, _('make the tag local')),
4451 ('r', 'rev', '',
4453 ('r', 'rev', '',
4452 _('revision to tag'), _('REV')),
4454 _('revision to tag'), _('REV')),
4453 ('', 'remove', None, _('remove a tag')),
4455 ('', 'remove', None, _('remove a tag')),
4454 # -l/--local is already there, commitopts cannot be used
4456 # -l/--local is already there, commitopts cannot be used
4455 ('e', 'edit', None, _('edit commit message')),
4457 ('e', 'edit', None, _('edit commit message')),
4456 ('m', 'message', '',
4458 ('m', 'message', '',
4457 _('use <text> as commit message'), _('TEXT')),
4459 _('use <text> as commit message'), _('TEXT')),
4458 ] + commitopts2,
4460 ] + commitopts2,
4459 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4461 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4460 "tags": (tags, [], ''),
4462 "tags": (tags, [], ''),
4461 "tip":
4463 "tip":
4462 (tip,
4464 (tip,
4463 [('p', 'patch', None, _('show patch')),
4465 [('p', 'patch', None, _('show patch')),
4464 ('g', 'git', None, _('use git extended diff format')),
4466 ('g', 'git', None, _('use git extended diff format')),
4465 ] + templateopts,
4467 ] + templateopts,
4466 _('[-p] [-g]')),
4468 _('[-p] [-g]')),
4467 "unbundle":
4469 "unbundle":
4468 (unbundle,
4470 (unbundle,
4469 [('u', 'update', None,
4471 [('u', 'update', None,
4470 _('update to new branch head if changesets were unbundled'))],
4472 _('update to new branch head if changesets were unbundled'))],
4471 _('[-u] FILE...')),
4473 _('[-u] FILE...')),
4472 "^update|up|checkout|co":
4474 "^update|up|checkout|co":
4473 (update,
4475 (update,
4474 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4476 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4475 ('c', 'check', None,
4477 ('c', 'check', None,
4476 _('update across branches if no uncommitted changes')),
4478 _('update across branches if no uncommitted changes')),
4477 ('d', 'date', '',
4479 ('d', 'date', '',
4478 _('tipmost revision matching date'), _('DATE')),
4480 _('tipmost revision matching date'), _('DATE')),
4479 ('r', 'rev', '',
4481 ('r', 'rev', '',
4480 _('revision'), _('REV'))],
4482 _('revision'), _('REV'))],
4481 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4483 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4482 "verify": (verify, []),
4484 "verify": (verify, []),
4483 "version": (version_, []),
4485 "version": (version_, []),
4484 }
4486 }
4485
4487
4486 norepo = ("clone init version help debugcommands debugcomplete"
4488 norepo = ("clone init version help debugcommands debugcomplete"
4487 " debugdate debuginstall debugfsinfo debugpushkey")
4489 " debugdate debuginstall debugfsinfo debugpushkey")
4488 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4490 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4489 " debugdata debugindex debugindexdot")
4491 " debugdata debugindex debugindexdot")
@@ -1,203 +1,87
1 Mercurial supports a functional language for selecting a set of
1 Mercurial supports a functional language for selecting a set of
2 revisions.
2 revisions.
3
3
4 The language supports a number of predicates which are joined by infix
4 The language supports a number of predicates which are joined by infix
5 operators. Parenthesis can be used for grouping.
5 operators. Parenthesis can be used for grouping.
6
6
7 Identifiers such as branch names must be quoted with single or double
7 Identifiers such as branch names must be quoted with single or double
8 quotes if they contain characters outside of
8 quotes if they contain characters outside of
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
10 predicates.
10 predicates.
11
11
12 Special characters can be used in quoted identifiers by escaping them,
12 Special characters can be used in quoted identifiers by escaping them,
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
15
15
16 There is a single prefix operator:
16 There is a single prefix operator:
17
17
18 ``not x``
18 ``not x``
19 Changesets not in x. Short form is ``! x``.
19 Changesets not in x. Short form is ``! x``.
20
20
21 These are the supported infix operators:
21 These are the supported infix operators:
22
22
23 ``x::y``
23 ``x::y``
24 A DAG range, meaning all changesets that are descendants of x and
24 A DAG range, meaning all changesets that are descendants of x and
25 ancestors of y, including x and y themselves. If the first endpoint
25 ancestors of y, including x and y themselves. If the first endpoint
26 is left out, this is equivalent to ``ancestors(y)``, if the second
26 is left out, this is equivalent to ``ancestors(y)``, if the second
27 is left out it is equivalent to ``descendants(x)``.
27 is left out it is equivalent to ``descendants(x)``.
28
28
29 An alternative syntax is ``x..y``.
29 An alternative syntax is ``x..y``.
30
30
31 ``x:y``
31 ``x:y``
32 All changesets with revision numbers between x and y, both
32 All changesets with revision numbers between x and y, both
33 inclusive. Either endpoint can be left out, they default to 0 and
33 inclusive. Either endpoint can be left out, they default to 0 and
34 tip.
34 tip.
35
35
36 ``x and y``
36 ``x and y``
37 The intersection of changesets in x and y. Short form is ``x & y``.
37 The intersection of changesets in x and y. Short form is ``x & y``.
38
38
39 ``x or y``
39 ``x or y``
40 The union of changesets in x and y. There are two alternative short
40 The union of changesets in x and y. There are two alternative short
41 forms: ``x | y`` and ``x + y``.
41 forms: ``x | y`` and ``x + y``.
42
42
43 ``x - y``
43 ``x - y``
44 Changesets in x but not in y.
44 Changesets in x but not in y.
45
45
46 The following predicates are supported:
46 The following predicates are supported:
47
47
48 ``adds(pattern)``
48 .. predicatesmarker
49 Changesets that add a file matching pattern.
50
51 ``all()``
52 All changesets, the same as ``0:tip``.
53
54 ``ancestor(single, single)``
55 Greatest common ancestor of the two changesets.
56
57 ``ancestors(set)``
58 Changesets that are ancestors of a changeset in set.
59
60 ``author(string)``
61 Alias for ``user(string)``.
62
63 ``branch(set)``
64 All changesets belonging to the branches of changesets in set.
65
66 ``children(set)``
67 Child changesets of changesets in set.
68
69 ``closed()``
70 Changeset is closed.
71
72 ``contains(pattern)``
73 Revision contains pattern.
74
75 ``date(interval)``
76 Changesets within the interval, see :hg:`help dates`.
77
78 ``descendants(set)``
79 Changesets which are descendants of changesets in set.
80
81 ``file(pattern)``
82 Changesets affecting files matched by pattern.
83
84 ``follow()``
85 An alias for ``::.`` (ancestors of the working copy's first parent).
86
87 ``grep(regex)``
88 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
89 to ensure special escape characters are handled correctly.
90
91 ``head()``
92 Changeset is a named branch head.
93
94 ``heads(set)``
95 Members of set with no children in set.
96
97 ``id(string)``
98 Revision non-ambiguously specified by the given hex string prefix
99
100 ``keyword(string)``
101 Search commit message, user name, and names of changed files for
102 string.
103
104 ``limit(set, n)``
105 First n members of set.
106
107 ``max(set)``
108 Changeset with highest revision number in set.
109
110 ``min(set)``
111 Changeset with lowest revision number in set.
112
113 ``merge()``
114 Changeset is a merge changeset.
115
116 ``modifies(pattern)``
117 Changesets modifying files matched by pattern.
118
119 ``outgoing([path])``
120 Changesets not found in the specified destination repository, or the
121 default push location.
122
123 ``p1(set)``
124 First parent of changesets in set.
125
126 ``p2(set)``
127 Second parent of changesets in set.
128
129 ``parents(set)``
130 The set of all parents for all changesets in set.
131
132 ``present(set)``
133 An empty set, if any revision in set isn't found; otherwise,
134 all revisions in set.
135
136 ``removes(pattern)``
137 Changesets which remove files matching pattern.
138
139 ``rev(number)``
140 Revision with the given numeric identifier.
141
142 ``reverse(set)``
143 Reverse order of set.
144
145 ``roots(set)``
146 Changesets with no parent changeset in set.
147
148 ``sort(set[, [-]key...])``
149 Sort set by keys. The default sort order is ascending, specify a key
150 as ``-key`` to sort in descending order.
151
152 The keys can be:
153
154 - ``rev`` for the revision number,
155 - ``branch`` for the branch name,
156 - ``desc`` for the commit message (description),
157 - ``user`` for user name (``author`` can be used as an alias),
158 - ``date`` for the commit date
159
160 ``tag(name)``
161 The specified tag by name, or all tagged revisions if no name is given.
162
163 ``user(string)``
164 User name is string.
165
49
166 Command line equivalents for :hg:`log`::
50 Command line equivalents for :hg:`log`::
167
51
168 -f -> ::.
52 -f -> ::.
169 -d x -> date(x)
53 -d x -> date(x)
170 -k x -> keyword(x)
54 -k x -> keyword(x)
171 -m -> merge()
55 -m -> merge()
172 -u x -> user(x)
56 -u x -> user(x)
173 -b x -> branch(x)
57 -b x -> branch(x)
174 -P x -> !::x
58 -P x -> !::x
175 -l x -> limit(expr, x)
59 -l x -> limit(expr, x)
176
60
177 Some sample queries:
61 Some sample queries:
178
62
179 - Changesets on the default branch::
63 - Changesets on the default branch::
180
64
181 hg log -r "branch(default)"
65 hg log -r "branch(default)"
182
66
183 - Changesets on the default branch since tag 1.5 (excluding merges)::
67 - Changesets on the default branch since tag 1.5 (excluding merges)::
184
68
185 hg log -r "branch(default) and 1.5:: and not merge()"
69 hg log -r "branch(default) and 1.5:: and not merge()"
186
70
187 - Open branch heads::
71 - Open branch heads::
188
72
189 hg log -r "head() and not closed()"
73 hg log -r "head() and not closed()"
190
74
191 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
75 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
192 ``hgext/*``::
76 ``hgext/*``::
193
77
194 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
78 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
195
79
196 - Changesets in committed May 2008, sorted by user::
80 - Changesets in committed May 2008, sorted by user::
197
81
198 hg log -r "sort(date('May 2008'), user)"
82 hg log -r "sort(date('May 2008'), user)"
199
83
200 - Changesets mentioning "bug" or "issue" that are not in a tagged
84 - Changesets mentioning "bug" or "issue" that are not in a tagged
201 release::
85 release::
202
86
203 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tagged())"
87 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tagged())"
@@ -1,655 +1,793
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery
9 import parser, util, error, discovery
10 import match as matchmod
10 import match as matchmod
11 from i18n import _
11 from i18n import _
12
12
13 elements = {
13 elements = {
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "-": (5, ("negate", 19), ("minus", 5)),
15 "-": (5, ("negate", 19), ("minus", 5)),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
17 ("dagrangepost", 17)),
17 ("dagrangepost", 17)),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
19 ("dagrangepost", 17)),
19 ("dagrangepost", 17)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
21 "not": (10, ("not", 10)),
21 "not": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
23 "and": (5, None, ("and", 5)),
23 "and": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
25 "or": (4, None, ("or", 4)),
25 "or": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
28 ",": (2, None, ("list", 2)),
28 ",": (2, None, ("list", 2)),
29 ")": (0, None, None),
29 ")": (0, None, None),
30 "symbol": (0, ("symbol",), None),
30 "symbol": (0, ("symbol",), None),
31 "string": (0, ("string",), None),
31 "string": (0, ("string",), None),
32 "end": (0, None, None),
32 "end": (0, None, None),
33 }
33 }
34
34
35 keywords = set(['and', 'or', 'not'])
35 keywords = set(['and', 'or', 'not'])
36
36
37 def tokenize(program):
37 def tokenize(program):
38 pos, l = 0, len(program)
38 pos, l = 0, len(program)
39 while pos < l:
39 while pos < l:
40 c = program[pos]
40 c = program[pos]
41 if c.isspace(): # skip inter-token whitespace
41 if c.isspace(): # skip inter-token whitespace
42 pass
42 pass
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
44 yield ('::', None, pos)
44 yield ('::', None, pos)
45 pos += 1 # skip ahead
45 pos += 1 # skip ahead
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
47 yield ('..', None, pos)
47 yield ('..', None, pos)
48 pos += 1 # skip ahead
48 pos += 1 # skip ahead
49 elif c in "():,-|&+!": # handle simple operators
49 elif c in "():,-|&+!": # handle simple operators
50 yield (c, None, pos)
50 yield (c, None, pos)
51 elif (c in '"\'' or c == 'r' and
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
53 if c == 'r':
54 pos += 1
54 pos += 1
55 c = program[pos]
55 c = program[pos]
56 decode = lambda x: x
56 decode = lambda x: x
57 else:
57 else:
58 decode = lambda x: x.decode('string-escape')
58 decode = lambda x: x.decode('string-escape')
59 pos += 1
59 pos += 1
60 s = pos
60 s = pos
61 while pos < l: # find closing quote
61 while pos < l: # find closing quote
62 d = program[pos]
62 d = program[pos]
63 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
64 pos += 2
64 pos += 2
65 continue
65 continue
66 if d == c:
66 if d == c:
67 yield ('string', decode(program[s:pos]), s)
67 yield ('string', decode(program[s:pos]), s)
68 break
68 break
69 pos += 1
69 pos += 1
70 else:
70 else:
71 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 s = pos
73 s = pos
74 pos += 1
74 pos += 1
75 while pos < l: # find end of symbol
75 while pos < l: # find end of symbol
76 d = program[pos]
76 d = program[pos]
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 break
78 break
79 if d == '.' and program[pos - 1] == '.': # special case for ..
79 if d == '.' and program[pos - 1] == '.': # special case for ..
80 pos -= 1
80 pos -= 1
81 break
81 break
82 pos += 1
82 pos += 1
83 sym = program[s:pos]
83 sym = program[s:pos]
84 if sym in keywords: # operator keywords
84 if sym in keywords: # operator keywords
85 yield (sym, None, s)
85 yield (sym, None, s)
86 else:
86 else:
87 yield ('symbol', sym, s)
87 yield ('symbol', sym, s)
88 pos -= 1
88 pos -= 1
89 else:
89 else:
90 raise error.ParseError(_("syntax error"), pos)
90 raise error.ParseError(_("syntax error"), pos)
91 pos += 1
91 pos += 1
92 yield ('end', None, pos)
92 yield ('end', None, pos)
93
93
94 # helpers
94 # helpers
95
95
96 def getstring(x, err):
96 def getstring(x, err):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 return x[1]
98 return x[1]
99 raise error.ParseError(err)
99 raise error.ParseError(err)
100
100
101 def getlist(x):
101 def getlist(x):
102 if not x:
102 if not x:
103 return []
103 return []
104 if x[0] == 'list':
104 if x[0] == 'list':
105 return getlist(x[1]) + [x[2]]
105 return getlist(x[1]) + [x[2]]
106 return [x]
106 return [x]
107
107
108 def getargs(x, min, max, err):
108 def getargs(x, min, max, err):
109 l = getlist(x)
109 l = getlist(x)
110 if len(l) < min or len(l) > max:
110 if len(l) < min or len(l) > max:
111 raise error.ParseError(err)
111 raise error.ParseError(err)
112 return l
112 return l
113
113
114 def getset(repo, subset, x):
114 def getset(repo, subset, x):
115 if not x:
115 if not x:
116 raise error.ParseError(_("missing argument"))
116 raise error.ParseError(_("missing argument"))
117 return methods[x[0]](repo, subset, *x[1:])
117 return methods[x[0]](repo, subset, *x[1:])
118
118
119 # operator methods
119 # operator methods
120
120
121 def stringset(repo, subset, x):
121 def stringset(repo, subset, x):
122 x = repo[x].rev()
122 x = repo[x].rev()
123 if x == -1 and len(subset) == len(repo):
123 if x == -1 and len(subset) == len(repo):
124 return [-1]
124 return [-1]
125 if x in subset:
125 if x in subset:
126 return [x]
126 return [x]
127 return []
127 return []
128
128
129 def symbolset(repo, subset, x):
129 def symbolset(repo, subset, x):
130 if x in symbols:
130 if x in symbols:
131 raise error.ParseError(_("can't use %s here") % x)
131 raise error.ParseError(_("can't use %s here") % x)
132 return stringset(repo, subset, x)
132 return stringset(repo, subset, x)
133
133
134 def rangeset(repo, subset, x, y):
134 def rangeset(repo, subset, x, y):
135 m = getset(repo, subset, x)
135 m = getset(repo, subset, x)
136 if not m:
136 if not m:
137 m = getset(repo, range(len(repo)), x)
137 m = getset(repo, range(len(repo)), x)
138
138
139 n = getset(repo, subset, y)
139 n = getset(repo, subset, y)
140 if not n:
140 if not n:
141 n = getset(repo, range(len(repo)), y)
141 n = getset(repo, range(len(repo)), y)
142
142
143 if not m or not n:
143 if not m or not n:
144 return []
144 return []
145 m, n = m[0], n[-1]
145 m, n = m[0], n[-1]
146
146
147 if m < n:
147 if m < n:
148 r = range(m, n + 1)
148 r = range(m, n + 1)
149 else:
149 else:
150 r = range(m, n - 1, -1)
150 r = range(m, n - 1, -1)
151 s = set(subset)
151 s = set(subset)
152 return [x for x in r if x in s]
152 return [x for x in r if x in s]
153
153
154 def andset(repo, subset, x, y):
154 def andset(repo, subset, x, y):
155 return getset(repo, getset(repo, subset, x), y)
155 return getset(repo, getset(repo, subset, x), y)
156
156
157 def orset(repo, subset, x, y):
157 def orset(repo, subset, x, y):
158 s = set(getset(repo, subset, x))
158 s = set(getset(repo, subset, x))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 return [r for r in subset if r in s]
160 return [r for r in subset if r in s]
161
161
162 def notset(repo, subset, x):
162 def notset(repo, subset, x):
163 s = set(getset(repo, subset, x))
163 s = set(getset(repo, subset, x))
164 return [r for r in subset if r not in s]
164 return [r for r in subset if r not in s]
165
165
166 def listset(repo, subset, a, b):
166 def listset(repo, subset, a, b):
167 raise error.ParseError(_("can't use a list in this context"))
167 raise error.ParseError(_("can't use a list in this context"))
168
168
169 def func(repo, subset, a, b):
169 def func(repo, subset, a, b):
170 if a[0] == 'symbol' and a[1] in symbols:
170 if a[0] == 'symbol' and a[1] in symbols:
171 return symbols[a[1]](repo, subset, b)
171 return symbols[a[1]](repo, subset, b)
172 raise error.ParseError(_("not a function: %s") % a[1])
172 raise error.ParseError(_("not a function: %s") % a[1])
173
173
174 # functions
174 # functions
175
175
176 def node(repo, subset, x):
176 def node(repo, subset, x):
177 """``id(string)``
178 Revision non-ambiguously specified by the given hex string prefix
179 """
177 # i18n: "id" is a keyword
180 # i18n: "id" is a keyword
178 l = getargs(x, 1, 1, _("id requires one argument"))
181 l = getargs(x, 1, 1, _("id requires one argument"))
179 # i18n: "id" is a keyword
182 # i18n: "id" is a keyword
180 n = getstring(l[0], _("id requires a string"))
183 n = getstring(l[0], _("id requires a string"))
181 if len(n) == 40:
184 if len(n) == 40:
182 rn = repo[n].rev()
185 rn = repo[n].rev()
183 else:
186 else:
184 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
187 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
185 return [r for r in subset if r == rn]
188 return [r for r in subset if r == rn]
186
189
187 def rev(repo, subset, x):
190 def rev(repo, subset, x):
191 """``rev(number)``
192 Revision with the given numeric identifier.
193 """
188 # i18n: "rev" is a keyword
194 # i18n: "rev" is a keyword
189 l = getargs(x, 1, 1, _("rev requires one argument"))
195 l = getargs(x, 1, 1, _("rev requires one argument"))
190 try:
196 try:
191 # i18n: "rev" is a keyword
197 # i18n: "rev" is a keyword
192 l = int(getstring(l[0], _("rev requires a number")))
198 l = int(getstring(l[0], _("rev requires a number")))
193 except ValueError:
199 except ValueError:
194 # i18n: "rev" is a keyword
200 # i18n: "rev" is a keyword
195 raise error.ParseError(_("rev expects a number"))
201 raise error.ParseError(_("rev expects a number"))
196 return [r for r in subset if r == l]
202 return [r for r in subset if r == l]
197
203
198 def p1(repo, subset, x):
204 def p1(repo, subset, x):
205 """``p1(set)``
206 First parent of changesets in set.
207 """
199 ps = set()
208 ps = set()
200 cl = repo.changelog
209 cl = repo.changelog
201 for r in getset(repo, range(len(repo)), x):
210 for r in getset(repo, range(len(repo)), x):
202 ps.add(cl.parentrevs(r)[0])
211 ps.add(cl.parentrevs(r)[0])
203 return [r for r in subset if r in ps]
212 return [r for r in subset if r in ps]
204
213
205 def p2(repo, subset, x):
214 def p2(repo, subset, x):
215 """``p2(set)``
216 Second parent of changesets in set.
217 """
206 ps = set()
218 ps = set()
207 cl = repo.changelog
219 cl = repo.changelog
208 for r in getset(repo, range(len(repo)), x):
220 for r in getset(repo, range(len(repo)), x):
209 ps.add(cl.parentrevs(r)[1])
221 ps.add(cl.parentrevs(r)[1])
210 return [r for r in subset if r in ps]
222 return [r for r in subset if r in ps]
211
223
212 def parents(repo, subset, x):
224 def parents(repo, subset, x):
225 """``parents(set)``
226 The set of all parents for all changesets in set.
227 """
213 ps = set()
228 ps = set()
214 cl = repo.changelog
229 cl = repo.changelog
215 for r in getset(repo, range(len(repo)), x):
230 for r in getset(repo, range(len(repo)), x):
216 ps.update(cl.parentrevs(r))
231 ps.update(cl.parentrevs(r))
217 return [r for r in subset if r in ps]
232 return [r for r in subset if r in ps]
218
233
219 def maxrev(repo, subset, x):
234 def maxrev(repo, subset, x):
235 """``max(set)``
236 Changeset with highest revision number in set.
237 """
220 s = getset(repo, subset, x)
238 s = getset(repo, subset, x)
221 if s:
239 if s:
222 m = max(s)
240 m = max(s)
223 if m in subset:
241 if m in subset:
224 return [m]
242 return [m]
225 return []
243 return []
226
244
227 def minrev(repo, subset, x):
245 def minrev(repo, subset, x):
246 """``min(set)``
247 Changeset with lowest revision number in set.
248 """
228 s = getset(repo, subset, x)
249 s = getset(repo, subset, x)
229 if s:
250 if s:
230 m = min(s)
251 m = min(s)
231 if m in subset:
252 if m in subset:
232 return [m]
253 return [m]
233 return []
254 return []
234
255
235 def limit(repo, subset, x):
256 def limit(repo, subset, x):
257 """``limit(set, n)``
258 First n members of set.
259 """
236 # i18n: "limit" is a keyword
260 # i18n: "limit" is a keyword
237 l = getargs(x, 2, 2, _("limit requires two arguments"))
261 l = getargs(x, 2, 2, _("limit requires two arguments"))
238 try:
262 try:
239 # i18n: "limit" is a keyword
263 # i18n: "limit" is a keyword
240 lim = int(getstring(l[1], _("limit requires a number")))
264 lim = int(getstring(l[1], _("limit requires a number")))
241 except ValueError:
265 except ValueError:
242 # i18n: "limit" is a keyword
266 # i18n: "limit" is a keyword
243 raise error.ParseError(_("limit expects a number"))
267 raise error.ParseError(_("limit expects a number"))
244 return getset(repo, subset, l[0])[:lim]
268 return getset(repo, subset, l[0])[:lim]
245
269
246 def children(repo, subset, x):
270 def children(repo, subset, x):
271 """``children(set)``
272 Child changesets of changesets in set.
273 """
247 cs = set()
274 cs = set()
248 cl = repo.changelog
275 cl = repo.changelog
249 s = set(getset(repo, range(len(repo)), x))
276 s = set(getset(repo, range(len(repo)), x))
250 for r in xrange(0, len(repo)):
277 for r in xrange(0, len(repo)):
251 for p in cl.parentrevs(r):
278 for p in cl.parentrevs(r):
252 if p in s:
279 if p in s:
253 cs.add(r)
280 cs.add(r)
254 return [r for r in subset if r in cs]
281 return [r for r in subset if r in cs]
255
282
256 def branch(repo, subset, x):
283 def branch(repo, subset, x):
284 """``branch(set)``
285 All changesets belonging to the branches of changesets in set.
286 """
257 s = getset(repo, range(len(repo)), x)
287 s = getset(repo, range(len(repo)), x)
258 b = set()
288 b = set()
259 for r in s:
289 for r in s:
260 b.add(repo[r].branch())
290 b.add(repo[r].branch())
261 s = set(s)
291 s = set(s)
262 return [r for r in subset if r in s or repo[r].branch() in b]
292 return [r for r in subset if r in s or repo[r].branch() in b]
263
293
264 def ancestor(repo, subset, x):
294 def ancestor(repo, subset, x):
295 """``ancestor(single, single)``
296 Greatest common ancestor of the two changesets.
297 """
265 # i18n: "ancestor" is a keyword
298 # i18n: "ancestor" is a keyword
266 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
299 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
267 r = range(len(repo))
300 r = range(len(repo))
268 a = getset(repo, r, l[0])
301 a = getset(repo, r, l[0])
269 b = getset(repo, r, l[1])
302 b = getset(repo, r, l[1])
270 if len(a) != 1 or len(b) != 1:
303 if len(a) != 1 or len(b) != 1:
271 # i18n: "ancestor" is a keyword
304 # i18n: "ancestor" is a keyword
272 raise error.ParseError(_("ancestor arguments must be single revisions"))
305 raise error.ParseError(_("ancestor arguments must be single revisions"))
273 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
306 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
274
307
275 return [r for r in an if r in subset]
308 return [r for r in an if r in subset]
276
309
277 def ancestors(repo, subset, x):
310 def ancestors(repo, subset, x):
311 """``ancestors(set)``
312 Changesets that are ancestors of a changeset in set.
313 """
278 args = getset(repo, range(len(repo)), x)
314 args = getset(repo, range(len(repo)), x)
279 if not args:
315 if not args:
280 return []
316 return []
281 s = set(repo.changelog.ancestors(*args)) | set(args)
317 s = set(repo.changelog.ancestors(*args)) | set(args)
282 return [r for r in subset if r in s]
318 return [r for r in subset if r in s]
283
319
284 def descendants(repo, subset, x):
320 def descendants(repo, subset, x):
321 """``descendants(set)``
322 Changesets which are descendants of changesets in set.
323 """
285 args = getset(repo, range(len(repo)), x)
324 args = getset(repo, range(len(repo)), x)
286 if not args:
325 if not args:
287 return []
326 return []
288 s = set(repo.changelog.descendants(*args)) | set(args)
327 s = set(repo.changelog.descendants(*args)) | set(args)
289 return [r for r in subset if r in s]
328 return [r for r in subset if r in s]
290
329
291 def follow(repo, subset, x):
330 def follow(repo, subset, x):
331 """``follow()``
332 An alias for ``::.`` (ancestors of the working copy's first parent).
333 """
292 # i18n: "follow" is a keyword
334 # i18n: "follow" is a keyword
293 getargs(x, 0, 0, _("follow takes no arguments"))
335 getargs(x, 0, 0, _("follow takes no arguments"))
294 p = repo['.'].rev()
336 p = repo['.'].rev()
295 s = set(repo.changelog.ancestors(p)) | set([p])
337 s = set(repo.changelog.ancestors(p)) | set([p])
296 return [r for r in subset if r in s]
338 return [r for r in subset if r in s]
297
339
298 def date(repo, subset, x):
340 def date(repo, subset, x):
341 """``date(interval)``
342 Changesets within the interval, see :hg:`help dates`.
343 """
299 # i18n: "date" is a keyword
344 # i18n: "date" is a keyword
300 ds = getstring(x, _("date requires a string"))
345 ds = getstring(x, _("date requires a string"))
301 dm = util.matchdate(ds)
346 dm = util.matchdate(ds)
302 return [r for r in subset if dm(repo[r].date()[0])]
347 return [r for r in subset if dm(repo[r].date()[0])]
303
348
304 def keyword(repo, subset, x):
349 def keyword(repo, subset, x):
350 """``keyword(string)``
351 Search commit message, user name, and names of changed files for
352 string.
353 """
305 # i18n: "keyword" is a keyword
354 # i18n: "keyword" is a keyword
306 kw = getstring(x, _("keyword requires a string")).lower()
355 kw = getstring(x, _("keyword requires a string")).lower()
307 l = []
356 l = []
308 for r in subset:
357 for r in subset:
309 c = repo[r]
358 c = repo[r]
310 t = " ".join(c.files() + [c.user(), c.description()])
359 t = " ".join(c.files() + [c.user(), c.description()])
311 if kw in t.lower():
360 if kw in t.lower():
312 l.append(r)
361 l.append(r)
313 return l
362 return l
314
363
315 def grep(repo, subset, x):
364 def grep(repo, subset, x):
365 """``grep(regex)``
366 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
367 to ensure special escape characters are handled correctly.
368 """
316 try:
369 try:
317 # i18n: "grep" is a keyword
370 # i18n: "grep" is a keyword
318 gr = re.compile(getstring(x, _("grep requires a string")))
371 gr = re.compile(getstring(x, _("grep requires a string")))
319 except re.error, e:
372 except re.error, e:
320 raise error.ParseError(_('invalid match pattern: %s') % e)
373 raise error.ParseError(_('invalid match pattern: %s') % e)
321 l = []
374 l = []
322 for r in subset:
375 for r in subset:
323 c = repo[r]
376 c = repo[r]
324 for e in c.files() + [c.user(), c.description()]:
377 for e in c.files() + [c.user(), c.description()]:
325 if gr.search(e):
378 if gr.search(e):
326 l.append(r)
379 l.append(r)
327 continue
380 continue
328 return l
381 return l
329
382
330 def author(repo, subset, x):
383 def author(repo, subset, x):
384 """``author(string)``
385 Alias for ``user(string)``.
386 """
331 # i18n: "author" is a keyword
387 # i18n: "author" is a keyword
332 n = getstring(x, _("author requires a string")).lower()
388 n = getstring(x, _("author requires a string")).lower()
333 return [r for r in subset if n in repo[r].user().lower()]
389 return [r for r in subset if n in repo[r].user().lower()]
334
390
391 def user(repo, subset, x):
392 """``user(string)``
393 User name is string.
394 """
395 return author(repo, subset, x)
396
335 def hasfile(repo, subset, x):
397 def hasfile(repo, subset, x):
398 """``file(pattern)``
399 Changesets affecting files matched by pattern.
400 """
336 # i18n: "file" is a keyword
401 # i18n: "file" is a keyword
337 pat = getstring(x, _("file requires a pattern"))
402 pat = getstring(x, _("file requires a pattern"))
338 m = matchmod.match(repo.root, repo.getcwd(), [pat])
403 m = matchmod.match(repo.root, repo.getcwd(), [pat])
339 s = []
404 s = []
340 for r in subset:
405 for r in subset:
341 for f in repo[r].files():
406 for f in repo[r].files():
342 if m(f):
407 if m(f):
343 s.append(r)
408 s.append(r)
344 continue
409 continue
345 return s
410 return s
346
411
347 def contains(repo, subset, x):
412 def contains(repo, subset, x):
413 """``contains(pattern)``
414 Revision contains pattern.
415 """
348 # i18n: "contains" is a keyword
416 # i18n: "contains" is a keyword
349 pat = getstring(x, _("contains requires a pattern"))
417 pat = getstring(x, _("contains requires a pattern"))
350 m = matchmod.match(repo.root, repo.getcwd(), [pat])
418 m = matchmod.match(repo.root, repo.getcwd(), [pat])
351 s = []
419 s = []
352 if m.files() == [pat]:
420 if m.files() == [pat]:
353 for r in subset:
421 for r in subset:
354 if pat in repo[r]:
422 if pat in repo[r]:
355 s.append(r)
423 s.append(r)
356 continue
424 continue
357 else:
425 else:
358 for r in subset:
426 for r in subset:
359 for f in repo[r].manifest():
427 for f in repo[r].manifest():
360 if m(f):
428 if m(f):
361 s.append(r)
429 s.append(r)
362 continue
430 continue
363 return s
431 return s
364
432
365 def checkstatus(repo, subset, pat, field):
433 def checkstatus(repo, subset, pat, field):
366 m = matchmod.match(repo.root, repo.getcwd(), [pat])
434 m = matchmod.match(repo.root, repo.getcwd(), [pat])
367 s = []
435 s = []
368 fast = (m.files() == [pat])
436 fast = (m.files() == [pat])
369 for r in subset:
437 for r in subset:
370 c = repo[r]
438 c = repo[r]
371 if fast:
439 if fast:
372 if pat not in c.files():
440 if pat not in c.files():
373 continue
441 continue
374 else:
442 else:
375 for f in c.files():
443 for f in c.files():
376 if m(f):
444 if m(f):
377 break
445 break
378 else:
446 else:
379 continue
447 continue
380 files = repo.status(c.p1().node(), c.node())[field]
448 files = repo.status(c.p1().node(), c.node())[field]
381 if fast:
449 if fast:
382 if pat in files:
450 if pat in files:
383 s.append(r)
451 s.append(r)
384 continue
452 continue
385 else:
453 else:
386 for f in files:
454 for f in files:
387 if m(f):
455 if m(f):
388 s.append(r)
456 s.append(r)
389 continue
457 continue
390 return s
458 return s
391
459
392 def modifies(repo, subset, x):
460 def modifies(repo, subset, x):
461 """``modifies(pattern)``
462 Changesets modifying files matched by pattern.
463 """
393 # i18n: "modifies" is a keyword
464 # i18n: "modifies" is a keyword
394 pat = getstring(x, _("modifies requires a pattern"))
465 pat = getstring(x, _("modifies requires a pattern"))
395 return checkstatus(repo, subset, pat, 0)
466 return checkstatus(repo, subset, pat, 0)
396
467
397 def adds(repo, subset, x):
468 def adds(repo, subset, x):
469 """``adds(pattern)``
470 Changesets that add a file matching pattern.
471 """
398 # i18n: "adds" is a keyword
472 # i18n: "adds" is a keyword
399 pat = getstring(x, _("adds requires a pattern"))
473 pat = getstring(x, _("adds requires a pattern"))
400 return checkstatus(repo, subset, pat, 1)
474 return checkstatus(repo, subset, pat, 1)
401
475
402 def removes(repo, subset, x):
476 def removes(repo, subset, x):
477 """``removes(pattern)``
478 Changesets which remove files matching pattern.
479 """
403 # i18n: "removes" is a keyword
480 # i18n: "removes" is a keyword
404 pat = getstring(x, _("removes requires a pattern"))
481 pat = getstring(x, _("removes requires a pattern"))
405 return checkstatus(repo, subset, pat, 2)
482 return checkstatus(repo, subset, pat, 2)
406
483
407 def merge(repo, subset, x):
484 def merge(repo, subset, x):
485 """``merge()``
486 Changeset is a merge changeset.
487 """
408 # i18n: "merge" is a keyword
488 # i18n: "merge" is a keyword
409 getargs(x, 0, 0, _("merge takes no arguments"))
489 getargs(x, 0, 0, _("merge takes no arguments"))
410 cl = repo.changelog
490 cl = repo.changelog
411 return [r for r in subset if cl.parentrevs(r)[1] != -1]
491 return [r for r in subset if cl.parentrevs(r)[1] != -1]
412
492
413 def closed(repo, subset, x):
493 def closed(repo, subset, x):
494 """``closed()``
495 Changeset is closed.
496 """
414 # i18n: "closed" is a keyword
497 # i18n: "closed" is a keyword
415 getargs(x, 0, 0, _("closed takes no arguments"))
498 getargs(x, 0, 0, _("closed takes no arguments"))
416 return [r for r in subset if repo[r].extra().get('close')]
499 return [r for r in subset if repo[r].extra().get('close')]
417
500
418 def head(repo, subset, x):
501 def head(repo, subset, x):
502 """``head()``
503 Changeset is a named branch head.
504 """
419 # i18n: "head" is a keyword
505 # i18n: "head" is a keyword
420 getargs(x, 0, 0, _("head takes no arguments"))
506 getargs(x, 0, 0, _("head takes no arguments"))
421 hs = set()
507 hs = set()
422 for b, ls in repo.branchmap().iteritems():
508 for b, ls in repo.branchmap().iteritems():
423 hs.update(repo[h].rev() for h in ls)
509 hs.update(repo[h].rev() for h in ls)
424 return [r for r in subset if r in hs]
510 return [r for r in subset if r in hs]
425
511
426 def reverse(repo, subset, x):
512 def reverse(repo, subset, x):
513 """``reverse(set)``
514 Reverse order of set.
515 """
427 l = getset(repo, subset, x)
516 l = getset(repo, subset, x)
428 l.reverse()
517 l.reverse()
429 return l
518 return l
430
519
431 def present(repo, subset, x):
520 def present(repo, subset, x):
521 """``present(set)``
522 An empty set, if any revision in set isn't found; otherwise,
523 all revisions in set.
524 """
432 try:
525 try:
433 return getset(repo, subset, x)
526 return getset(repo, subset, x)
434 except error.RepoLookupError:
527 except error.RepoLookupError:
435 return []
528 return []
436
529
437 def sort(repo, subset, x):
530 def sort(repo, subset, x):
531 """``sort(set[, [-]key...])``
532 Sort set by keys. The default sort order is ascending, specify a key
533 as ``-key`` to sort in descending order.
534
535 The keys can be:
536
537 - ``rev`` for the revision number,
538 - ``branch`` for the branch name,
539 - ``desc`` for the commit message (description),
540 - ``user`` for user name (``author`` can be used as an alias),
541 - ``date`` for the commit date
542 """
438 # i18n: "sort" is a keyword
543 # i18n: "sort" is a keyword
439 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
544 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
440 keys = "rev"
545 keys = "rev"
441 if len(l) == 2:
546 if len(l) == 2:
442 keys = getstring(l[1], _("sort spec must be a string"))
547 keys = getstring(l[1], _("sort spec must be a string"))
443
548
444 s = l[0]
549 s = l[0]
445 keys = keys.split()
550 keys = keys.split()
446 l = []
551 l = []
447 def invert(s):
552 def invert(s):
448 return "".join(chr(255 - ord(c)) for c in s)
553 return "".join(chr(255 - ord(c)) for c in s)
449 for r in getset(repo, subset, s):
554 for r in getset(repo, subset, s):
450 c = repo[r]
555 c = repo[r]
451 e = []
556 e = []
452 for k in keys:
557 for k in keys:
453 if k == 'rev':
558 if k == 'rev':
454 e.append(r)
559 e.append(r)
455 elif k == '-rev':
560 elif k == '-rev':
456 e.append(-r)
561 e.append(-r)
457 elif k == 'branch':
562 elif k == 'branch':
458 e.append(c.branch())
563 e.append(c.branch())
459 elif k == '-branch':
564 elif k == '-branch':
460 e.append(invert(c.branch()))
565 e.append(invert(c.branch()))
461 elif k == 'desc':
566 elif k == 'desc':
462 e.append(c.description())
567 e.append(c.description())
463 elif k == '-desc':
568 elif k == '-desc':
464 e.append(invert(c.description()))
569 e.append(invert(c.description()))
465 elif k in 'user author':
570 elif k in 'user author':
466 e.append(c.user())
571 e.append(c.user())
467 elif k in '-user -author':
572 elif k in '-user -author':
468 e.append(invert(c.user()))
573 e.append(invert(c.user()))
469 elif k == 'date':
574 elif k == 'date':
470 e.append(c.date()[0])
575 e.append(c.date()[0])
471 elif k == '-date':
576 elif k == '-date':
472 e.append(-c.date()[0])
577 e.append(-c.date()[0])
473 else:
578 else:
474 raise error.ParseError(_("unknown sort key %r") % k)
579 raise error.ParseError(_("unknown sort key %r") % k)
475 e.append(r)
580 e.append(r)
476 l.append(e)
581 l.append(e)
477 l.sort()
582 l.sort()
478 return [e[-1] for e in l]
583 return [e[-1] for e in l]
479
584
480 def getall(repo, subset, x):
585 def getall(repo, subset, x):
586 """``all()``
587 All changesets, the same as ``0:tip``.
588 """
481 # i18n: "all" is a keyword
589 # i18n: "all" is a keyword
482 getargs(x, 0, 0, _("all takes no arguments"))
590 getargs(x, 0, 0, _("all takes no arguments"))
483 return subset
591 return subset
484
592
485 def heads(repo, subset, x):
593 def heads(repo, subset, x):
594 """``heads(set)``
595 Members of set with no children in set.
596 """
486 s = getset(repo, subset, x)
597 s = getset(repo, subset, x)
487 ps = set(parents(repo, subset, x))
598 ps = set(parents(repo, subset, x))
488 return [r for r in s if r not in ps]
599 return [r for r in s if r not in ps]
489
600
490 def roots(repo, subset, x):
601 def roots(repo, subset, x):
602 """``roots(set)``
603 Changesets with no parent changeset in set.
604 """
491 s = getset(repo, subset, x)
605 s = getset(repo, subset, x)
492 cs = set(children(repo, subset, x))
606 cs = set(children(repo, subset, x))
493 return [r for r in s if r not in cs]
607 return [r for r in s if r not in cs]
494
608
495 def outgoing(repo, subset, x):
609 def outgoing(repo, subset, x):
610 """``outgoing([path])``
611 Changesets not found in the specified destination repository, or the
612 default push location.
613 """
496 import hg # avoid start-up nasties
614 import hg # avoid start-up nasties
497 # i18n: "outgoing" is a keyword
615 # i18n: "outgoing" is a keyword
498 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
616 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
499 # i18n: "outgoing" is a keyword
617 # i18n: "outgoing" is a keyword
500 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
618 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
501 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
619 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
502 dest, branches = hg.parseurl(dest)
620 dest, branches = hg.parseurl(dest)
503 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
621 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
504 if revs:
622 if revs:
505 revs = [repo.lookup(rev) for rev in revs]
623 revs = [repo.lookup(rev) for rev in revs]
506 other = hg.repository(hg.remoteui(repo, {}), dest)
624 other = hg.repository(hg.remoteui(repo, {}), dest)
507 repo.ui.pushbuffer()
625 repo.ui.pushbuffer()
508 o = discovery.findoutgoing(repo, other)
626 o = discovery.findoutgoing(repo, other)
509 repo.ui.popbuffer()
627 repo.ui.popbuffer()
510 cl = repo.changelog
628 cl = repo.changelog
511 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
629 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
512 return [r for r in subset if r in o]
630 return [r for r in subset if r in o]
513
631
514 def tag(repo, subset, x):
632 def tag(repo, subset, x):
633 """``tag(name)``
634 The specified tag by name, or all tagged revisions if no name is given.
635 """
515 # i18n: "tag" is a keyword
636 # i18n: "tag" is a keyword
516 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
637 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
517 cl = repo.changelog
638 cl = repo.changelog
518 if args:
639 if args:
519 tn = getstring(args[0],
640 tn = getstring(args[0],
520 # i18n: "tag" is a keyword
641 # i18n: "tag" is a keyword
521 _('the argument to tag must be a string'))
642 _('the argument to tag must be a string'))
522 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
643 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
523 else:
644 else:
524 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
645 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
525 return [r for r in subset if r in s]
646 return [r for r in subset if r in s]
526
647
648 def tagged(repo, subset, x):
649 return tag(repo, subset, x)
650
527 symbols = {
651 symbols = {
528 "adds": adds,
652 "adds": adds,
529 "all": getall,
653 "all": getall,
530 "ancestor": ancestor,
654 "ancestor": ancestor,
531 "ancestors": ancestors,
655 "ancestors": ancestors,
532 "author": author,
656 "author": author,
533 "branch": branch,
657 "branch": branch,
534 "children": children,
658 "children": children,
535 "closed": closed,
659 "closed": closed,
536 "contains": contains,
660 "contains": contains,
537 "date": date,
661 "date": date,
538 "descendants": descendants,
662 "descendants": descendants,
539 "file": hasfile,
663 "file": hasfile,
540 "follow": follow,
664 "follow": follow,
541 "grep": grep,
665 "grep": grep,
542 "head": head,
666 "head": head,
543 "heads": heads,
667 "heads": heads,
544 "keyword": keyword,
668 "keyword": keyword,
545 "limit": limit,
669 "limit": limit,
546 "max": maxrev,
670 "max": maxrev,
547 "min": minrev,
671 "min": minrev,
548 "merge": merge,
672 "merge": merge,
549 "modifies": modifies,
673 "modifies": modifies,
550 "id": node,
674 "id": node,
551 "outgoing": outgoing,
675 "outgoing": outgoing,
552 "p1": p1,
676 "p1": p1,
553 "p2": p2,
677 "p2": p2,
554 "parents": parents,
678 "parents": parents,
555 "present": present,
679 "present": present,
556 "removes": removes,
680 "removes": removes,
557 "reverse": reverse,
681 "reverse": reverse,
558 "rev": rev,
682 "rev": rev,
559 "roots": roots,
683 "roots": roots,
560 "sort": sort,
684 "sort": sort,
561 "tag": tag,
685 "tag": tag,
562 "tagged": tag,
686 "tagged": tagged,
563 "user": author,
687 "user": user,
564 }
688 }
565
689
566 methods = {
690 methods = {
567 "range": rangeset,
691 "range": rangeset,
568 "string": stringset,
692 "string": stringset,
569 "symbol": symbolset,
693 "symbol": symbolset,
570 "and": andset,
694 "and": andset,
571 "or": orset,
695 "or": orset,
572 "not": notset,
696 "not": notset,
573 "list": listset,
697 "list": listset,
574 "func": func,
698 "func": func,
575 }
699 }
576
700
577 def optimize(x, small):
701 def optimize(x, small):
578 if x == None:
702 if x == None:
579 return 0, x
703 return 0, x
580
704
581 smallbonus = 1
705 smallbonus = 1
582 if small:
706 if small:
583 smallbonus = .5
707 smallbonus = .5
584
708
585 op = x[0]
709 op = x[0]
586 if op == 'minus':
710 if op == 'minus':
587 return optimize(('and', x[1], ('not', x[2])), small)
711 return optimize(('and', x[1], ('not', x[2])), small)
588 elif op == 'dagrange':
712 elif op == 'dagrange':
589 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
713 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
590 ('func', ('symbol', 'ancestors'), x[2])), small)
714 ('func', ('symbol', 'ancestors'), x[2])), small)
591 elif op == 'dagrangepre':
715 elif op == 'dagrangepre':
592 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
716 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
593 elif op == 'dagrangepost':
717 elif op == 'dagrangepost':
594 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
718 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
595 elif op == 'rangepre':
719 elif op == 'rangepre':
596 return optimize(('range', ('string', '0'), x[1]), small)
720 return optimize(('range', ('string', '0'), x[1]), small)
597 elif op == 'rangepost':
721 elif op == 'rangepost':
598 return optimize(('range', x[1], ('string', 'tip')), small)
722 return optimize(('range', x[1], ('string', 'tip')), small)
599 elif op == 'negate':
723 elif op == 'negate':
600 return optimize(('string',
724 return optimize(('string',
601 '-' + getstring(x[1], _("can't negate that"))), small)
725 '-' + getstring(x[1], _("can't negate that"))), small)
602 elif op in 'string symbol negate':
726 elif op in 'string symbol negate':
603 return smallbonus, x # single revisions are small
727 return smallbonus, x # single revisions are small
604 elif op == 'and' or op == 'dagrange':
728 elif op == 'and' or op == 'dagrange':
605 wa, ta = optimize(x[1], True)
729 wa, ta = optimize(x[1], True)
606 wb, tb = optimize(x[2], True)
730 wb, tb = optimize(x[2], True)
607 w = min(wa, wb)
731 w = min(wa, wb)
608 if wa > wb:
732 if wa > wb:
609 return w, (op, tb, ta)
733 return w, (op, tb, ta)
610 return w, (op, ta, tb)
734 return w, (op, ta, tb)
611 elif op == 'or':
735 elif op == 'or':
612 wa, ta = optimize(x[1], False)
736 wa, ta = optimize(x[1], False)
613 wb, tb = optimize(x[2], False)
737 wb, tb = optimize(x[2], False)
614 if wb < wa:
738 if wb < wa:
615 wb, wa = wa, wb
739 wb, wa = wa, wb
616 return max(wa, wb), (op, ta, tb)
740 return max(wa, wb), (op, ta, tb)
617 elif op == 'not':
741 elif op == 'not':
618 o = optimize(x[1], not small)
742 o = optimize(x[1], not small)
619 return o[0], (op, o[1])
743 return o[0], (op, o[1])
620 elif op == 'group':
744 elif op == 'group':
621 return optimize(x[1], small)
745 return optimize(x[1], small)
622 elif op in 'range list':
746 elif op in 'range list':
623 wa, ta = optimize(x[1], small)
747 wa, ta = optimize(x[1], small)
624 wb, tb = optimize(x[2], small)
748 wb, tb = optimize(x[2], small)
625 return wa + wb, (op, ta, tb)
749 return wa + wb, (op, ta, tb)
626 elif op == 'func':
750 elif op == 'func':
627 f = getstring(x[1], _("not a symbol"))
751 f = getstring(x[1], _("not a symbol"))
628 wa, ta = optimize(x[2], small)
752 wa, ta = optimize(x[2], small)
629 if f in "grep date user author keyword branch file outgoing":
753 if f in "grep date user author keyword branch file outgoing":
630 w = 10 # slow
754 w = 10 # slow
631 elif f in "modifies adds removes":
755 elif f in "modifies adds removes":
632 w = 30 # slower
756 w = 30 # slower
633 elif f == "contains":
757 elif f == "contains":
634 w = 100 # very slow
758 w = 100 # very slow
635 elif f == "ancestor":
759 elif f == "ancestor":
636 w = 1 * smallbonus
760 w = 1 * smallbonus
637 elif f == "reverse limit":
761 elif f == "reverse limit":
638 w = 0
762 w = 0
639 elif f in "sort":
763 elif f in "sort":
640 w = 10 # assume most sorts look at changelog
764 w = 10 # assume most sorts look at changelog
641 else:
765 else:
642 w = 1
766 w = 1
643 return w + wa, (op, x[1], ta)
767 return w + wa, (op, x[1], ta)
644 return 1, x
768 return 1, x
645
769
646 parse = parser.parser(tokenize, elements).parse
770 parse = parser.parser(tokenize, elements).parse
647
771
648 def match(spec):
772 def match(spec):
649 if not spec:
773 if not spec:
650 raise error.ParseError(_("empty query"))
774 raise error.ParseError(_("empty query"))
651 tree = parse(spec)
775 tree = parse(spec)
652 weight, tree = optimize(tree, True)
776 weight, tree = optimize(tree, True)
653 def mfunc(repo, subset):
777 def mfunc(repo, subset):
654 return getset(repo, subset, tree)
778 return getset(repo, subset, tree)
655 return mfunc
779 return mfunc
780
781 def makedoc(topic, doc):
782 """Generate and include predicates help in revsets topic."""
783 predicates = []
784 for name in sorted(symbols):
785 text = symbols[name].__doc__
786 if not text:
787 continue
788 lines = text.splitlines()
789 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
790 predicates.append('\n'.join(lines))
791 predicates = '\n'.join(predicates)
792 doc = doc.replace('.. predicatesmarker', predicates)
793 return doc
General Comments 0
You need to be logged in to leave comments. Login now