##// END OF EJS Templates
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
Peter Arrenbrecht -
r14213:30273f0c default
parent child Browse files
Show More
@@ -1,4973 +1,4975 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms 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, bin, nullid, nullrev, short
8 from node import hex, bin, 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, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, 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, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser, context, simplemerge
17 import dagparser, context, simplemerge
18 import random, setdiscovery, treediscovery, dagutil
18 import random, setdiscovery, treediscovery, dagutil
19
19
20 # Commands start here, listed alphabetically
20 # Commands start here, listed alphabetically
21
21
22 def add(ui, repo, *pats, **opts):
22 def add(ui, repo, *pats, **opts):
23 """add the specified files on the next commit
23 """add the specified files on the next commit
24
24
25 Schedule files to be version controlled and added to the
25 Schedule files to be version controlled and added to the
26 repository.
26 repository.
27
27
28 The files will be added to the repository at the next commit. To
28 The files will be added to the repository at the next commit. To
29 undo an add before that, see :hg:`forget`.
29 undo an add before that, see :hg:`forget`.
30
30
31 If no names are given, add all files to the repository.
31 If no names are given, add all files to the repository.
32
32
33 .. container:: verbose
33 .. container:: verbose
34
34
35 An example showing how new (unknown) files are added
35 An example showing how new (unknown) files are added
36 automatically by :hg:`add`::
36 automatically by :hg:`add`::
37
37
38 $ ls
38 $ ls
39 foo.c
39 foo.c
40 $ hg status
40 $ hg status
41 ? foo.c
41 ? foo.c
42 $ hg add
42 $ hg add
43 adding foo.c
43 adding foo.c
44 $ hg status
44 $ hg status
45 A foo.c
45 A foo.c
46
46
47 Returns 0 if all files are successfully added.
47 Returns 0 if all files are successfully added.
48 """
48 """
49
49
50 m = cmdutil.match(repo, pats, opts)
50 m = cmdutil.match(repo, pats, opts)
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
52 opts.get('subrepos'), prefix="")
52 opts.get('subrepos'), prefix="")
53 return rejected and 1 or 0
53 return rejected and 1 or 0
54
54
55 def addremove(ui, repo, *pats, **opts):
55 def addremove(ui, repo, *pats, **opts):
56 """add all new files, delete all missing files
56 """add all new files, delete all missing files
57
57
58 Add all new files and remove all missing files from the
58 Add all new files and remove all missing files from the
59 repository.
59 repository.
60
60
61 New files are ignored if they match any of the patterns in
61 New files are ignored if they match any of the patterns in
62 ``.hgignore``. As with add, these changes take effect at the next
62 ``.hgignore``. As with add, these changes take effect at the next
63 commit.
63 commit.
64
64
65 Use the -s/--similarity option to detect renamed files. With a
65 Use the -s/--similarity option to detect renamed files. With a
66 parameter greater than 0, this compares every removed file with
66 parameter greater than 0, this compares every removed file with
67 every added file and records those similar enough as renames. This
67 every added file and records those similar enough as renames. This
68 option takes a percentage between 0 (disabled) and 100 (files must
68 option takes a percentage between 0 (disabled) and 100 (files must
69 be identical) as its parameter. Detecting renamed files this way
69 be identical) as its parameter. Detecting renamed files this way
70 can be expensive. After using this option, :hg:`status -C` can be
70 can be expensive. After using this option, :hg:`status -C` can be
71 used to check which files were identified as moved or renamed.
71 used to check which files were identified as moved or renamed.
72
72
73 Returns 0 if all files are successfully added.
73 Returns 0 if all files are successfully added.
74 """
74 """
75 try:
75 try:
76 sim = float(opts.get('similarity') or 100)
76 sim = float(opts.get('similarity') or 100)
77 except ValueError:
77 except ValueError:
78 raise util.Abort(_('similarity must be a number'))
78 raise util.Abort(_('similarity must be a number'))
79 if sim < 0 or sim > 100:
79 if sim < 0 or sim > 100:
80 raise util.Abort(_('similarity must be between 0 and 100'))
80 raise util.Abort(_('similarity must be between 0 and 100'))
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
82
82
83 def annotate(ui, repo, *pats, **opts):
83 def annotate(ui, repo, *pats, **opts):
84 """show changeset information by line for each file
84 """show changeset information by line for each file
85
85
86 List changes in files, showing the revision id responsible for
86 List changes in files, showing the revision id responsible for
87 each line
87 each line
88
88
89 This command is useful for discovering when a change was made and
89 This command is useful for discovering when a change was made and
90 by whom.
90 by whom.
91
91
92 Without the -a/--text option, annotate will avoid processing files
92 Without the -a/--text option, annotate will avoid processing files
93 it detects as binary. With -a, annotate will annotate the file
93 it detects as binary. With -a, annotate will annotate the file
94 anyway, although the results will probably be neither useful
94 anyway, although the results will probably be neither useful
95 nor desirable.
95 nor desirable.
96
96
97 Returns 0 on success.
97 Returns 0 on success.
98 """
98 """
99 if opts.get('follow'):
99 if opts.get('follow'):
100 # --follow is deprecated and now just an alias for -f/--file
100 # --follow is deprecated and now just an alias for -f/--file
101 # to mimic the behavior of Mercurial before version 1.5
101 # to mimic the behavior of Mercurial before version 1.5
102 opts['file'] = 1
102 opts['file'] = 1
103
103
104 datefunc = ui.quiet and util.shortdate or util.datestr
104 datefunc = ui.quiet and util.shortdate or util.datestr
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
106
106
107 if not pats:
107 if not pats:
108 raise util.Abort(_('at least one filename or pattern is required'))
108 raise util.Abort(_('at least one filename or pattern is required'))
109
109
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
111 ('number', lambda x: str(x[0].rev())),
111 ('number', lambda x: str(x[0].rev())),
112 ('changeset', lambda x: short(x[0].node())),
112 ('changeset', lambda x: short(x[0].node())),
113 ('date', getdate),
113 ('date', getdate),
114 ('file', lambda x: x[0].path()),
114 ('file', lambda x: x[0].path()),
115 ]
115 ]
116
116
117 if (not opts.get('user') and not opts.get('changeset')
117 if (not opts.get('user') and not opts.get('changeset')
118 and not opts.get('date') and not opts.get('file')):
118 and not opts.get('date') and not opts.get('file')):
119 opts['number'] = 1
119 opts['number'] = 1
120
120
121 linenumber = opts.get('line_number') is not None
121 linenumber = opts.get('line_number') is not None
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
124
124
125 funcmap = [func for op, func in opmap if opts.get(op)]
125 funcmap = [func for op, func in opmap if opts.get(op)]
126 if linenumber:
126 if linenumber:
127 lastfunc = funcmap[-1]
127 lastfunc = funcmap[-1]
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
129
129
130 def bad(x, y):
130 def bad(x, y):
131 raise util.Abort("%s: %s" % (x, y))
131 raise util.Abort("%s: %s" % (x, y))
132
132
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
134 m = cmdutil.match(repo, pats, opts)
134 m = cmdutil.match(repo, pats, opts)
135 m.bad = bad
135 m.bad = bad
136 follow = not opts.get('no_follow')
136 follow = not opts.get('no_follow')
137 for abs in ctx.walk(m):
137 for abs in ctx.walk(m):
138 fctx = ctx[abs]
138 fctx = ctx[abs]
139 if not opts.get('text') and util.binary(fctx.data()):
139 if not opts.get('text') and util.binary(fctx.data()):
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
141 continue
141 continue
142
142
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
144 pieces = []
144 pieces = []
145
145
146 for f in funcmap:
146 for f in funcmap:
147 l = [f(n) for n, dummy in lines]
147 l = [f(n) for n, dummy in lines]
148 if l:
148 if l:
149 sized = [(x, encoding.colwidth(x)) for x in l]
149 sized = [(x, encoding.colwidth(x)) for x in l]
150 ml = max([w for x, w in sized])
150 ml = max([w for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
152
152
153 if pieces:
153 if pieces:
154 for p, l in zip(zip(*pieces), lines):
154 for p, l in zip(zip(*pieces), lines):
155 ui.write("%s: %s" % (" ".join(p), l[1]))
155 ui.write("%s: %s" % (" ".join(p), l[1]))
156
156
157 def archive(ui, repo, dest, **opts):
157 def archive(ui, repo, dest, **opts):
158 '''create an unversioned archive of a repository revision
158 '''create an unversioned archive of a repository revision
159
159
160 By default, the revision used is the parent of the working
160 By default, the revision used is the parent of the working
161 directory; use -r/--rev to specify a different revision.
161 directory; use -r/--rev to specify a different revision.
162
162
163 The archive type is automatically detected based on file
163 The archive type is automatically detected based on file
164 extension (or override using -t/--type).
164 extension (or override using -t/--type).
165
165
166 Valid types are:
166 Valid types are:
167
167
168 :``files``: a directory full of files (default)
168 :``files``: a directory full of files (default)
169 :``tar``: tar archive, uncompressed
169 :``tar``: tar archive, uncompressed
170 :``tbz2``: tar archive, compressed using bzip2
170 :``tbz2``: tar archive, compressed using bzip2
171 :``tgz``: tar archive, compressed using gzip
171 :``tgz``: tar archive, compressed using gzip
172 :``uzip``: zip archive, uncompressed
172 :``uzip``: zip archive, uncompressed
173 :``zip``: zip archive, compressed using deflate
173 :``zip``: zip archive, compressed using deflate
174
174
175 The exact name of the destination archive or directory is given
175 The exact name of the destination archive or directory is given
176 using a format string; see :hg:`help export` for details.
176 using a format string; see :hg:`help export` for details.
177
177
178 Each member added to an archive file has a directory prefix
178 Each member added to an archive file has a directory prefix
179 prepended. Use -p/--prefix to specify a format string for the
179 prepended. Use -p/--prefix to specify a format string for the
180 prefix. The default is the basename of the archive, with suffixes
180 prefix. The default is the basename of the archive, with suffixes
181 removed.
181 removed.
182
182
183 Returns 0 on success.
183 Returns 0 on success.
184 '''
184 '''
185
185
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
187 if not ctx:
187 if not ctx:
188 raise util.Abort(_('no working directory: please specify a revision'))
188 raise util.Abort(_('no working directory: please specify a revision'))
189 node = ctx.node()
189 node = ctx.node()
190 dest = cmdutil.make_filename(repo, dest, node)
190 dest = cmdutil.make_filename(repo, dest, node)
191 if os.path.realpath(dest) == repo.root:
191 if os.path.realpath(dest) == repo.root:
192 raise util.Abort(_('repository root cannot be destination'))
192 raise util.Abort(_('repository root cannot be destination'))
193
193
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
195 prefix = opts.get('prefix')
195 prefix = opts.get('prefix')
196
196
197 if dest == '-':
197 if dest == '-':
198 if kind == 'files':
198 if kind == 'files':
199 raise util.Abort(_('cannot archive plain files to stdout'))
199 raise util.Abort(_('cannot archive plain files to stdout'))
200 dest = sys.stdout
200 dest = sys.stdout
201 if not prefix:
201 if not prefix:
202 prefix = os.path.basename(repo.root) + '-%h'
202 prefix = os.path.basename(repo.root) + '-%h'
203
203
204 prefix = cmdutil.make_filename(repo, prefix, node)
204 prefix = cmdutil.make_filename(repo, prefix, node)
205 matchfn = cmdutil.match(repo, [], opts)
205 matchfn = cmdutil.match(repo, [], opts)
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
207 matchfn, prefix, subrepos=opts.get('subrepos'))
207 matchfn, prefix, subrepos=opts.get('subrepos'))
208
208
209 def backout(ui, repo, node=None, rev=None, **opts):
209 def backout(ui, repo, node=None, rev=None, **opts):
210 '''reverse effect of earlier changeset
210 '''reverse effect of earlier changeset
211
211
212 Prepare a new changeset with the effect of REV undone in the
212 Prepare a new changeset with the effect of REV undone in the
213 current working directory.
213 current working directory.
214
214
215 If REV is the parent of the working directory, then this new changeset
215 If REV is the parent of the working directory, then this new changeset
216 is committed automatically. Otherwise, hg needs to merge the
216 is committed automatically. Otherwise, hg needs to merge the
217 changes and the merged result is left uncommitted.
217 changes and the merged result is left uncommitted.
218
218
219 By default, the pending changeset will have one parent,
219 By default, the pending changeset will have one parent,
220 maintaining a linear history. With --merge, the pending changeset
220 maintaining a linear history. With --merge, the pending changeset
221 will instead have two parents: the old parent of the working
221 will instead have two parents: the old parent of the working
222 directory and a new child of REV that simply undoes REV.
222 directory and a new child of REV that simply undoes REV.
223
223
224 Before version 1.7, the behavior without --merge was equivalent to
224 Before version 1.7, the behavior without --merge was equivalent to
225 specifying --merge followed by :hg:`update --clean .` to cancel
225 specifying --merge followed by :hg:`update --clean .` to cancel
226 the merge and leave the child of REV as a head to be merged
226 the merge and leave the child of REV as a head to be merged
227 separately.
227 separately.
228
228
229 See :hg:`help dates` for a list of formats valid for -d/--date.
229 See :hg:`help dates` for a list of formats valid for -d/--date.
230
230
231 Returns 0 on success.
231 Returns 0 on success.
232 '''
232 '''
233 if rev and node:
233 if rev and node:
234 raise util.Abort(_("please specify just one revision"))
234 raise util.Abort(_("please specify just one revision"))
235
235
236 if not rev:
236 if not rev:
237 rev = node
237 rev = node
238
238
239 if not rev:
239 if not rev:
240 raise util.Abort(_("please specify a revision to backout"))
240 raise util.Abort(_("please specify a revision to backout"))
241
241
242 date = opts.get('date')
242 date = opts.get('date')
243 if date:
243 if date:
244 opts['date'] = util.parsedate(date)
244 opts['date'] = util.parsedate(date)
245
245
246 cmdutil.bail_if_changed(repo)
246 cmdutil.bail_if_changed(repo)
247 node = cmdutil.revsingle(repo, rev).node()
247 node = cmdutil.revsingle(repo, rev).node()
248
248
249 op1, op2 = repo.dirstate.parents()
249 op1, op2 = repo.dirstate.parents()
250 a = repo.changelog.ancestor(op1, node)
250 a = repo.changelog.ancestor(op1, node)
251 if a != node:
251 if a != node:
252 raise util.Abort(_('cannot backout change on a different branch'))
252 raise util.Abort(_('cannot backout change on a different branch'))
253
253
254 p1, p2 = repo.changelog.parents(node)
254 p1, p2 = repo.changelog.parents(node)
255 if p1 == nullid:
255 if p1 == nullid:
256 raise util.Abort(_('cannot backout a change with no parents'))
256 raise util.Abort(_('cannot backout a change with no parents'))
257 if p2 != nullid:
257 if p2 != nullid:
258 if not opts.get('parent'):
258 if not opts.get('parent'):
259 raise util.Abort(_('cannot backout a merge changeset without '
259 raise util.Abort(_('cannot backout a merge changeset without '
260 '--parent'))
260 '--parent'))
261 p = repo.lookup(opts['parent'])
261 p = repo.lookup(opts['parent'])
262 if p not in (p1, p2):
262 if p not in (p1, p2):
263 raise util.Abort(_('%s is not a parent of %s') %
263 raise util.Abort(_('%s is not a parent of %s') %
264 (short(p), short(node)))
264 (short(p), short(node)))
265 parent = p
265 parent = p
266 else:
266 else:
267 if opts.get('parent'):
267 if opts.get('parent'):
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
269 parent = p1
269 parent = p1
270
270
271 # the backout should appear on the same branch
271 # the backout should appear on the same branch
272 branch = repo.dirstate.branch()
272 branch = repo.dirstate.branch()
273 hg.clean(repo, node, show_stats=False)
273 hg.clean(repo, node, show_stats=False)
274 repo.dirstate.setbranch(branch)
274 repo.dirstate.setbranch(branch)
275 revert_opts = opts.copy()
275 revert_opts = opts.copy()
276 revert_opts['date'] = None
276 revert_opts['date'] = None
277 revert_opts['all'] = True
277 revert_opts['all'] = True
278 revert_opts['rev'] = hex(parent)
278 revert_opts['rev'] = hex(parent)
279 revert_opts['no_backup'] = None
279 revert_opts['no_backup'] = None
280 revert(ui, repo, **revert_opts)
280 revert(ui, repo, **revert_opts)
281 if not opts.get('merge') and op1 != node:
281 if not opts.get('merge') and op1 != node:
282 try:
282 try:
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
284 return hg.update(repo, op1)
284 return hg.update(repo, op1)
285 finally:
285 finally:
286 ui.setconfig('ui', 'forcemerge', '')
286 ui.setconfig('ui', 'forcemerge', '')
287
287
288 commit_opts = opts.copy()
288 commit_opts = opts.copy()
289 commit_opts['addremove'] = False
289 commit_opts['addremove'] = False
290 if not commit_opts['message'] and not commit_opts['logfile']:
290 if not commit_opts['message'] and not commit_opts['logfile']:
291 # we don't translate commit messages
291 # we don't translate commit messages
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
293 commit_opts['force_editor'] = True
293 commit_opts['force_editor'] = True
294 commit(ui, repo, **commit_opts)
294 commit(ui, repo, **commit_opts)
295 def nice(node):
295 def nice(node):
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
297 ui.status(_('changeset %s backs out changeset %s\n') %
297 ui.status(_('changeset %s backs out changeset %s\n') %
298 (nice(repo.changelog.tip()), nice(node)))
298 (nice(repo.changelog.tip()), nice(node)))
299 if opts.get('merge') and op1 != node:
299 if opts.get('merge') and op1 != node:
300 hg.clean(repo, op1, show_stats=False)
300 hg.clean(repo, op1, show_stats=False)
301 ui.status(_('merging with changeset %s\n')
301 ui.status(_('merging with changeset %s\n')
302 % nice(repo.changelog.tip()))
302 % nice(repo.changelog.tip()))
303 try:
303 try:
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
305 return hg.merge(repo, hex(repo.changelog.tip()))
305 return hg.merge(repo, hex(repo.changelog.tip()))
306 finally:
306 finally:
307 ui.setconfig('ui', 'forcemerge', '')
307 ui.setconfig('ui', 'forcemerge', '')
308 return 0
308 return 0
309
309
310 def bisect(ui, repo, rev=None, extra=None, command=None,
310 def bisect(ui, repo, rev=None, extra=None, command=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
312 noupdate=None):
312 noupdate=None):
313 """subdivision search of changesets
313 """subdivision search of changesets
314
314
315 This command helps to find changesets which introduce problems. To
315 This command helps to find changesets which introduce problems. To
316 use, mark the earliest changeset you know exhibits the problem as
316 use, mark the earliest changeset you know exhibits the problem as
317 bad, then mark the latest changeset which is free from the problem
317 bad, then mark the latest changeset which is free from the problem
318 as good. Bisect will update your working directory to a revision
318 as good. Bisect will update your working directory to a revision
319 for testing (unless the -U/--noupdate option is specified). Once
319 for testing (unless the -U/--noupdate option is specified). Once
320 you have performed tests, mark the working directory as good or
320 you have performed tests, mark the working directory as good or
321 bad, and bisect will either update to another candidate changeset
321 bad, and bisect will either update to another candidate changeset
322 or announce that it has found the bad revision.
322 or announce that it has found the bad revision.
323
323
324 As a shortcut, you can also use the revision argument to mark a
324 As a shortcut, you can also use the revision argument to mark a
325 revision as good or bad without checking it out first.
325 revision as good or bad without checking it out first.
326
326
327 If you supply a command, it will be used for automatic bisection.
327 If you supply a command, it will be used for automatic bisection.
328 Its exit status will be used to mark revisions as good or bad:
328 Its exit status will be used to mark revisions as good or bad:
329 status 0 means good, 125 means to skip the revision, 127
329 status 0 means good, 125 means to skip the revision, 127
330 (command not found) will abort the bisection, and any other
330 (command not found) will abort the bisection, and any other
331 non-zero exit status means the revision is bad.
331 non-zero exit status means the revision is bad.
332
332
333 Returns 0 on success.
333 Returns 0 on success.
334 """
334 """
335 def extendbisectrange(nodes, good):
335 def extendbisectrange(nodes, good):
336 # bisect is incomplete when it ends on a merge node and
336 # bisect is incomplete when it ends on a merge node and
337 # one of the parent was not checked.
337 # one of the parent was not checked.
338 parents = repo[nodes[0]].parents()
338 parents = repo[nodes[0]].parents()
339 if len(parents) > 1:
339 if len(parents) > 1:
340 side = good and state['bad'] or state['good']
340 side = good and state['bad'] or state['good']
341 num = len(set(i.node() for i in parents) & set(side))
341 num = len(set(i.node() for i in parents) & set(side))
342 if num == 1:
342 if num == 1:
343 return parents[0].ancestor(parents[1])
343 return parents[0].ancestor(parents[1])
344 return None
344 return None
345
345
346 def print_result(nodes, good):
346 def print_result(nodes, good):
347 displayer = cmdutil.show_changeset(ui, repo, {})
347 displayer = cmdutil.show_changeset(ui, repo, {})
348 if len(nodes) == 1:
348 if len(nodes) == 1:
349 # narrowed it down to a single revision
349 # narrowed it down to a single revision
350 if good:
350 if good:
351 ui.write(_("The first good revision is:\n"))
351 ui.write(_("The first good revision is:\n"))
352 else:
352 else:
353 ui.write(_("The first bad revision is:\n"))
353 ui.write(_("The first bad revision is:\n"))
354 displayer.show(repo[nodes[0]])
354 displayer.show(repo[nodes[0]])
355 extendnode = extendbisectrange(nodes, good)
355 extendnode = extendbisectrange(nodes, good)
356 if extendnode is not None:
356 if extendnode is not None:
357 ui.write(_('Not all ancestors of this changeset have been'
357 ui.write(_('Not all ancestors of this changeset have been'
358 ' checked.\nUse bisect --extend to continue the '
358 ' checked.\nUse bisect --extend to continue the '
359 'bisection from\nthe common ancestor, %s.\n')
359 'bisection from\nthe common ancestor, %s.\n')
360 % extendnode)
360 % extendnode)
361 else:
361 else:
362 # multiple possible revisions
362 # multiple possible revisions
363 if good:
363 if good:
364 ui.write(_("Due to skipped revisions, the first "
364 ui.write(_("Due to skipped revisions, the first "
365 "good revision could be any of:\n"))
365 "good revision could be any of:\n"))
366 else:
366 else:
367 ui.write(_("Due to skipped revisions, the first "
367 ui.write(_("Due to skipped revisions, the first "
368 "bad revision could be any of:\n"))
368 "bad revision could be any of:\n"))
369 for n in nodes:
369 for n in nodes:
370 displayer.show(repo[n])
370 displayer.show(repo[n])
371 displayer.close()
371 displayer.close()
372
372
373 def check_state(state, interactive=True):
373 def check_state(state, interactive=True):
374 if not state['good'] or not state['bad']:
374 if not state['good'] or not state['bad']:
375 if (good or bad or skip or reset) and interactive:
375 if (good or bad or skip or reset) and interactive:
376 return
376 return
377 if not state['good']:
377 if not state['good']:
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
379 else:
379 else:
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
381 return True
381 return True
382
382
383 # backward compatibility
383 # backward compatibility
384 if rev in "good bad reset init".split():
384 if rev in "good bad reset init".split():
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
386 cmd, rev, extra = rev, extra, None
386 cmd, rev, extra = rev, extra, None
387 if cmd == "good":
387 if cmd == "good":
388 good = True
388 good = True
389 elif cmd == "bad":
389 elif cmd == "bad":
390 bad = True
390 bad = True
391 else:
391 else:
392 reset = True
392 reset = True
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
394 raise util.Abort(_('incompatible arguments'))
394 raise util.Abort(_('incompatible arguments'))
395
395
396 if reset:
396 if reset:
397 p = repo.join("bisect.state")
397 p = repo.join("bisect.state")
398 if os.path.exists(p):
398 if os.path.exists(p):
399 os.unlink(p)
399 os.unlink(p)
400 return
400 return
401
401
402 state = hbisect.load_state(repo)
402 state = hbisect.load_state(repo)
403
403
404 if command:
404 if command:
405 changesets = 1
405 changesets = 1
406 try:
406 try:
407 while changesets:
407 while changesets:
408 # update state
408 # update state
409 status = util.system(command)
409 status = util.system(command)
410 if status == 125:
410 if status == 125:
411 transition = "skip"
411 transition = "skip"
412 elif status == 0:
412 elif status == 0:
413 transition = "good"
413 transition = "good"
414 # status < 0 means process was killed
414 # status < 0 means process was killed
415 elif status == 127:
415 elif status == 127:
416 raise util.Abort(_("failed to execute %s") % command)
416 raise util.Abort(_("failed to execute %s") % command)
417 elif status < 0:
417 elif status < 0:
418 raise util.Abort(_("%s killed") % command)
418 raise util.Abort(_("%s killed") % command)
419 else:
419 else:
420 transition = "bad"
420 transition = "bad"
421 ctx = cmdutil.revsingle(repo, rev)
421 ctx = cmdutil.revsingle(repo, rev)
422 rev = None # clear for future iterations
422 rev = None # clear for future iterations
423 state[transition].append(ctx.node())
423 state[transition].append(ctx.node())
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
425 check_state(state, interactive=False)
425 check_state(state, interactive=False)
426 # bisect
426 # bisect
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
428 # update to next check
428 # update to next check
429 cmdutil.bail_if_changed(repo)
429 cmdutil.bail_if_changed(repo)
430 hg.clean(repo, nodes[0], show_stats=False)
430 hg.clean(repo, nodes[0], show_stats=False)
431 finally:
431 finally:
432 hbisect.save_state(repo, state)
432 hbisect.save_state(repo, state)
433 print_result(nodes, good)
433 print_result(nodes, good)
434 return
434 return
435
435
436 # update state
436 # update state
437
437
438 if rev:
438 if rev:
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
440 else:
440 else:
441 nodes = [repo.lookup('.')]
441 nodes = [repo.lookup('.')]
442
442
443 if good or bad or skip:
443 if good or bad or skip:
444 if good:
444 if good:
445 state['good'] += nodes
445 state['good'] += nodes
446 elif bad:
446 elif bad:
447 state['bad'] += nodes
447 state['bad'] += nodes
448 elif skip:
448 elif skip:
449 state['skip'] += nodes
449 state['skip'] += nodes
450 hbisect.save_state(repo, state)
450 hbisect.save_state(repo, state)
451
451
452 if not check_state(state):
452 if not check_state(state):
453 return
453 return
454
454
455 # actually bisect
455 # actually bisect
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
457 if extend:
457 if extend:
458 if not changesets:
458 if not changesets:
459 extendnode = extendbisectrange(nodes, good)
459 extendnode = extendbisectrange(nodes, good)
460 if extendnode is not None:
460 if extendnode is not None:
461 ui.write(_("Extending search to changeset %d:%s\n"
461 ui.write(_("Extending search to changeset %d:%s\n"
462 % (extendnode.rev(), extendnode)))
462 % (extendnode.rev(), extendnode)))
463 if noupdate:
463 if noupdate:
464 return
464 return
465 cmdutil.bail_if_changed(repo)
465 cmdutil.bail_if_changed(repo)
466 return hg.clean(repo, extendnode.node())
466 return hg.clean(repo, extendnode.node())
467 raise util.Abort(_("nothing to extend"))
467 raise util.Abort(_("nothing to extend"))
468
468
469 if changesets == 0:
469 if changesets == 0:
470 print_result(nodes, good)
470 print_result(nodes, good)
471 else:
471 else:
472 assert len(nodes) == 1 # only a single node can be tested next
472 assert len(nodes) == 1 # only a single node can be tested next
473 node = nodes[0]
473 node = nodes[0]
474 # compute the approximate number of remaining tests
474 # compute the approximate number of remaining tests
475 tests, size = 0, 2
475 tests, size = 0, 2
476 while size <= changesets:
476 while size <= changesets:
477 tests, size = tests + 1, size * 2
477 tests, size = tests + 1, size * 2
478 rev = repo.changelog.rev(node)
478 rev = repo.changelog.rev(node)
479 ui.write(_("Testing changeset %d:%s "
479 ui.write(_("Testing changeset %d:%s "
480 "(%d changesets remaining, ~%d tests)\n")
480 "(%d changesets remaining, ~%d tests)\n")
481 % (rev, short(node), changesets, tests))
481 % (rev, short(node), changesets, tests))
482 if not noupdate:
482 if not noupdate:
483 cmdutil.bail_if_changed(repo)
483 cmdutil.bail_if_changed(repo)
484 return hg.clean(repo, node)
484 return hg.clean(repo, node)
485
485
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
487 rename=None, inactive=False):
487 rename=None, inactive=False):
488 '''track a line of development with movable markers
488 '''track a line of development with movable markers
489
489
490 Bookmarks are pointers to certain commits that move when
490 Bookmarks are pointers to certain commits that move when
491 committing. Bookmarks are local. They can be renamed, copied and
491 committing. Bookmarks are local. They can be renamed, copied and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
493 :hg:`update` to merge and update respectively to a given bookmark.
493 :hg:`update` to merge and update respectively to a given bookmark.
494
494
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
496 directory's parent revision with the given name. If you specify
496 directory's parent revision with the given name. If you specify
497 a revision using -r REV (where REV may be an existing bookmark),
497 a revision using -r REV (where REV may be an existing bookmark),
498 the bookmark is assigned to that revision.
498 the bookmark is assigned to that revision.
499
499
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
501 push` and :hg:`help pull`). This requires both the local and remote
501 push` and :hg:`help pull`). This requires both the local and remote
502 repositories to support bookmarks. For versions prior to 1.8, this means
502 repositories to support bookmarks. For versions prior to 1.8, this means
503 the bookmarks extension must be enabled.
503 the bookmarks extension must be enabled.
504 '''
504 '''
505 hexfn = ui.debugflag and hex or short
505 hexfn = ui.debugflag and hex or short
506 marks = repo._bookmarks
506 marks = repo._bookmarks
507 cur = repo.changectx('.').node()
507 cur = repo.changectx('.').node()
508
508
509 if rename:
509 if rename:
510 if rename not in marks:
510 if rename not in marks:
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
512 if mark in marks and not force:
512 if mark in marks and not force:
513 raise util.Abort(_("bookmark '%s' already exists "
513 raise util.Abort(_("bookmark '%s' already exists "
514 "(use -f to force)") % mark)
514 "(use -f to force)") % mark)
515 if mark is None:
515 if mark is None:
516 raise util.Abort(_("new bookmark name required"))
516 raise util.Abort(_("new bookmark name required"))
517 marks[mark] = marks[rename]
517 marks[mark] = marks[rename]
518 if repo._bookmarkcurrent == rename and not inactive:
518 if repo._bookmarkcurrent == rename and not inactive:
519 bookmarks.setcurrent(repo, mark)
519 bookmarks.setcurrent(repo, mark)
520 del marks[rename]
520 del marks[rename]
521 bookmarks.write(repo)
521 bookmarks.write(repo)
522 return
522 return
523
523
524 if delete:
524 if delete:
525 if mark is None:
525 if mark is None:
526 raise util.Abort(_("bookmark name required"))
526 raise util.Abort(_("bookmark name required"))
527 if mark not in marks:
527 if mark not in marks:
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
529 if mark == repo._bookmarkcurrent:
529 if mark == repo._bookmarkcurrent:
530 bookmarks.setcurrent(repo, None)
530 bookmarks.setcurrent(repo, None)
531 del marks[mark]
531 del marks[mark]
532 bookmarks.write(repo)
532 bookmarks.write(repo)
533 return
533 return
534
534
535 if mark is not None:
535 if mark is not None:
536 if "\n" in mark:
536 if "\n" in mark:
537 raise util.Abort(_("bookmark name cannot contain newlines"))
537 raise util.Abort(_("bookmark name cannot contain newlines"))
538 mark = mark.strip()
538 mark = mark.strip()
539 if not mark:
539 if not mark:
540 raise util.Abort(_("bookmark names cannot consist entirely of "
540 raise util.Abort(_("bookmark names cannot consist entirely of "
541 "whitespace"))
541 "whitespace"))
542 if inactive and mark == repo._bookmarkcurrent:
542 if inactive and mark == repo._bookmarkcurrent:
543 bookmarks.setcurrent(repo, None)
543 bookmarks.setcurrent(repo, None)
544 return
544 return
545 if mark in marks and not force:
545 if mark in marks and not force:
546 raise util.Abort(_("bookmark '%s' already exists "
546 raise util.Abort(_("bookmark '%s' already exists "
547 "(use -f to force)") % mark)
547 "(use -f to force)") % mark)
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
549 and not force):
549 and not force):
550 raise util.Abort(
550 raise util.Abort(
551 _("a bookmark cannot have the name of an existing branch"))
551 _("a bookmark cannot have the name of an existing branch"))
552 if rev:
552 if rev:
553 marks[mark] = repo.lookup(rev)
553 marks[mark] = repo.lookup(rev)
554 else:
554 else:
555 marks[mark] = repo.changectx('.').node()
555 marks[mark] = repo.changectx('.').node()
556 if not inactive and repo.changectx('.').node() == marks[mark]:
556 if not inactive and repo.changectx('.').node() == marks[mark]:
557 bookmarks.setcurrent(repo, mark)
557 bookmarks.setcurrent(repo, mark)
558 bookmarks.write(repo)
558 bookmarks.write(repo)
559 return
559 return
560
560
561 if mark is None:
561 if mark is None:
562 if rev:
562 if rev:
563 raise util.Abort(_("bookmark name required"))
563 raise util.Abort(_("bookmark name required"))
564 if len(marks) == 0:
564 if len(marks) == 0:
565 ui.status(_("no bookmarks set\n"))
565 ui.status(_("no bookmarks set\n"))
566 else:
566 else:
567 for bmark, n in sorted(marks.iteritems()):
567 for bmark, n in sorted(marks.iteritems()):
568 current = repo._bookmarkcurrent
568 current = repo._bookmarkcurrent
569 if bmark == current and n == cur:
569 if bmark == current and n == cur:
570 prefix, label = '*', 'bookmarks.current'
570 prefix, label = '*', 'bookmarks.current'
571 else:
571 else:
572 prefix, label = ' ', ''
572 prefix, label = ' ', ''
573
573
574 if ui.quiet:
574 if ui.quiet:
575 ui.write("%s\n" % bmark, label=label)
575 ui.write("%s\n" % bmark, label=label)
576 else:
576 else:
577 ui.write(" %s %-25s %d:%s\n" % (
577 ui.write(" %s %-25s %d:%s\n" % (
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
579 label=label)
579 label=label)
580 return
580 return
581
581
582 def branch(ui, repo, label=None, **opts):
582 def branch(ui, repo, label=None, **opts):
583 """set or show the current branch name
583 """set or show the current branch name
584
584
585 With no argument, show the current branch name. With one argument,
585 With no argument, show the current branch name. With one argument,
586 set the working directory branch name (the branch will not exist
586 set the working directory branch name (the branch will not exist
587 in the repository until the next commit). Standard practice
587 in the repository until the next commit). Standard practice
588 recommends that primary development take place on the 'default'
588 recommends that primary development take place on the 'default'
589 branch.
589 branch.
590
590
591 Unless -f/--force is specified, branch will not let you set a
591 Unless -f/--force is specified, branch will not let you set a
592 branch name that already exists, even if it's inactive.
592 branch name that already exists, even if it's inactive.
593
593
594 Use -C/--clean to reset the working directory branch to that of
594 Use -C/--clean to reset the working directory branch to that of
595 the parent of the working directory, negating a previous branch
595 the parent of the working directory, negating a previous branch
596 change.
596 change.
597
597
598 Use the command :hg:`update` to switch to an existing branch. Use
598 Use the command :hg:`update` to switch to an existing branch. Use
599 :hg:`commit --close-branch` to mark this branch as closed.
599 :hg:`commit --close-branch` to mark this branch as closed.
600
600
601 Returns 0 on success.
601 Returns 0 on success.
602 """
602 """
603
603
604 if opts.get('clean'):
604 if opts.get('clean'):
605 label = repo[None].p1().branch()
605 label = repo[None].p1().branch()
606 repo.dirstate.setbranch(label)
606 repo.dirstate.setbranch(label)
607 ui.status(_('reset working directory to branch %s\n') % label)
607 ui.status(_('reset working directory to branch %s\n') % label)
608 elif label:
608 elif label:
609 if not opts.get('force') and label in repo.branchtags():
609 if not opts.get('force') and label in repo.branchtags():
610 if label not in [p.branch() for p in repo.parents()]:
610 if label not in [p.branch() for p in repo.parents()]:
611 raise util.Abort(_('a branch of the same name already exists'),
611 raise util.Abort(_('a branch of the same name already exists'),
612 hint=_("use 'hg update' to switch to it"))
612 hint=_("use 'hg update' to switch to it"))
613 repo.dirstate.setbranch(label)
613 repo.dirstate.setbranch(label)
614 ui.status(_('marked working directory as branch %s\n') % label)
614 ui.status(_('marked working directory as branch %s\n') % label)
615 else:
615 else:
616 ui.write("%s\n" % repo.dirstate.branch())
616 ui.write("%s\n" % repo.dirstate.branch())
617
617
618 def branches(ui, repo, active=False, closed=False):
618 def branches(ui, repo, active=False, closed=False):
619 """list repository named branches
619 """list repository named branches
620
620
621 List the repository's named branches, indicating which ones are
621 List the repository's named branches, indicating which ones are
622 inactive. If -c/--closed is specified, also list branches which have
622 inactive. If -c/--closed is specified, also list branches which have
623 been marked closed (see :hg:`commit --close-branch`).
623 been marked closed (see :hg:`commit --close-branch`).
624
624
625 If -a/--active is specified, only show active branches. A branch
625 If -a/--active is specified, only show active branches. A branch
626 is considered active if it contains repository heads.
626 is considered active if it contains repository heads.
627
627
628 Use the command :hg:`update` to switch to an existing branch.
628 Use the command :hg:`update` to switch to an existing branch.
629
629
630 Returns 0.
630 Returns 0.
631 """
631 """
632
632
633 hexfunc = ui.debugflag and hex or short
633 hexfunc = ui.debugflag and hex or short
634 activebranches = [repo[n].branch() for n in repo.heads()]
634 activebranches = [repo[n].branch() for n in repo.heads()]
635 def testactive(tag, node):
635 def testactive(tag, node):
636 realhead = tag in activebranches
636 realhead = tag in activebranches
637 open = node in repo.branchheads(tag, closed=False)
637 open = node in repo.branchheads(tag, closed=False)
638 return realhead and open
638 return realhead and open
639 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
639 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
640 for tag, node in repo.branchtags().items()],
640 for tag, node in repo.branchtags().items()],
641 reverse=True)
641 reverse=True)
642
642
643 for isactive, node, tag in branches:
643 for isactive, node, tag in branches:
644 if (not active) or isactive:
644 if (not active) or isactive:
645 if ui.quiet:
645 if ui.quiet:
646 ui.write("%s\n" % tag)
646 ui.write("%s\n" % tag)
647 else:
647 else:
648 hn = repo.lookup(node)
648 hn = repo.lookup(node)
649 if isactive:
649 if isactive:
650 label = 'branches.active'
650 label = 'branches.active'
651 notice = ''
651 notice = ''
652 elif hn not in repo.branchheads(tag, closed=False):
652 elif hn not in repo.branchheads(tag, closed=False):
653 if not closed:
653 if not closed:
654 continue
654 continue
655 label = 'branches.closed'
655 label = 'branches.closed'
656 notice = _(' (closed)')
656 notice = _(' (closed)')
657 else:
657 else:
658 label = 'branches.inactive'
658 label = 'branches.inactive'
659 notice = _(' (inactive)')
659 notice = _(' (inactive)')
660 if tag == repo.dirstate.branch():
660 if tag == repo.dirstate.branch():
661 label = 'branches.current'
661 label = 'branches.current'
662 rev = str(node).rjust(31 - encoding.colwidth(tag))
662 rev = str(node).rjust(31 - encoding.colwidth(tag))
663 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
663 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
664 tag = ui.label(tag, label)
664 tag = ui.label(tag, label)
665 ui.write("%s %s%s\n" % (tag, rev, notice))
665 ui.write("%s %s%s\n" % (tag, rev, notice))
666
666
667 def bundle(ui, repo, fname, dest=None, **opts):
667 def bundle(ui, repo, fname, dest=None, **opts):
668 """create a changegroup file
668 """create a changegroup file
669
669
670 Generate a compressed changegroup file collecting changesets not
670 Generate a compressed changegroup file collecting changesets not
671 known to be in another repository.
671 known to be in another repository.
672
672
673 If you omit the destination repository, then hg assumes the
673 If you omit the destination repository, then hg assumes the
674 destination will have all the nodes you specify with --base
674 destination will have all the nodes you specify with --base
675 parameters. To create a bundle containing all changesets, use
675 parameters. To create a bundle containing all changesets, use
676 -a/--all (or --base null).
676 -a/--all (or --base null).
677
677
678 You can change compression method with the -t/--type option.
678 You can change compression method with the -t/--type option.
679 The available compression methods are: none, bzip2, and
679 The available compression methods are: none, bzip2, and
680 gzip (by default, bundles are compressed using bzip2).
680 gzip (by default, bundles are compressed using bzip2).
681
681
682 The bundle file can then be transferred using conventional means
682 The bundle file can then be transferred using conventional means
683 and applied to another repository with the unbundle or pull
683 and applied to another repository with the unbundle or pull
684 command. This is useful when direct push and pull are not
684 command. This is useful when direct push and pull are not
685 available or when exporting an entire repository is undesirable.
685 available or when exporting an entire repository is undesirable.
686
686
687 Applying bundles preserves all changeset contents including
687 Applying bundles preserves all changeset contents including
688 permissions, copy/rename information, and revision history.
688 permissions, copy/rename information, and revision history.
689
689
690 Returns 0 on success, 1 if no changes found.
690 Returns 0 on success, 1 if no changes found.
691 """
691 """
692 revs = None
692 revs = None
693 if 'rev' in opts:
693 if 'rev' in opts:
694 revs = cmdutil.revrange(repo, opts['rev'])
694 revs = cmdutil.revrange(repo, opts['rev'])
695
695
696 if opts.get('all'):
696 if opts.get('all'):
697 base = ['null']
697 base = ['null']
698 else:
698 else:
699 base = cmdutil.revrange(repo, opts.get('base'))
699 base = cmdutil.revrange(repo, opts.get('base'))
700 if base:
700 if base:
701 if dest:
701 if dest:
702 raise util.Abort(_("--base is incompatible with specifying "
702 raise util.Abort(_("--base is incompatible with specifying "
703 "a destination"))
703 "a destination"))
704 common = [repo.lookup(rev) for rev in base]
704 common = [repo.lookup(rev) for rev in base]
705 heads = revs and map(repo.lookup, revs) or revs
705 else:
706 else:
706 dest = ui.expandpath(dest or 'default-push', dest or 'default')
707 dest = ui.expandpath(dest or 'default-push', dest or 'default')
707 dest, branches = hg.parseurl(dest, opts.get('branch'))
708 dest, branches = hg.parseurl(dest, opts.get('branch'))
708 other = hg.repository(hg.remoteui(repo, opts), dest)
709 other = hg.repository(hg.remoteui(repo, opts), dest)
709 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
710 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
710 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
711 heads = revs and map(repo.lookup, revs) or revs
711 common, _anyinc, _heads = inc
712 common, outheads = discovery.findcommonoutgoing(repo, other,
712
713 onlyheads=heads,
713 nodes = revs and map(repo.lookup, revs) or revs
714 force=opts.get('force'))
714 cg = repo.getbundle('bundle', common=common, heads=nodes)
715
716 cg = repo.getbundle('bundle', common=common, heads=heads)
715 if not cg:
717 if not cg:
716 ui.status(_("no changes found\n"))
718 ui.status(_("no changes found\n"))
717 return 1
719 return 1
718
720
719 bundletype = opts.get('type', 'bzip2').lower()
721 bundletype = opts.get('type', 'bzip2').lower()
720 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
722 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
721 bundletype = btypes.get(bundletype)
723 bundletype = btypes.get(bundletype)
722 if bundletype not in changegroup.bundletypes:
724 if bundletype not in changegroup.bundletypes:
723 raise util.Abort(_('unknown bundle type specified with --type'))
725 raise util.Abort(_('unknown bundle type specified with --type'))
724
726
725 changegroup.writebundle(cg, fname, bundletype)
727 changegroup.writebundle(cg, fname, bundletype)
726
728
727 def cat(ui, repo, file1, *pats, **opts):
729 def cat(ui, repo, file1, *pats, **opts):
728 """output the current or given revision of files
730 """output the current or given revision of files
729
731
730 Print the specified files as they were at the given revision. If
732 Print the specified files as they were at the given revision. If
731 no revision is given, the parent of the working directory is used,
733 no revision is given, the parent of the working directory is used,
732 or tip if no revision is checked out.
734 or tip if no revision is checked out.
733
735
734 Output may be to a file, in which case the name of the file is
736 Output may be to a file, in which case the name of the file is
735 given using a format string. The formatting rules are the same as
737 given using a format string. The formatting rules are the same as
736 for the export command, with the following additions:
738 for the export command, with the following additions:
737
739
738 :``%s``: basename of file being printed
740 :``%s``: basename of file being printed
739 :``%d``: dirname of file being printed, or '.' if in repository root
741 :``%d``: dirname of file being printed, or '.' if in repository root
740 :``%p``: root-relative path name of file being printed
742 :``%p``: root-relative path name of file being printed
741
743
742 Returns 0 on success.
744 Returns 0 on success.
743 """
745 """
744 ctx = cmdutil.revsingle(repo, opts.get('rev'))
746 ctx = cmdutil.revsingle(repo, opts.get('rev'))
745 err = 1
747 err = 1
746 m = cmdutil.match(repo, (file1,) + pats, opts)
748 m = cmdutil.match(repo, (file1,) + pats, opts)
747 for abs in ctx.walk(m):
749 for abs in ctx.walk(m):
748 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
750 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
749 data = ctx[abs].data()
751 data = ctx[abs].data()
750 if opts.get('decode'):
752 if opts.get('decode'):
751 data = repo.wwritedata(abs, data)
753 data = repo.wwritedata(abs, data)
752 fp.write(data)
754 fp.write(data)
753 fp.close()
755 fp.close()
754 err = 0
756 err = 0
755 return err
757 return err
756
758
757 def clone(ui, source, dest=None, **opts):
759 def clone(ui, source, dest=None, **opts):
758 """make a copy of an existing repository
760 """make a copy of an existing repository
759
761
760 Create a copy of an existing repository in a new directory.
762 Create a copy of an existing repository in a new directory.
761
763
762 If no destination directory name is specified, it defaults to the
764 If no destination directory name is specified, it defaults to the
763 basename of the source.
765 basename of the source.
764
766
765 The location of the source is added to the new repository's
767 The location of the source is added to the new repository's
766 ``.hg/hgrc`` file, as the default to be used for future pulls.
768 ``.hg/hgrc`` file, as the default to be used for future pulls.
767
769
768 See :hg:`help urls` for valid source format details.
770 See :hg:`help urls` for valid source format details.
769
771
770 It is possible to specify an ``ssh://`` URL as the destination, but no
772 It is possible to specify an ``ssh://`` URL as the destination, but no
771 ``.hg/hgrc`` and working directory will be created on the remote side.
773 ``.hg/hgrc`` and working directory will be created on the remote side.
772 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
774 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
773
775
774 A set of changesets (tags, or branch names) to pull may be specified
776 A set of changesets (tags, or branch names) to pull may be specified
775 by listing each changeset (tag, or branch name) with -r/--rev.
777 by listing each changeset (tag, or branch name) with -r/--rev.
776 If -r/--rev is used, the cloned repository will contain only a subset
778 If -r/--rev is used, the cloned repository will contain only a subset
777 of the changesets of the source repository. Only the set of changesets
779 of the changesets of the source repository. Only the set of changesets
778 defined by all -r/--rev options (including all their ancestors)
780 defined by all -r/--rev options (including all their ancestors)
779 will be pulled into the destination repository.
781 will be pulled into the destination repository.
780 No subsequent changesets (including subsequent tags) will be present
782 No subsequent changesets (including subsequent tags) will be present
781 in the destination.
783 in the destination.
782
784
783 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
785 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
784 local source repositories.
786 local source repositories.
785
787
786 For efficiency, hardlinks are used for cloning whenever the source
788 For efficiency, hardlinks are used for cloning whenever the source
787 and destination are on the same filesystem (note this applies only
789 and destination are on the same filesystem (note this applies only
788 to the repository data, not to the working directory). Some
790 to the repository data, not to the working directory). Some
789 filesystems, such as AFS, implement hardlinking incorrectly, but
791 filesystems, such as AFS, implement hardlinking incorrectly, but
790 do not report errors. In these cases, use the --pull option to
792 do not report errors. In these cases, use the --pull option to
791 avoid hardlinking.
793 avoid hardlinking.
792
794
793 In some cases, you can clone repositories and the working directory
795 In some cases, you can clone repositories and the working directory
794 using full hardlinks with ::
796 using full hardlinks with ::
795
797
796 $ cp -al REPO REPOCLONE
798 $ cp -al REPO REPOCLONE
797
799
798 This is the fastest way to clone, but it is not always safe. The
800 This is the fastest way to clone, but it is not always safe. The
799 operation is not atomic (making sure REPO is not modified during
801 operation is not atomic (making sure REPO is not modified during
800 the operation is up to you) and you have to make sure your editor
802 the operation is up to you) and you have to make sure your editor
801 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
803 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
802 this is not compatible with certain extensions that place their
804 this is not compatible with certain extensions that place their
803 metadata under the .hg directory, such as mq.
805 metadata under the .hg directory, such as mq.
804
806
805 Mercurial will update the working directory to the first applicable
807 Mercurial will update the working directory to the first applicable
806 revision from this list:
808 revision from this list:
807
809
808 a) null if -U or the source repository has no changesets
810 a) null if -U or the source repository has no changesets
809 b) if -u . and the source repository is local, the first parent of
811 b) if -u . and the source repository is local, the first parent of
810 the source repository's working directory
812 the source repository's working directory
811 c) the changeset specified with -u (if a branch name, this means the
813 c) the changeset specified with -u (if a branch name, this means the
812 latest head of that branch)
814 latest head of that branch)
813 d) the changeset specified with -r
815 d) the changeset specified with -r
814 e) the tipmost head specified with -b
816 e) the tipmost head specified with -b
815 f) the tipmost head specified with the url#branch source syntax
817 f) the tipmost head specified with the url#branch source syntax
816 g) the tipmost head of the default branch
818 g) the tipmost head of the default branch
817 h) tip
819 h) tip
818
820
819 Returns 0 on success.
821 Returns 0 on success.
820 """
822 """
821 if opts.get('noupdate') and opts.get('updaterev'):
823 if opts.get('noupdate') and opts.get('updaterev'):
822 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
824 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
823
825
824 r = hg.clone(hg.remoteui(ui, opts), source, dest,
826 r = hg.clone(hg.remoteui(ui, opts), source, dest,
825 pull=opts.get('pull'),
827 pull=opts.get('pull'),
826 stream=opts.get('uncompressed'),
828 stream=opts.get('uncompressed'),
827 rev=opts.get('rev'),
829 rev=opts.get('rev'),
828 update=opts.get('updaterev') or not opts.get('noupdate'),
830 update=opts.get('updaterev') or not opts.get('noupdate'),
829 branch=opts.get('branch'))
831 branch=opts.get('branch'))
830
832
831 return r is None
833 return r is None
832
834
833 def commit(ui, repo, *pats, **opts):
835 def commit(ui, repo, *pats, **opts):
834 """commit the specified files or all outstanding changes
836 """commit the specified files or all outstanding changes
835
837
836 Commit changes to the given files into the repository. Unlike a
838 Commit changes to the given files into the repository. Unlike a
837 centralized SCM, this operation is a local operation. See
839 centralized SCM, this operation is a local operation. See
838 :hg:`push` for a way to actively distribute your changes.
840 :hg:`push` for a way to actively distribute your changes.
839
841
840 If a list of files is omitted, all changes reported by :hg:`status`
842 If a list of files is omitted, all changes reported by :hg:`status`
841 will be committed.
843 will be committed.
842
844
843 If you are committing the result of a merge, do not provide any
845 If you are committing the result of a merge, do not provide any
844 filenames or -I/-X filters.
846 filenames or -I/-X filters.
845
847
846 If no commit message is specified, Mercurial starts your
848 If no commit message is specified, Mercurial starts your
847 configured editor where you can enter a message. In case your
849 configured editor where you can enter a message. In case your
848 commit fails, you will find a backup of your message in
850 commit fails, you will find a backup of your message in
849 ``.hg/last-message.txt``.
851 ``.hg/last-message.txt``.
850
852
851 See :hg:`help dates` for a list of formats valid for -d/--date.
853 See :hg:`help dates` for a list of formats valid for -d/--date.
852
854
853 Returns 0 on success, 1 if nothing changed.
855 Returns 0 on success, 1 if nothing changed.
854 """
856 """
855 extra = {}
857 extra = {}
856 if opts.get('close_branch'):
858 if opts.get('close_branch'):
857 if repo['.'].node() not in repo.branchheads():
859 if repo['.'].node() not in repo.branchheads():
858 # The topo heads set is included in the branch heads set of the
860 # The topo heads set is included in the branch heads set of the
859 # current branch, so it's sufficient to test branchheads
861 # current branch, so it's sufficient to test branchheads
860 raise util.Abort(_('can only close branch heads'))
862 raise util.Abort(_('can only close branch heads'))
861 extra['close'] = 1
863 extra['close'] = 1
862 e = cmdutil.commiteditor
864 e = cmdutil.commiteditor
863 if opts.get('force_editor'):
865 if opts.get('force_editor'):
864 e = cmdutil.commitforceeditor
866 e = cmdutil.commitforceeditor
865
867
866 def commitfunc(ui, repo, message, match, opts):
868 def commitfunc(ui, repo, message, match, opts):
867 return repo.commit(message, opts.get('user'), opts.get('date'), match,
869 return repo.commit(message, opts.get('user'), opts.get('date'), match,
868 editor=e, extra=extra)
870 editor=e, extra=extra)
869
871
870 branch = repo[None].branch()
872 branch = repo[None].branch()
871 bheads = repo.branchheads(branch)
873 bheads = repo.branchheads(branch)
872
874
873 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
875 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
874 if not node:
876 if not node:
875 stat = repo.status(match=cmdutil.match(repo, pats, opts))
877 stat = repo.status(match=cmdutil.match(repo, pats, opts))
876 if stat[3]:
878 if stat[3]:
877 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
879 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
878 % len(stat[3]))
880 % len(stat[3]))
879 else:
881 else:
880 ui.status(_("nothing changed\n"))
882 ui.status(_("nothing changed\n"))
881 return 1
883 return 1
882
884
883 ctx = repo[node]
885 ctx = repo[node]
884 parents = ctx.parents()
886 parents = ctx.parents()
885
887
886 if bheads and not [x for x in parents
888 if bheads and not [x for x in parents
887 if x.node() in bheads and x.branch() == branch]:
889 if x.node() in bheads and x.branch() == branch]:
888 ui.status(_('created new head\n'))
890 ui.status(_('created new head\n'))
889 # The message is not printed for initial roots. For the other
891 # The message is not printed for initial roots. For the other
890 # changesets, it is printed in the following situations:
892 # changesets, it is printed in the following situations:
891 #
893 #
892 # Par column: for the 2 parents with ...
894 # Par column: for the 2 parents with ...
893 # N: null or no parent
895 # N: null or no parent
894 # B: parent is on another named branch
896 # B: parent is on another named branch
895 # C: parent is a regular non head changeset
897 # C: parent is a regular non head changeset
896 # H: parent was a branch head of the current branch
898 # H: parent was a branch head of the current branch
897 # Msg column: whether we print "created new head" message
899 # Msg column: whether we print "created new head" message
898 # In the following, it is assumed that there already exists some
900 # In the following, it is assumed that there already exists some
899 # initial branch heads of the current branch, otherwise nothing is
901 # initial branch heads of the current branch, otherwise nothing is
900 # printed anyway.
902 # printed anyway.
901 #
903 #
902 # Par Msg Comment
904 # Par Msg Comment
903 # NN y additional topo root
905 # NN y additional topo root
904 #
906 #
905 # BN y additional branch root
907 # BN y additional branch root
906 # CN y additional topo head
908 # CN y additional topo head
907 # HN n usual case
909 # HN n usual case
908 #
910 #
909 # BB y weird additional branch root
911 # BB y weird additional branch root
910 # CB y branch merge
912 # CB y branch merge
911 # HB n merge with named branch
913 # HB n merge with named branch
912 #
914 #
913 # CC y additional head from merge
915 # CC y additional head from merge
914 # CH n merge with a head
916 # CH n merge with a head
915 #
917 #
916 # HH n head merge: head count decreases
918 # HH n head merge: head count decreases
917
919
918 if not opts.get('close_branch'):
920 if not opts.get('close_branch'):
919 for r in parents:
921 for r in parents:
920 if r.extra().get('close') and r.branch() == branch:
922 if r.extra().get('close') and r.branch() == branch:
921 ui.status(_('reopening closed branch head %d\n') % r)
923 ui.status(_('reopening closed branch head %d\n') % r)
922
924
923 if ui.debugflag:
925 if ui.debugflag:
924 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
926 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
925 elif ui.verbose:
927 elif ui.verbose:
926 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
928 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
927
929
928 def copy(ui, repo, *pats, **opts):
930 def copy(ui, repo, *pats, **opts):
929 """mark files as copied for the next commit
931 """mark files as copied for the next commit
930
932
931 Mark dest as having copies of source files. If dest is a
933 Mark dest as having copies of source files. If dest is a
932 directory, copies are put in that directory. If dest is a file,
934 directory, copies are put in that directory. If dest is a file,
933 the source must be a single file.
935 the source must be a single file.
934
936
935 By default, this command copies the contents of files as they
937 By default, this command copies the contents of files as they
936 exist in the working directory. If invoked with -A/--after, the
938 exist in the working directory. If invoked with -A/--after, the
937 operation is recorded, but no copying is performed.
939 operation is recorded, but no copying is performed.
938
940
939 This command takes effect with the next commit. To undo a copy
941 This command takes effect with the next commit. To undo a copy
940 before that, see :hg:`revert`.
942 before that, see :hg:`revert`.
941
943
942 Returns 0 on success, 1 if errors are encountered.
944 Returns 0 on success, 1 if errors are encountered.
943 """
945 """
944 wlock = repo.wlock(False)
946 wlock = repo.wlock(False)
945 try:
947 try:
946 return cmdutil.copy(ui, repo, pats, opts)
948 return cmdutil.copy(ui, repo, pats, opts)
947 finally:
949 finally:
948 wlock.release()
950 wlock.release()
949
951
950 def debugancestor(ui, repo, *args):
952 def debugancestor(ui, repo, *args):
951 """find the ancestor revision of two revisions in a given index"""
953 """find the ancestor revision of two revisions in a given index"""
952 if len(args) == 3:
954 if len(args) == 3:
953 index, rev1, rev2 = args
955 index, rev1, rev2 = args
954 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
956 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
955 lookup = r.lookup
957 lookup = r.lookup
956 elif len(args) == 2:
958 elif len(args) == 2:
957 if not repo:
959 if not repo:
958 raise util.Abort(_("there is no Mercurial repository here "
960 raise util.Abort(_("there is no Mercurial repository here "
959 "(.hg not found)"))
961 "(.hg not found)"))
960 rev1, rev2 = args
962 rev1, rev2 = args
961 r = repo.changelog
963 r = repo.changelog
962 lookup = repo.lookup
964 lookup = repo.lookup
963 else:
965 else:
964 raise util.Abort(_('either two or three arguments required'))
966 raise util.Abort(_('either two or three arguments required'))
965 a = r.ancestor(lookup(rev1), lookup(rev2))
967 a = r.ancestor(lookup(rev1), lookup(rev2))
966 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
968 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
967
969
968 def debugbuilddag(ui, repo, text,
970 def debugbuilddag(ui, repo, text,
969 mergeable_file=False,
971 mergeable_file=False,
970 overwritten_file=False,
972 overwritten_file=False,
971 new_file=False):
973 new_file=False):
972 """builds a repo with a given dag from scratch in the current empty repo
974 """builds a repo with a given dag from scratch in the current empty repo
973
975
974 Elements:
976 Elements:
975
977
976 - "+n" is a linear run of n nodes based on the current default parent
978 - "+n" is a linear run of n nodes based on the current default parent
977 - "." is a single node based on the current default parent
979 - "." is a single node based on the current default parent
978 - "$" resets the default parent to null (implied at the start);
980 - "$" resets the default parent to null (implied at the start);
979 otherwise the default parent is always the last node created
981 otherwise the default parent is always the last node created
980 - "<p" sets the default parent to the backref p
982 - "<p" sets the default parent to the backref p
981 - "*p" is a fork at parent p, which is a backref
983 - "*p" is a fork at parent p, which is a backref
982 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
984 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
983 - "/p2" is a merge of the preceding node and p2
985 - "/p2" is a merge of the preceding node and p2
984 - ":tag" defines a local tag for the preceding node
986 - ":tag" defines a local tag for the preceding node
985 - "@branch" sets the named branch for subsequent nodes
987 - "@branch" sets the named branch for subsequent nodes
986 - "#...\\n" is a comment up to the end of the line
988 - "#...\\n" is a comment up to the end of the line
987
989
988 Whitespace between the above elements is ignored.
990 Whitespace between the above elements is ignored.
989
991
990 A backref is either
992 A backref is either
991
993
992 - a number n, which references the node curr-n, where curr is the current
994 - a number n, which references the node curr-n, where curr is the current
993 node, or
995 node, or
994 - the name of a local tag you placed earlier using ":tag", or
996 - the name of a local tag you placed earlier using ":tag", or
995 - empty to denote the default parent.
997 - empty to denote the default parent.
996
998
997 All string valued-elements are either strictly alphanumeric, or must
999 All string valued-elements are either strictly alphanumeric, or must
998 be enclosed in double quotes ("..."), with "\\" as escape character.
1000 be enclosed in double quotes ("..."), with "\\" as escape character.
999 """
1001 """
1000
1002
1001 cl = repo.changelog
1003 cl = repo.changelog
1002 if len(cl) > 0:
1004 if len(cl) > 0:
1003 raise util.Abort(_('repository is not empty'))
1005 raise util.Abort(_('repository is not empty'))
1004
1006
1005 if mergeable_file:
1007 if mergeable_file:
1006 linesperrev = 2
1008 linesperrev = 2
1007 # determine number of revs in DAG
1009 # determine number of revs in DAG
1008 n = 0
1010 n = 0
1009 for type, data in dagparser.parsedag(text):
1011 for type, data in dagparser.parsedag(text):
1010 if type == 'n':
1012 if type == 'n':
1011 n += 1
1013 n += 1
1012 # make a file with k lines per rev
1014 # make a file with k lines per rev
1013 initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
1015 initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
1014 initialmergedlines.append("")
1016 initialmergedlines.append("")
1015
1017
1016 tags = []
1018 tags = []
1017
1019
1018 tr = repo.transaction("builddag")
1020 tr = repo.transaction("builddag")
1019 try:
1021 try:
1020
1022
1021 at = -1
1023 at = -1
1022 atbranch = 'default'
1024 atbranch = 'default'
1023 nodeids = []
1025 nodeids = []
1024 for type, data in dagparser.parsedag(text):
1026 for type, data in dagparser.parsedag(text):
1025 if type == 'n':
1027 if type == 'n':
1026 ui.note('node %s\n' % str(data))
1028 ui.note('node %s\n' % str(data))
1027 id, ps = data
1029 id, ps = data
1028
1030
1029 files = []
1031 files = []
1030 fctxs = {}
1032 fctxs = {}
1031
1033
1032 p2 = None
1034 p2 = None
1033 if mergeable_file:
1035 if mergeable_file:
1034 fn = "mf"
1036 fn = "mf"
1035 p1 = repo[ps[0]]
1037 p1 = repo[ps[0]]
1036 if len(ps) > 1:
1038 if len(ps) > 1:
1037 p2 = repo[ps[1]]
1039 p2 = repo[ps[1]]
1038 pa = p1.ancestor(p2)
1040 pa = p1.ancestor(p2)
1039 base, local, other = [x[fn].data() for x in pa, p1, p2]
1041 base, local, other = [x[fn].data() for x in pa, p1, p2]
1040 m3 = simplemerge.Merge3Text(base, local, other)
1042 m3 = simplemerge.Merge3Text(base, local, other)
1041 ml = [l.strip() for l in m3.merge_lines()]
1043 ml = [l.strip() for l in m3.merge_lines()]
1042 ml.append("")
1044 ml.append("")
1043 elif at > 0:
1045 elif at > 0:
1044 ml = p1[fn].data().split("\n")
1046 ml = p1[fn].data().split("\n")
1045 else:
1047 else:
1046 ml = initialmergedlines
1048 ml = initialmergedlines
1047 ml[id * linesperrev] += " r%i" % id
1049 ml[id * linesperrev] += " r%i" % id
1048 mergedtext = "\n".join(ml)
1050 mergedtext = "\n".join(ml)
1049 files.append(fn)
1051 files.append(fn)
1050 fctxs[fn] = context.memfilectx(fn, mergedtext)
1052 fctxs[fn] = context.memfilectx(fn, mergedtext)
1051
1053
1052 if overwritten_file:
1054 if overwritten_file:
1053 fn = "of"
1055 fn = "of"
1054 files.append(fn)
1056 files.append(fn)
1055 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1057 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1056
1058
1057 if new_file:
1059 if new_file:
1058 fn = "nf%i" % id
1060 fn = "nf%i" % id
1059 files.append(fn)
1061 files.append(fn)
1060 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1062 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1061 if len(ps) > 1:
1063 if len(ps) > 1:
1062 if not p2:
1064 if not p2:
1063 p2 = repo[ps[1]]
1065 p2 = repo[ps[1]]
1064 for fn in p2:
1066 for fn in p2:
1065 if fn.startswith("nf"):
1067 if fn.startswith("nf"):
1066 files.append(fn)
1068 files.append(fn)
1067 fctxs[fn] = p2[fn]
1069 fctxs[fn] = p2[fn]
1068
1070
1069 def fctxfn(repo, cx, path):
1071 def fctxfn(repo, cx, path):
1070 return fctxs.get(path)
1072 return fctxs.get(path)
1071
1073
1072 if len(ps) == 0 or ps[0] < 0:
1074 if len(ps) == 0 or ps[0] < 0:
1073 pars = [None, None]
1075 pars = [None, None]
1074 elif len(ps) == 1:
1076 elif len(ps) == 1:
1075 pars = [nodeids[ps[0]], None]
1077 pars = [nodeids[ps[0]], None]
1076 else:
1078 else:
1077 pars = [nodeids[p] for p in ps]
1079 pars = [nodeids[p] for p in ps]
1078 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1080 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1079 date=(id, 0),
1081 date=(id, 0),
1080 user="debugbuilddag",
1082 user="debugbuilddag",
1081 extra={'branch': atbranch})
1083 extra={'branch': atbranch})
1082 nodeid = repo.commitctx(cx)
1084 nodeid = repo.commitctx(cx)
1083 nodeids.append(nodeid)
1085 nodeids.append(nodeid)
1084 at = id
1086 at = id
1085 elif type == 'l':
1087 elif type == 'l':
1086 id, name = data
1088 id, name = data
1087 ui.note('tag %s\n' % name)
1089 ui.note('tag %s\n' % name)
1088 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1090 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1089 elif type == 'a':
1091 elif type == 'a':
1090 ui.note('branch %s\n' % data)
1092 ui.note('branch %s\n' % data)
1091 atbranch = data
1093 atbranch = data
1092 tr.close()
1094 tr.close()
1093 finally:
1095 finally:
1094 tr.release()
1096 tr.release()
1095
1097
1096 if tags:
1098 if tags:
1097 tagsf = repo.opener("localtags", "w")
1099 tagsf = repo.opener("localtags", "w")
1098 try:
1100 try:
1099 tagsf.write("".join(tags))
1101 tagsf.write("".join(tags))
1100 finally:
1102 finally:
1101 tagsf.close()
1103 tagsf.close()
1102
1104
1103 def debugcommands(ui, cmd='', *args):
1105 def debugcommands(ui, cmd='', *args):
1104 """list all available commands and options"""
1106 """list all available commands and options"""
1105 for cmd, vals in sorted(table.iteritems()):
1107 for cmd, vals in sorted(table.iteritems()):
1106 cmd = cmd.split('|')[0].strip('^')
1108 cmd = cmd.split('|')[0].strip('^')
1107 opts = ', '.join([i[1] for i in vals[1]])
1109 opts = ', '.join([i[1] for i in vals[1]])
1108 ui.write('%s: %s\n' % (cmd, opts))
1110 ui.write('%s: %s\n' % (cmd, opts))
1109
1111
1110 def debugcomplete(ui, cmd='', **opts):
1112 def debugcomplete(ui, cmd='', **opts):
1111 """returns the completion list associated with the given command"""
1113 """returns the completion list associated with the given command"""
1112
1114
1113 if opts.get('options'):
1115 if opts.get('options'):
1114 options = []
1116 options = []
1115 otables = [globalopts]
1117 otables = [globalopts]
1116 if cmd:
1118 if cmd:
1117 aliases, entry = cmdutil.findcmd(cmd, table, False)
1119 aliases, entry = cmdutil.findcmd(cmd, table, False)
1118 otables.append(entry[1])
1120 otables.append(entry[1])
1119 for t in otables:
1121 for t in otables:
1120 for o in t:
1122 for o in t:
1121 if "(DEPRECATED)" in o[3]:
1123 if "(DEPRECATED)" in o[3]:
1122 continue
1124 continue
1123 if o[0]:
1125 if o[0]:
1124 options.append('-%s' % o[0])
1126 options.append('-%s' % o[0])
1125 options.append('--%s' % o[1])
1127 options.append('--%s' % o[1])
1126 ui.write("%s\n" % "\n".join(options))
1128 ui.write("%s\n" % "\n".join(options))
1127 return
1129 return
1128
1130
1129 cmdlist = cmdutil.findpossible(cmd, table)
1131 cmdlist = cmdutil.findpossible(cmd, table)
1130 if ui.verbose:
1132 if ui.verbose:
1131 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1133 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1132 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1134 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1133
1135
1134 def debugfsinfo(ui, path = "."):
1136 def debugfsinfo(ui, path = "."):
1135 """show information detected about current filesystem"""
1137 """show information detected about current filesystem"""
1136 util.writefile('.debugfsinfo', '')
1138 util.writefile('.debugfsinfo', '')
1137 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1139 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1138 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1140 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1139 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1141 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1140 and 'yes' or 'no'))
1142 and 'yes' or 'no'))
1141 os.unlink('.debugfsinfo')
1143 os.unlink('.debugfsinfo')
1142
1144
1143 def debugrebuildstate(ui, repo, rev="tip"):
1145 def debugrebuildstate(ui, repo, rev="tip"):
1144 """rebuild the dirstate as it would look like for the given revision"""
1146 """rebuild the dirstate as it would look like for the given revision"""
1145 ctx = cmdutil.revsingle(repo, rev)
1147 ctx = cmdutil.revsingle(repo, rev)
1146 wlock = repo.wlock()
1148 wlock = repo.wlock()
1147 try:
1149 try:
1148 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1150 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1149 finally:
1151 finally:
1150 wlock.release()
1152 wlock.release()
1151
1153
1152 def debugcheckstate(ui, repo):
1154 def debugcheckstate(ui, repo):
1153 """validate the correctness of the current dirstate"""
1155 """validate the correctness of the current dirstate"""
1154 parent1, parent2 = repo.dirstate.parents()
1156 parent1, parent2 = repo.dirstate.parents()
1155 m1 = repo[parent1].manifest()
1157 m1 = repo[parent1].manifest()
1156 m2 = repo[parent2].manifest()
1158 m2 = repo[parent2].manifest()
1157 errors = 0
1159 errors = 0
1158 for f in repo.dirstate:
1160 for f in repo.dirstate:
1159 state = repo.dirstate[f]
1161 state = repo.dirstate[f]
1160 if state in "nr" and f not in m1:
1162 if state in "nr" and f not in m1:
1161 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1163 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1162 errors += 1
1164 errors += 1
1163 if state in "a" and f in m1:
1165 if state in "a" and f in m1:
1164 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1166 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1165 errors += 1
1167 errors += 1
1166 if state in "m" and f not in m1 and f not in m2:
1168 if state in "m" and f not in m1 and f not in m2:
1167 ui.warn(_("%s in state %s, but not in either manifest\n") %
1169 ui.warn(_("%s in state %s, but not in either manifest\n") %
1168 (f, state))
1170 (f, state))
1169 errors += 1
1171 errors += 1
1170 for f in m1:
1172 for f in m1:
1171 state = repo.dirstate[f]
1173 state = repo.dirstate[f]
1172 if state not in "nrm":
1174 if state not in "nrm":
1173 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1175 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1174 errors += 1
1176 errors += 1
1175 if errors:
1177 if errors:
1176 error = _(".hg/dirstate inconsistent with current parent's manifest")
1178 error = _(".hg/dirstate inconsistent with current parent's manifest")
1177 raise util.Abort(error)
1179 raise util.Abort(error)
1178
1180
1179 def showconfig(ui, repo, *values, **opts):
1181 def showconfig(ui, repo, *values, **opts):
1180 """show combined config settings from all hgrc files
1182 """show combined config settings from all hgrc files
1181
1183
1182 With no arguments, print names and values of all config items.
1184 With no arguments, print names and values of all config items.
1183
1185
1184 With one argument of the form section.name, print just the value
1186 With one argument of the form section.name, print just the value
1185 of that config item.
1187 of that config item.
1186
1188
1187 With multiple arguments, print names and values of all config
1189 With multiple arguments, print names and values of all config
1188 items with matching section names.
1190 items with matching section names.
1189
1191
1190 With --debug, the source (filename and line number) is printed
1192 With --debug, the source (filename and line number) is printed
1191 for each config item.
1193 for each config item.
1192
1194
1193 Returns 0 on success.
1195 Returns 0 on success.
1194 """
1196 """
1195
1197
1196 for f in scmutil.rcpath():
1198 for f in scmutil.rcpath():
1197 ui.debug(_('read config from: %s\n') % f)
1199 ui.debug(_('read config from: %s\n') % f)
1198 untrusted = bool(opts.get('untrusted'))
1200 untrusted = bool(opts.get('untrusted'))
1199 if values:
1201 if values:
1200 sections = [v for v in values if '.' not in v]
1202 sections = [v for v in values if '.' not in v]
1201 items = [v for v in values if '.' in v]
1203 items = [v for v in values if '.' in v]
1202 if len(items) > 1 or items and sections:
1204 if len(items) > 1 or items and sections:
1203 raise util.Abort(_('only one config item permitted'))
1205 raise util.Abort(_('only one config item permitted'))
1204 for section, name, value in ui.walkconfig(untrusted=untrusted):
1206 for section, name, value in ui.walkconfig(untrusted=untrusted):
1205 value = str(value).replace('\n', '\\n')
1207 value = str(value).replace('\n', '\\n')
1206 sectname = section + '.' + name
1208 sectname = section + '.' + name
1207 if values:
1209 if values:
1208 for v in values:
1210 for v in values:
1209 if v == section:
1211 if v == section:
1210 ui.debug('%s: ' %
1212 ui.debug('%s: ' %
1211 ui.configsource(section, name, untrusted))
1213 ui.configsource(section, name, untrusted))
1212 ui.write('%s=%s\n' % (sectname, value))
1214 ui.write('%s=%s\n' % (sectname, value))
1213 elif v == sectname:
1215 elif v == sectname:
1214 ui.debug('%s: ' %
1216 ui.debug('%s: ' %
1215 ui.configsource(section, name, untrusted))
1217 ui.configsource(section, name, untrusted))
1216 ui.write(value, '\n')
1218 ui.write(value, '\n')
1217 else:
1219 else:
1218 ui.debug('%s: ' %
1220 ui.debug('%s: ' %
1219 ui.configsource(section, name, untrusted))
1221 ui.configsource(section, name, untrusted))
1220 ui.write('%s=%s\n' % (sectname, value))
1222 ui.write('%s=%s\n' % (sectname, value))
1221
1223
1222 def debugknown(ui, repopath, *ids, **opts):
1224 def debugknown(ui, repopath, *ids, **opts):
1223 """test whether node ids are known to a repo
1225 """test whether node ids are known to a repo
1224
1226
1225 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1227 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1226 indicating unknown/known.
1228 indicating unknown/known.
1227 """
1229 """
1228 repo = hg.repository(ui, repopath)
1230 repo = hg.repository(ui, repopath)
1229 if not repo.capable('known'):
1231 if not repo.capable('known'):
1230 raise util.Abort("known() not supported by target repository")
1232 raise util.Abort("known() not supported by target repository")
1231 flags = repo.known([bin(s) for s in ids])
1233 flags = repo.known([bin(s) for s in ids])
1232 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1234 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1233
1235
1234 def debugbundle(ui, bundlepath, all=None, **opts):
1236 def debugbundle(ui, bundlepath, all=None, **opts):
1235 """lists the contents of a bundle"""
1237 """lists the contents of a bundle"""
1236 f = url.open(ui, bundlepath)
1238 f = url.open(ui, bundlepath)
1237 try:
1239 try:
1238 gen = changegroup.readbundle(f, bundlepath)
1240 gen = changegroup.readbundle(f, bundlepath)
1239 if all:
1241 if all:
1240 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1242 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1241
1243
1242 def showchunks(named):
1244 def showchunks(named):
1243 ui.write("\n%s\n" % named)
1245 ui.write("\n%s\n" % named)
1244 chain = None
1246 chain = None
1245 while 1:
1247 while 1:
1246 chunkdata = gen.deltachunk(chain)
1248 chunkdata = gen.deltachunk(chain)
1247 if not chunkdata:
1249 if not chunkdata:
1248 break
1250 break
1249 node = chunkdata['node']
1251 node = chunkdata['node']
1250 p1 = chunkdata['p1']
1252 p1 = chunkdata['p1']
1251 p2 = chunkdata['p2']
1253 p2 = chunkdata['p2']
1252 cs = chunkdata['cs']
1254 cs = chunkdata['cs']
1253 deltabase = chunkdata['deltabase']
1255 deltabase = chunkdata['deltabase']
1254 delta = chunkdata['delta']
1256 delta = chunkdata['delta']
1255 ui.write("%s %s %s %s %s %s\n" %
1257 ui.write("%s %s %s %s %s %s\n" %
1256 (hex(node), hex(p1), hex(p2),
1258 (hex(node), hex(p1), hex(p2),
1257 hex(cs), hex(deltabase), len(delta)))
1259 hex(cs), hex(deltabase), len(delta)))
1258 chain = node
1260 chain = node
1259
1261
1260 chunkdata = gen.changelogheader()
1262 chunkdata = gen.changelogheader()
1261 showchunks("changelog")
1263 showchunks("changelog")
1262 chunkdata = gen.manifestheader()
1264 chunkdata = gen.manifestheader()
1263 showchunks("manifest")
1265 showchunks("manifest")
1264 while 1:
1266 while 1:
1265 chunkdata = gen.filelogheader()
1267 chunkdata = gen.filelogheader()
1266 if not chunkdata:
1268 if not chunkdata:
1267 break
1269 break
1268 fname = chunkdata['filename']
1270 fname = chunkdata['filename']
1269 showchunks(fname)
1271 showchunks(fname)
1270 else:
1272 else:
1271 chunkdata = gen.changelogheader()
1273 chunkdata = gen.changelogheader()
1272 chain = None
1274 chain = None
1273 while 1:
1275 while 1:
1274 chunkdata = gen.deltachunk(chain)
1276 chunkdata = gen.deltachunk(chain)
1275 if not chunkdata:
1277 if not chunkdata:
1276 break
1278 break
1277 node = chunkdata['node']
1279 node = chunkdata['node']
1278 ui.write("%s\n" % hex(node))
1280 ui.write("%s\n" % hex(node))
1279 chain = node
1281 chain = node
1280 finally:
1282 finally:
1281 f.close()
1283 f.close()
1282
1284
1283 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1285 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1284 """retrieves a bundle from a repo
1286 """retrieves a bundle from a repo
1285
1287
1286 Every ID must be a full-length hex node id string. Saves the bundle to the
1288 Every ID must be a full-length hex node id string. Saves the bundle to the
1287 given file.
1289 given file.
1288 """
1290 """
1289 repo = hg.repository(ui, repopath)
1291 repo = hg.repository(ui, repopath)
1290 if not repo.capable('getbundle'):
1292 if not repo.capable('getbundle'):
1291 raise util.Abort("getbundle() not supported by target repository")
1293 raise util.Abort("getbundle() not supported by target repository")
1292 args = {}
1294 args = {}
1293 if common:
1295 if common:
1294 args['common'] = [bin(s) for s in common]
1296 args['common'] = [bin(s) for s in common]
1295 if head:
1297 if head:
1296 args['heads'] = [bin(s) for s in head]
1298 args['heads'] = [bin(s) for s in head]
1297 bundle = repo.getbundle('debug', **args)
1299 bundle = repo.getbundle('debug', **args)
1298
1300
1299 bundletype = opts.get('type', 'bzip2').lower()
1301 bundletype = opts.get('type', 'bzip2').lower()
1300 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1302 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1301 bundletype = btypes.get(bundletype)
1303 bundletype = btypes.get(bundletype)
1302 if bundletype not in changegroup.bundletypes:
1304 if bundletype not in changegroup.bundletypes:
1303 raise util.Abort(_('unknown bundle type specified with --type'))
1305 raise util.Abort(_('unknown bundle type specified with --type'))
1304 changegroup.writebundle(bundle, bundlepath, bundletype)
1306 changegroup.writebundle(bundle, bundlepath, bundletype)
1305
1307
1306 def debugpushkey(ui, repopath, namespace, *keyinfo):
1308 def debugpushkey(ui, repopath, namespace, *keyinfo):
1307 '''access the pushkey key/value protocol
1309 '''access the pushkey key/value protocol
1308
1310
1309 With two args, list the keys in the given namespace.
1311 With two args, list the keys in the given namespace.
1310
1312
1311 With five args, set a key to new if it currently is set to old.
1313 With five args, set a key to new if it currently is set to old.
1312 Reports success or failure.
1314 Reports success or failure.
1313 '''
1315 '''
1314
1316
1315 target = hg.repository(ui, repopath)
1317 target = hg.repository(ui, repopath)
1316 if keyinfo:
1318 if keyinfo:
1317 key, old, new = keyinfo
1319 key, old, new = keyinfo
1318 r = target.pushkey(namespace, key, old, new)
1320 r = target.pushkey(namespace, key, old, new)
1319 ui.status(str(r) + '\n')
1321 ui.status(str(r) + '\n')
1320 return not r
1322 return not r
1321 else:
1323 else:
1322 for k, v in target.listkeys(namespace).iteritems():
1324 for k, v in target.listkeys(namespace).iteritems():
1323 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1325 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1324 v.encode('string-escape')))
1326 v.encode('string-escape')))
1325
1327
1326 def debugrevspec(ui, repo, expr):
1328 def debugrevspec(ui, repo, expr):
1327 '''parse and apply a revision specification'''
1329 '''parse and apply a revision specification'''
1328 if ui.verbose:
1330 if ui.verbose:
1329 tree = revset.parse(expr)[0]
1331 tree = revset.parse(expr)[0]
1330 ui.note(tree, "\n")
1332 ui.note(tree, "\n")
1331 newtree = revset.findaliases(ui, tree)
1333 newtree = revset.findaliases(ui, tree)
1332 if newtree != tree:
1334 if newtree != tree:
1333 ui.note(newtree, "\n")
1335 ui.note(newtree, "\n")
1334 func = revset.match(ui, expr)
1336 func = revset.match(ui, expr)
1335 for c in func(repo, range(len(repo))):
1337 for c in func(repo, range(len(repo))):
1336 ui.write("%s\n" % c)
1338 ui.write("%s\n" % c)
1337
1339
1338 def debugsetparents(ui, repo, rev1, rev2=None):
1340 def debugsetparents(ui, repo, rev1, rev2=None):
1339 """manually set the parents of the current working directory
1341 """manually set the parents of the current working directory
1340
1342
1341 This is useful for writing repository conversion tools, but should
1343 This is useful for writing repository conversion tools, but should
1342 be used with care.
1344 be used with care.
1343
1345
1344 Returns 0 on success.
1346 Returns 0 on success.
1345 """
1347 """
1346
1348
1347 r1 = cmdutil.revsingle(repo, rev1).node()
1349 r1 = cmdutil.revsingle(repo, rev1).node()
1348 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1350 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1349
1351
1350 wlock = repo.wlock()
1352 wlock = repo.wlock()
1351 try:
1353 try:
1352 repo.dirstate.setparents(r1, r2)
1354 repo.dirstate.setparents(r1, r2)
1353 finally:
1355 finally:
1354 wlock.release()
1356 wlock.release()
1355
1357
1356 def debugstate(ui, repo, nodates=None, datesort=None):
1358 def debugstate(ui, repo, nodates=None, datesort=None):
1357 """show the contents of the current dirstate"""
1359 """show the contents of the current dirstate"""
1358 timestr = ""
1360 timestr = ""
1359 showdate = not nodates
1361 showdate = not nodates
1360 if datesort:
1362 if datesort:
1361 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1363 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1362 else:
1364 else:
1363 keyfunc = None # sort by filename
1365 keyfunc = None # sort by filename
1364 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1366 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1365 if showdate:
1367 if showdate:
1366 if ent[3] == -1:
1368 if ent[3] == -1:
1367 # Pad or slice to locale representation
1369 # Pad or slice to locale representation
1368 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1370 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1369 time.localtime(0)))
1371 time.localtime(0)))
1370 timestr = 'unset'
1372 timestr = 'unset'
1371 timestr = (timestr[:locale_len] +
1373 timestr = (timestr[:locale_len] +
1372 ' ' * (locale_len - len(timestr)))
1374 ' ' * (locale_len - len(timestr)))
1373 else:
1375 else:
1374 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1376 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1375 time.localtime(ent[3]))
1377 time.localtime(ent[3]))
1376 if ent[1] & 020000:
1378 if ent[1] & 020000:
1377 mode = 'lnk'
1379 mode = 'lnk'
1378 else:
1380 else:
1379 mode = '%3o' % (ent[1] & 0777)
1381 mode = '%3o' % (ent[1] & 0777)
1380 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1382 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1381 for f in repo.dirstate.copies():
1383 for f in repo.dirstate.copies():
1382 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1384 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1383
1385
1384 def debugsub(ui, repo, rev=None):
1386 def debugsub(ui, repo, rev=None):
1385 ctx = cmdutil.revsingle(repo, rev, None)
1387 ctx = cmdutil.revsingle(repo, rev, None)
1386 for k, v in sorted(ctx.substate.items()):
1388 for k, v in sorted(ctx.substate.items()):
1387 ui.write('path %s\n' % k)
1389 ui.write('path %s\n' % k)
1388 ui.write(' source %s\n' % v[0])
1390 ui.write(' source %s\n' % v[0])
1389 ui.write(' revision %s\n' % v[1])
1391 ui.write(' revision %s\n' % v[1])
1390
1392
1391 def debugdag(ui, repo, file_=None, *revs, **opts):
1393 def debugdag(ui, repo, file_=None, *revs, **opts):
1392 """format the changelog or an index DAG as a concise textual description
1394 """format the changelog or an index DAG as a concise textual description
1393
1395
1394 If you pass a revlog index, the revlog's DAG is emitted. If you list
1396 If you pass a revlog index, the revlog's DAG is emitted. If you list
1395 revision numbers, they get labelled in the output as rN.
1397 revision numbers, they get labelled in the output as rN.
1396
1398
1397 Otherwise, the changelog DAG of the current repo is emitted.
1399 Otherwise, the changelog DAG of the current repo is emitted.
1398 """
1400 """
1399 spaces = opts.get('spaces')
1401 spaces = opts.get('spaces')
1400 dots = opts.get('dots')
1402 dots = opts.get('dots')
1401 if file_:
1403 if file_:
1402 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1404 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1403 revs = set((int(r) for r in revs))
1405 revs = set((int(r) for r in revs))
1404 def events():
1406 def events():
1405 for r in rlog:
1407 for r in rlog:
1406 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1408 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1407 if r in revs:
1409 if r in revs:
1408 yield 'l', (r, "r%i" % r)
1410 yield 'l', (r, "r%i" % r)
1409 elif repo:
1411 elif repo:
1410 cl = repo.changelog
1412 cl = repo.changelog
1411 tags = opts.get('tags')
1413 tags = opts.get('tags')
1412 branches = opts.get('branches')
1414 branches = opts.get('branches')
1413 if tags:
1415 if tags:
1414 labels = {}
1416 labels = {}
1415 for l, n in repo.tags().items():
1417 for l, n in repo.tags().items():
1416 labels.setdefault(cl.rev(n), []).append(l)
1418 labels.setdefault(cl.rev(n), []).append(l)
1417 def events():
1419 def events():
1418 b = "default"
1420 b = "default"
1419 for r in cl:
1421 for r in cl:
1420 if branches:
1422 if branches:
1421 newb = cl.read(cl.node(r))[5]['branch']
1423 newb = cl.read(cl.node(r))[5]['branch']
1422 if newb != b:
1424 if newb != b:
1423 yield 'a', newb
1425 yield 'a', newb
1424 b = newb
1426 b = newb
1425 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1427 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1426 if tags:
1428 if tags:
1427 ls = labels.get(r)
1429 ls = labels.get(r)
1428 if ls:
1430 if ls:
1429 for l in ls:
1431 for l in ls:
1430 yield 'l', (r, l)
1432 yield 'l', (r, l)
1431 else:
1433 else:
1432 raise util.Abort(_('need repo for changelog dag'))
1434 raise util.Abort(_('need repo for changelog dag'))
1433
1435
1434 for line in dagparser.dagtextlines(events(),
1436 for line in dagparser.dagtextlines(events(),
1435 addspaces=spaces,
1437 addspaces=spaces,
1436 wraplabels=True,
1438 wraplabels=True,
1437 wrapannotations=True,
1439 wrapannotations=True,
1438 wrapnonlinear=dots,
1440 wrapnonlinear=dots,
1439 usedots=dots,
1441 usedots=dots,
1440 maxlinewidth=70):
1442 maxlinewidth=70):
1441 ui.write(line)
1443 ui.write(line)
1442 ui.write("\n")
1444 ui.write("\n")
1443
1445
1444 def debugdata(ui, repo, file_, rev):
1446 def debugdata(ui, repo, file_, rev):
1445 """dump the contents of a data file revision"""
1447 """dump the contents of a data file revision"""
1446 r = None
1448 r = None
1447 if repo:
1449 if repo:
1448 filelog = repo.file(file_)
1450 filelog = repo.file(file_)
1449 if len(filelog):
1451 if len(filelog):
1450 r = filelog
1452 r = filelog
1451 if not r:
1453 if not r:
1452 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1454 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1453 file_[:-2] + ".i")
1455 file_[:-2] + ".i")
1454 try:
1456 try:
1455 ui.write(r.revision(r.lookup(rev)))
1457 ui.write(r.revision(r.lookup(rev)))
1456 except KeyError:
1458 except KeyError:
1457 raise util.Abort(_('invalid revision identifier %s') % rev)
1459 raise util.Abort(_('invalid revision identifier %s') % rev)
1458
1460
1459 def debugdate(ui, date, range=None, **opts):
1461 def debugdate(ui, date, range=None, **opts):
1460 """parse and display a date"""
1462 """parse and display a date"""
1461 if opts["extended"]:
1463 if opts["extended"]:
1462 d = util.parsedate(date, util.extendeddateformats)
1464 d = util.parsedate(date, util.extendeddateformats)
1463 else:
1465 else:
1464 d = util.parsedate(date)
1466 d = util.parsedate(date)
1465 ui.write("internal: %s %s\n" % d)
1467 ui.write("internal: %s %s\n" % d)
1466 ui.write("standard: %s\n" % util.datestr(d))
1468 ui.write("standard: %s\n" % util.datestr(d))
1467 if range:
1469 if range:
1468 m = util.matchdate(range)
1470 m = util.matchdate(range)
1469 ui.write("match: %s\n" % m(d[0]))
1471 ui.write("match: %s\n" % m(d[0]))
1470
1472
1471 def debugignore(ui, repo, *values, **opts):
1473 def debugignore(ui, repo, *values, **opts):
1472 """display the combined ignore pattern"""
1474 """display the combined ignore pattern"""
1473 ignore = repo.dirstate._ignore
1475 ignore = repo.dirstate._ignore
1474 if hasattr(ignore, 'includepat'):
1476 if hasattr(ignore, 'includepat'):
1475 ui.write("%s\n" % ignore.includepat)
1477 ui.write("%s\n" % ignore.includepat)
1476 else:
1478 else:
1477 raise util.Abort(_("no ignore patterns found"))
1479 raise util.Abort(_("no ignore patterns found"))
1478
1480
1479 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1481 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1480 """runs the changeset discovery protocol in isolation"""
1482 """runs the changeset discovery protocol in isolation"""
1481 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1483 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1482 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1484 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1483 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1485 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1484
1486
1485 # make sure tests are repeatable
1487 # make sure tests are repeatable
1486 random.seed(12323)
1488 random.seed(12323)
1487
1489
1488 def doit(localheads, remoteheads):
1490 def doit(localheads, remoteheads):
1489 if opts.get('old'):
1491 if opts.get('old'):
1490 if localheads:
1492 if localheads:
1491 raise util.Abort('cannot use localheads with old style discovery')
1493 raise util.Abort('cannot use localheads with old style discovery')
1492 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1494 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1493 force=True)
1495 force=True)
1494 common = set(common)
1496 common = set(common)
1495 if not opts.get('nonheads'):
1497 if not opts.get('nonheads'):
1496 ui.write("unpruned common: %s\n" % " ".join([short(n)
1498 ui.write("unpruned common: %s\n" % " ".join([short(n)
1497 for n in common]))
1499 for n in common]))
1498 dag = dagutil.revlogdag(repo.changelog)
1500 dag = dagutil.revlogdag(repo.changelog)
1499 all = dag.ancestorset(dag.internalizeall(common))
1501 all = dag.ancestorset(dag.internalizeall(common))
1500 common = dag.externalizeall(dag.headsetofconnecteds(all))
1502 common = dag.externalizeall(dag.headsetofconnecteds(all))
1501 else:
1503 else:
1502 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1504 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1503 common = set(common)
1505 common = set(common)
1504 rheads = set(hds)
1506 rheads = set(hds)
1505 lheads = set(repo.heads())
1507 lheads = set(repo.heads())
1506 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1508 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1507 if lheads <= common:
1509 if lheads <= common:
1508 ui.write("local is subset\n")
1510 ui.write("local is subset\n")
1509 elif rheads <= common:
1511 elif rheads <= common:
1510 ui.write("remote is subset\n")
1512 ui.write("remote is subset\n")
1511
1513
1512 serverlogs = opts.get('serverlog')
1514 serverlogs = opts.get('serverlog')
1513 if serverlogs:
1515 if serverlogs:
1514 for filename in serverlogs:
1516 for filename in serverlogs:
1515 logfile = open(filename, 'r')
1517 logfile = open(filename, 'r')
1516 try:
1518 try:
1517 line = logfile.readline()
1519 line = logfile.readline()
1518 while line:
1520 while line:
1519 parts = line.strip().split(';')
1521 parts = line.strip().split(';')
1520 op = parts[1]
1522 op = parts[1]
1521 if op == 'cg':
1523 if op == 'cg':
1522 pass
1524 pass
1523 elif op == 'cgss':
1525 elif op == 'cgss':
1524 doit(parts[2].split(' '), parts[3].split(' '))
1526 doit(parts[2].split(' '), parts[3].split(' '))
1525 elif op == 'unb':
1527 elif op == 'unb':
1526 doit(parts[3].split(' '), parts[2].split(' '))
1528 doit(parts[3].split(' '), parts[2].split(' '))
1527 line = logfile.readline()
1529 line = logfile.readline()
1528 finally:
1530 finally:
1529 logfile.close()
1531 logfile.close()
1530
1532
1531 else:
1533 else:
1532 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1534 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1533 opts.get('remote_head'))
1535 opts.get('remote_head'))
1534 localrevs = opts.get('local_head')
1536 localrevs = opts.get('local_head')
1535 doit(localrevs, remoterevs)
1537 doit(localrevs, remoterevs)
1536
1538
1537
1539
1538 def debugindex(ui, repo, file_, **opts):
1540 def debugindex(ui, repo, file_, **opts):
1539 """dump the contents of an index file"""
1541 """dump the contents of an index file"""
1540 r = None
1542 r = None
1541 if repo:
1543 if repo:
1542 filelog = repo.file(file_)
1544 filelog = repo.file(file_)
1543 if len(filelog):
1545 if len(filelog):
1544 r = filelog
1546 r = filelog
1545
1547
1546 format = opts.get('format', 0)
1548 format = opts.get('format', 0)
1547 if format not in (0, 1):
1549 if format not in (0, 1):
1548 raise util.Abort(_("unknown format %d") % format)
1550 raise util.Abort(_("unknown format %d") % format)
1549
1551
1550 if not r:
1552 if not r:
1551 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1553 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1552
1554
1553 if format == 0:
1555 if format == 0:
1554 ui.write(" rev offset length base linkrev"
1556 ui.write(" rev offset length base linkrev"
1555 " nodeid p1 p2\n")
1557 " nodeid p1 p2\n")
1556 elif format == 1:
1558 elif format == 1:
1557 ui.write(" rev flag offset length"
1559 ui.write(" rev flag offset length"
1558 " size base link p1 p2 nodeid\n")
1560 " size base link p1 p2 nodeid\n")
1559
1561
1560 for i in r:
1562 for i in r:
1561 node = r.node(i)
1563 node = r.node(i)
1562 if format == 0:
1564 if format == 0:
1563 try:
1565 try:
1564 pp = r.parents(node)
1566 pp = r.parents(node)
1565 except:
1567 except:
1566 pp = [nullid, nullid]
1568 pp = [nullid, nullid]
1567 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1569 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1568 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1570 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1569 short(node), short(pp[0]), short(pp[1])))
1571 short(node), short(pp[0]), short(pp[1])))
1570 elif format == 1:
1572 elif format == 1:
1571 pr = r.parentrevs(i)
1573 pr = r.parentrevs(i)
1572 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1574 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1573 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1575 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1574 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1576 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1575
1577
1576 def debugindexdot(ui, repo, file_):
1578 def debugindexdot(ui, repo, file_):
1577 """dump an index DAG as a graphviz dot file"""
1579 """dump an index DAG as a graphviz dot file"""
1578 r = None
1580 r = None
1579 if repo:
1581 if repo:
1580 filelog = repo.file(file_)
1582 filelog = repo.file(file_)
1581 if len(filelog):
1583 if len(filelog):
1582 r = filelog
1584 r = filelog
1583 if not r:
1585 if not r:
1584 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1586 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1585 ui.write("digraph G {\n")
1587 ui.write("digraph G {\n")
1586 for i in r:
1588 for i in r:
1587 node = r.node(i)
1589 node = r.node(i)
1588 pp = r.parents(node)
1590 pp = r.parents(node)
1589 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1591 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1590 if pp[1] != nullid:
1592 if pp[1] != nullid:
1591 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1593 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1592 ui.write("}\n")
1594 ui.write("}\n")
1593
1595
1594 def debuginstall(ui):
1596 def debuginstall(ui):
1595 '''test Mercurial installation
1597 '''test Mercurial installation
1596
1598
1597 Returns 0 on success.
1599 Returns 0 on success.
1598 '''
1600 '''
1599
1601
1600 def writetemp(contents):
1602 def writetemp(contents):
1601 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1603 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1602 f = os.fdopen(fd, "wb")
1604 f = os.fdopen(fd, "wb")
1603 f.write(contents)
1605 f.write(contents)
1604 f.close()
1606 f.close()
1605 return name
1607 return name
1606
1608
1607 problems = 0
1609 problems = 0
1608
1610
1609 # encoding
1611 # encoding
1610 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1612 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1611 try:
1613 try:
1612 encoding.fromlocal("test")
1614 encoding.fromlocal("test")
1613 except util.Abort, inst:
1615 except util.Abort, inst:
1614 ui.write(" %s\n" % inst)
1616 ui.write(" %s\n" % inst)
1615 ui.write(_(" (check that your locale is properly set)\n"))
1617 ui.write(_(" (check that your locale is properly set)\n"))
1616 problems += 1
1618 problems += 1
1617
1619
1618 # compiled modules
1620 # compiled modules
1619 ui.status(_("Checking installed modules (%s)...\n")
1621 ui.status(_("Checking installed modules (%s)...\n")
1620 % os.path.dirname(__file__))
1622 % os.path.dirname(__file__))
1621 try:
1623 try:
1622 import bdiff, mpatch, base85, osutil
1624 import bdiff, mpatch, base85, osutil
1623 except Exception, inst:
1625 except Exception, inst:
1624 ui.write(" %s\n" % inst)
1626 ui.write(" %s\n" % inst)
1625 ui.write(_(" One or more extensions could not be found"))
1627 ui.write(_(" One or more extensions could not be found"))
1626 ui.write(_(" (check that you compiled the extensions)\n"))
1628 ui.write(_(" (check that you compiled the extensions)\n"))
1627 problems += 1
1629 problems += 1
1628
1630
1629 # templates
1631 # templates
1630 ui.status(_("Checking templates...\n"))
1632 ui.status(_("Checking templates...\n"))
1631 try:
1633 try:
1632 import templater
1634 import templater
1633 templater.templater(templater.templatepath("map-cmdline.default"))
1635 templater.templater(templater.templatepath("map-cmdline.default"))
1634 except Exception, inst:
1636 except Exception, inst:
1635 ui.write(" %s\n" % inst)
1637 ui.write(" %s\n" % inst)
1636 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1638 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1637 problems += 1
1639 problems += 1
1638
1640
1639 # editor
1641 # editor
1640 ui.status(_("Checking commit editor...\n"))
1642 ui.status(_("Checking commit editor...\n"))
1641 editor = ui.geteditor()
1643 editor = ui.geteditor()
1642 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1644 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1643 if not cmdpath:
1645 if not cmdpath:
1644 if editor == 'vi':
1646 if editor == 'vi':
1645 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1647 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1646 ui.write(_(" (specify a commit editor in your configuration"
1648 ui.write(_(" (specify a commit editor in your configuration"
1647 " file)\n"))
1649 " file)\n"))
1648 else:
1650 else:
1649 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1651 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1650 ui.write(_(" (specify a commit editor in your configuration"
1652 ui.write(_(" (specify a commit editor in your configuration"
1651 " file)\n"))
1653 " file)\n"))
1652 problems += 1
1654 problems += 1
1653
1655
1654 # check username
1656 # check username
1655 ui.status(_("Checking username...\n"))
1657 ui.status(_("Checking username...\n"))
1656 try:
1658 try:
1657 ui.username()
1659 ui.username()
1658 except util.Abort, e:
1660 except util.Abort, e:
1659 ui.write(" %s\n" % e)
1661 ui.write(" %s\n" % e)
1660 ui.write(_(" (specify a username in your configuration file)\n"))
1662 ui.write(_(" (specify a username in your configuration file)\n"))
1661 problems += 1
1663 problems += 1
1662
1664
1663 if not problems:
1665 if not problems:
1664 ui.status(_("No problems detected\n"))
1666 ui.status(_("No problems detected\n"))
1665 else:
1667 else:
1666 ui.write(_("%s problems detected,"
1668 ui.write(_("%s problems detected,"
1667 " please check your install!\n") % problems)
1669 " please check your install!\n") % problems)
1668
1670
1669 return problems
1671 return problems
1670
1672
1671 def debugrename(ui, repo, file1, *pats, **opts):
1673 def debugrename(ui, repo, file1, *pats, **opts):
1672 """dump rename information"""
1674 """dump rename information"""
1673
1675
1674 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1676 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1675 m = cmdutil.match(repo, (file1,) + pats, opts)
1677 m = cmdutil.match(repo, (file1,) + pats, opts)
1676 for abs in ctx.walk(m):
1678 for abs in ctx.walk(m):
1677 fctx = ctx[abs]
1679 fctx = ctx[abs]
1678 o = fctx.filelog().renamed(fctx.filenode())
1680 o = fctx.filelog().renamed(fctx.filenode())
1679 rel = m.rel(abs)
1681 rel = m.rel(abs)
1680 if o:
1682 if o:
1681 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1683 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1682 else:
1684 else:
1683 ui.write(_("%s not renamed\n") % rel)
1685 ui.write(_("%s not renamed\n") % rel)
1684
1686
1685 def debugwalk(ui, repo, *pats, **opts):
1687 def debugwalk(ui, repo, *pats, **opts):
1686 """show how files match on given patterns"""
1688 """show how files match on given patterns"""
1687 m = cmdutil.match(repo, pats, opts)
1689 m = cmdutil.match(repo, pats, opts)
1688 items = list(repo.walk(m))
1690 items = list(repo.walk(m))
1689 if not items:
1691 if not items:
1690 return
1692 return
1691 fmt = 'f %%-%ds %%-%ds %%s' % (
1693 fmt = 'f %%-%ds %%-%ds %%s' % (
1692 max([len(abs) for abs in items]),
1694 max([len(abs) for abs in items]),
1693 max([len(m.rel(abs)) for abs in items]))
1695 max([len(m.rel(abs)) for abs in items]))
1694 for abs in items:
1696 for abs in items:
1695 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1697 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1696 ui.write("%s\n" % line.rstrip())
1698 ui.write("%s\n" % line.rstrip())
1697
1699
1698 def debugwireargs(ui, repopath, *vals, **opts):
1700 def debugwireargs(ui, repopath, *vals, **opts):
1699 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1701 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1700 for opt in remoteopts:
1702 for opt in remoteopts:
1701 del opts[opt[1]]
1703 del opts[opt[1]]
1702 args = {}
1704 args = {}
1703 for k, v in opts.iteritems():
1705 for k, v in opts.iteritems():
1704 if v:
1706 if v:
1705 args[k] = v
1707 args[k] = v
1706 # run twice to check that we don't mess up the stream for the next command
1708 # run twice to check that we don't mess up the stream for the next command
1707 res1 = repo.debugwireargs(*vals, **args)
1709 res1 = repo.debugwireargs(*vals, **args)
1708 res2 = repo.debugwireargs(*vals, **args)
1710 res2 = repo.debugwireargs(*vals, **args)
1709 ui.write("%s\n" % res1)
1711 ui.write("%s\n" % res1)
1710 if res1 != res2:
1712 if res1 != res2:
1711 ui.warn("%s\n" % res2)
1713 ui.warn("%s\n" % res2)
1712
1714
1713 def diff(ui, repo, *pats, **opts):
1715 def diff(ui, repo, *pats, **opts):
1714 """diff repository (or selected files)
1716 """diff repository (or selected files)
1715
1717
1716 Show differences between revisions for the specified files.
1718 Show differences between revisions for the specified files.
1717
1719
1718 Differences between files are shown using the unified diff format.
1720 Differences between files are shown using the unified diff format.
1719
1721
1720 .. note::
1722 .. note::
1721 diff may generate unexpected results for merges, as it will
1723 diff may generate unexpected results for merges, as it will
1722 default to comparing against the working directory's first
1724 default to comparing against the working directory's first
1723 parent changeset if no revisions are specified.
1725 parent changeset if no revisions are specified.
1724
1726
1725 When two revision arguments are given, then changes are shown
1727 When two revision arguments are given, then changes are shown
1726 between those revisions. If only one revision is specified then
1728 between those revisions. If only one revision is specified then
1727 that revision is compared to the working directory, and, when no
1729 that revision is compared to the working directory, and, when no
1728 revisions are specified, the working directory files are compared
1730 revisions are specified, the working directory files are compared
1729 to its parent.
1731 to its parent.
1730
1732
1731 Alternatively you can specify -c/--change with a revision to see
1733 Alternatively you can specify -c/--change with a revision to see
1732 the changes in that changeset relative to its first parent.
1734 the changes in that changeset relative to its first parent.
1733
1735
1734 Without the -a/--text option, diff will avoid generating diffs of
1736 Without the -a/--text option, diff will avoid generating diffs of
1735 files it detects as binary. With -a, diff will generate a diff
1737 files it detects as binary. With -a, diff will generate a diff
1736 anyway, probably with undesirable results.
1738 anyway, probably with undesirable results.
1737
1739
1738 Use the -g/--git option to generate diffs in the git extended diff
1740 Use the -g/--git option to generate diffs in the git extended diff
1739 format. For more information, read :hg:`help diffs`.
1741 format. For more information, read :hg:`help diffs`.
1740
1742
1741 Returns 0 on success.
1743 Returns 0 on success.
1742 """
1744 """
1743
1745
1744 revs = opts.get('rev')
1746 revs = opts.get('rev')
1745 change = opts.get('change')
1747 change = opts.get('change')
1746 stat = opts.get('stat')
1748 stat = opts.get('stat')
1747 reverse = opts.get('reverse')
1749 reverse = opts.get('reverse')
1748
1750
1749 if revs and change:
1751 if revs and change:
1750 msg = _('cannot specify --rev and --change at the same time')
1752 msg = _('cannot specify --rev and --change at the same time')
1751 raise util.Abort(msg)
1753 raise util.Abort(msg)
1752 elif change:
1754 elif change:
1753 node2 = cmdutil.revsingle(repo, change, None).node()
1755 node2 = cmdutil.revsingle(repo, change, None).node()
1754 node1 = repo[node2].p1().node()
1756 node1 = repo[node2].p1().node()
1755 else:
1757 else:
1756 node1, node2 = cmdutil.revpair(repo, revs)
1758 node1, node2 = cmdutil.revpair(repo, revs)
1757
1759
1758 if reverse:
1760 if reverse:
1759 node1, node2 = node2, node1
1761 node1, node2 = node2, node1
1760
1762
1761 diffopts = patch.diffopts(ui, opts)
1763 diffopts = patch.diffopts(ui, opts)
1762 m = cmdutil.match(repo, pats, opts)
1764 m = cmdutil.match(repo, pats, opts)
1763 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1765 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1764 listsubrepos=opts.get('subrepos'))
1766 listsubrepos=opts.get('subrepos'))
1765
1767
1766 def export(ui, repo, *changesets, **opts):
1768 def export(ui, repo, *changesets, **opts):
1767 """dump the header and diffs for one or more changesets
1769 """dump the header and diffs for one or more changesets
1768
1770
1769 Print the changeset header and diffs for one or more revisions.
1771 Print the changeset header and diffs for one or more revisions.
1770
1772
1771 The information shown in the changeset header is: author, date,
1773 The information shown in the changeset header is: author, date,
1772 branch name (if non-default), changeset hash, parent(s) and commit
1774 branch name (if non-default), changeset hash, parent(s) and commit
1773 comment.
1775 comment.
1774
1776
1775 .. note::
1777 .. note::
1776 export may generate unexpected diff output for merge
1778 export may generate unexpected diff output for merge
1777 changesets, as it will compare the merge changeset against its
1779 changesets, as it will compare the merge changeset against its
1778 first parent only.
1780 first parent only.
1779
1781
1780 Output may be to a file, in which case the name of the file is
1782 Output may be to a file, in which case the name of the file is
1781 given using a format string. The formatting rules are as follows:
1783 given using a format string. The formatting rules are as follows:
1782
1784
1783 :``%%``: literal "%" character
1785 :``%%``: literal "%" character
1784 :``%H``: changeset hash (40 hexadecimal digits)
1786 :``%H``: changeset hash (40 hexadecimal digits)
1785 :``%N``: number of patches being generated
1787 :``%N``: number of patches being generated
1786 :``%R``: changeset revision number
1788 :``%R``: changeset revision number
1787 :``%b``: basename of the exporting repository
1789 :``%b``: basename of the exporting repository
1788 :``%h``: short-form changeset hash (12 hexadecimal digits)
1790 :``%h``: short-form changeset hash (12 hexadecimal digits)
1789 :``%n``: zero-padded sequence number, starting at 1
1791 :``%n``: zero-padded sequence number, starting at 1
1790 :``%r``: zero-padded changeset revision number
1792 :``%r``: zero-padded changeset revision number
1791
1793
1792 Without the -a/--text option, export will avoid generating diffs
1794 Without the -a/--text option, export will avoid generating diffs
1793 of files it detects as binary. With -a, export will generate a
1795 of files it detects as binary. With -a, export will generate a
1794 diff anyway, probably with undesirable results.
1796 diff anyway, probably with undesirable results.
1795
1797
1796 Use the -g/--git option to generate diffs in the git extended diff
1798 Use the -g/--git option to generate diffs in the git extended diff
1797 format. See :hg:`help diffs` for more information.
1799 format. See :hg:`help diffs` for more information.
1798
1800
1799 With the --switch-parent option, the diff will be against the
1801 With the --switch-parent option, the diff will be against the
1800 second parent. It can be useful to review a merge.
1802 second parent. It can be useful to review a merge.
1801
1803
1802 Returns 0 on success.
1804 Returns 0 on success.
1803 """
1805 """
1804 changesets += tuple(opts.get('rev', []))
1806 changesets += tuple(opts.get('rev', []))
1805 if not changesets:
1807 if not changesets:
1806 raise util.Abort(_("export requires at least one changeset"))
1808 raise util.Abort(_("export requires at least one changeset"))
1807 revs = cmdutil.revrange(repo, changesets)
1809 revs = cmdutil.revrange(repo, changesets)
1808 if len(revs) > 1:
1810 if len(revs) > 1:
1809 ui.note(_('exporting patches:\n'))
1811 ui.note(_('exporting patches:\n'))
1810 else:
1812 else:
1811 ui.note(_('exporting patch:\n'))
1813 ui.note(_('exporting patch:\n'))
1812 cmdutil.export(repo, revs, template=opts.get('output'),
1814 cmdutil.export(repo, revs, template=opts.get('output'),
1813 switch_parent=opts.get('switch_parent'),
1815 switch_parent=opts.get('switch_parent'),
1814 opts=patch.diffopts(ui, opts))
1816 opts=patch.diffopts(ui, opts))
1815
1817
1816 def forget(ui, repo, *pats, **opts):
1818 def forget(ui, repo, *pats, **opts):
1817 """forget the specified files on the next commit
1819 """forget the specified files on the next commit
1818
1820
1819 Mark the specified files so they will no longer be tracked
1821 Mark the specified files so they will no longer be tracked
1820 after the next commit.
1822 after the next commit.
1821
1823
1822 This only removes files from the current branch, not from the
1824 This only removes files from the current branch, not from the
1823 entire project history, and it does not delete them from the
1825 entire project history, and it does not delete them from the
1824 working directory.
1826 working directory.
1825
1827
1826 To undo a forget before the next commit, see :hg:`add`.
1828 To undo a forget before the next commit, see :hg:`add`.
1827
1829
1828 Returns 0 on success.
1830 Returns 0 on success.
1829 """
1831 """
1830
1832
1831 if not pats:
1833 if not pats:
1832 raise util.Abort(_('no files specified'))
1834 raise util.Abort(_('no files specified'))
1833
1835
1834 m = cmdutil.match(repo, pats, opts)
1836 m = cmdutil.match(repo, pats, opts)
1835 s = repo.status(match=m, clean=True)
1837 s = repo.status(match=m, clean=True)
1836 forget = sorted(s[0] + s[1] + s[3] + s[6])
1838 forget = sorted(s[0] + s[1] + s[3] + s[6])
1837 errs = 0
1839 errs = 0
1838
1840
1839 for f in m.files():
1841 for f in m.files():
1840 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1842 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1841 ui.warn(_('not removing %s: file is already untracked\n')
1843 ui.warn(_('not removing %s: file is already untracked\n')
1842 % m.rel(f))
1844 % m.rel(f))
1843 errs = 1
1845 errs = 1
1844
1846
1845 for f in forget:
1847 for f in forget:
1846 if ui.verbose or not m.exact(f):
1848 if ui.verbose or not m.exact(f):
1847 ui.status(_('removing %s\n') % m.rel(f))
1849 ui.status(_('removing %s\n') % m.rel(f))
1848
1850
1849 repo[None].remove(forget, unlink=False)
1851 repo[None].remove(forget, unlink=False)
1850 return errs
1852 return errs
1851
1853
1852 def grep(ui, repo, pattern, *pats, **opts):
1854 def grep(ui, repo, pattern, *pats, **opts):
1853 """search for a pattern in specified files and revisions
1855 """search for a pattern in specified files and revisions
1854
1856
1855 Search revisions of files for a regular expression.
1857 Search revisions of files for a regular expression.
1856
1858
1857 This command behaves differently than Unix grep. It only accepts
1859 This command behaves differently than Unix grep. It only accepts
1858 Python/Perl regexps. It searches repository history, not the
1860 Python/Perl regexps. It searches repository history, not the
1859 working directory. It always prints the revision number in which a
1861 working directory. It always prints the revision number in which a
1860 match appears.
1862 match appears.
1861
1863
1862 By default, grep only prints output for the first revision of a
1864 By default, grep only prints output for the first revision of a
1863 file in which it finds a match. To get it to print every revision
1865 file in which it finds a match. To get it to print every revision
1864 that contains a change in match status ("-" for a match that
1866 that contains a change in match status ("-" for a match that
1865 becomes a non-match, or "+" for a non-match that becomes a match),
1867 becomes a non-match, or "+" for a non-match that becomes a match),
1866 use the --all flag.
1868 use the --all flag.
1867
1869
1868 Returns 0 if a match is found, 1 otherwise.
1870 Returns 0 if a match is found, 1 otherwise.
1869 """
1871 """
1870 reflags = 0
1872 reflags = 0
1871 if opts.get('ignore_case'):
1873 if opts.get('ignore_case'):
1872 reflags |= re.I
1874 reflags |= re.I
1873 try:
1875 try:
1874 regexp = re.compile(pattern, reflags)
1876 regexp = re.compile(pattern, reflags)
1875 except re.error, inst:
1877 except re.error, inst:
1876 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1878 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1877 return 1
1879 return 1
1878 sep, eol = ':', '\n'
1880 sep, eol = ':', '\n'
1879 if opts.get('print0'):
1881 if opts.get('print0'):
1880 sep = eol = '\0'
1882 sep = eol = '\0'
1881
1883
1882 getfile = util.lrucachefunc(repo.file)
1884 getfile = util.lrucachefunc(repo.file)
1883
1885
1884 def matchlines(body):
1886 def matchlines(body):
1885 begin = 0
1887 begin = 0
1886 linenum = 0
1888 linenum = 0
1887 while True:
1889 while True:
1888 match = regexp.search(body, begin)
1890 match = regexp.search(body, begin)
1889 if not match:
1891 if not match:
1890 break
1892 break
1891 mstart, mend = match.span()
1893 mstart, mend = match.span()
1892 linenum += body.count('\n', begin, mstart) + 1
1894 linenum += body.count('\n', begin, mstart) + 1
1893 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1895 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1894 begin = body.find('\n', mend) + 1 or len(body)
1896 begin = body.find('\n', mend) + 1 or len(body)
1895 lend = begin - 1
1897 lend = begin - 1
1896 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1898 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1897
1899
1898 class linestate(object):
1900 class linestate(object):
1899 def __init__(self, line, linenum, colstart, colend):
1901 def __init__(self, line, linenum, colstart, colend):
1900 self.line = line
1902 self.line = line
1901 self.linenum = linenum
1903 self.linenum = linenum
1902 self.colstart = colstart
1904 self.colstart = colstart
1903 self.colend = colend
1905 self.colend = colend
1904
1906
1905 def __hash__(self):
1907 def __hash__(self):
1906 return hash((self.linenum, self.line))
1908 return hash((self.linenum, self.line))
1907
1909
1908 def __eq__(self, other):
1910 def __eq__(self, other):
1909 return self.line == other.line
1911 return self.line == other.line
1910
1912
1911 matches = {}
1913 matches = {}
1912 copies = {}
1914 copies = {}
1913 def grepbody(fn, rev, body):
1915 def grepbody(fn, rev, body):
1914 matches[rev].setdefault(fn, [])
1916 matches[rev].setdefault(fn, [])
1915 m = matches[rev][fn]
1917 m = matches[rev][fn]
1916 for lnum, cstart, cend, line in matchlines(body):
1918 for lnum, cstart, cend, line in matchlines(body):
1917 s = linestate(line, lnum, cstart, cend)
1919 s = linestate(line, lnum, cstart, cend)
1918 m.append(s)
1920 m.append(s)
1919
1921
1920 def difflinestates(a, b):
1922 def difflinestates(a, b):
1921 sm = difflib.SequenceMatcher(None, a, b)
1923 sm = difflib.SequenceMatcher(None, a, b)
1922 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1924 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1923 if tag == 'insert':
1925 if tag == 'insert':
1924 for i in xrange(blo, bhi):
1926 for i in xrange(blo, bhi):
1925 yield ('+', b[i])
1927 yield ('+', b[i])
1926 elif tag == 'delete':
1928 elif tag == 'delete':
1927 for i in xrange(alo, ahi):
1929 for i in xrange(alo, ahi):
1928 yield ('-', a[i])
1930 yield ('-', a[i])
1929 elif tag == 'replace':
1931 elif tag == 'replace':
1930 for i in xrange(alo, ahi):
1932 for i in xrange(alo, ahi):
1931 yield ('-', a[i])
1933 yield ('-', a[i])
1932 for i in xrange(blo, bhi):
1934 for i in xrange(blo, bhi):
1933 yield ('+', b[i])
1935 yield ('+', b[i])
1934
1936
1935 def display(fn, ctx, pstates, states):
1937 def display(fn, ctx, pstates, states):
1936 rev = ctx.rev()
1938 rev = ctx.rev()
1937 datefunc = ui.quiet and util.shortdate or util.datestr
1939 datefunc = ui.quiet and util.shortdate or util.datestr
1938 found = False
1940 found = False
1939 filerevmatches = {}
1941 filerevmatches = {}
1940 def binary():
1942 def binary():
1941 flog = getfile(fn)
1943 flog = getfile(fn)
1942 return util.binary(flog.read(ctx.filenode(fn)))
1944 return util.binary(flog.read(ctx.filenode(fn)))
1943
1945
1944 if opts.get('all'):
1946 if opts.get('all'):
1945 iter = difflinestates(pstates, states)
1947 iter = difflinestates(pstates, states)
1946 else:
1948 else:
1947 iter = [('', l) for l in states]
1949 iter = [('', l) for l in states]
1948 for change, l in iter:
1950 for change, l in iter:
1949 cols = [fn, str(rev)]
1951 cols = [fn, str(rev)]
1950 before, match, after = None, None, None
1952 before, match, after = None, None, None
1951 if opts.get('line_number'):
1953 if opts.get('line_number'):
1952 cols.append(str(l.linenum))
1954 cols.append(str(l.linenum))
1953 if opts.get('all'):
1955 if opts.get('all'):
1954 cols.append(change)
1956 cols.append(change)
1955 if opts.get('user'):
1957 if opts.get('user'):
1956 cols.append(ui.shortuser(ctx.user()))
1958 cols.append(ui.shortuser(ctx.user()))
1957 if opts.get('date'):
1959 if opts.get('date'):
1958 cols.append(datefunc(ctx.date()))
1960 cols.append(datefunc(ctx.date()))
1959 if opts.get('files_with_matches'):
1961 if opts.get('files_with_matches'):
1960 c = (fn, rev)
1962 c = (fn, rev)
1961 if c in filerevmatches:
1963 if c in filerevmatches:
1962 continue
1964 continue
1963 filerevmatches[c] = 1
1965 filerevmatches[c] = 1
1964 else:
1966 else:
1965 before = l.line[:l.colstart]
1967 before = l.line[:l.colstart]
1966 match = l.line[l.colstart:l.colend]
1968 match = l.line[l.colstart:l.colend]
1967 after = l.line[l.colend:]
1969 after = l.line[l.colend:]
1968 ui.write(sep.join(cols))
1970 ui.write(sep.join(cols))
1969 if before is not None:
1971 if before is not None:
1970 if not opts.get('text') and binary():
1972 if not opts.get('text') and binary():
1971 ui.write(sep + " Binary file matches")
1973 ui.write(sep + " Binary file matches")
1972 else:
1974 else:
1973 ui.write(sep + before)
1975 ui.write(sep + before)
1974 ui.write(match, label='grep.match')
1976 ui.write(match, label='grep.match')
1975 ui.write(after)
1977 ui.write(after)
1976 ui.write(eol)
1978 ui.write(eol)
1977 found = True
1979 found = True
1978 return found
1980 return found
1979
1981
1980 skip = {}
1982 skip = {}
1981 revfiles = {}
1983 revfiles = {}
1982 matchfn = cmdutil.match(repo, pats, opts)
1984 matchfn = cmdutil.match(repo, pats, opts)
1983 found = False
1985 found = False
1984 follow = opts.get('follow')
1986 follow = opts.get('follow')
1985
1987
1986 def prep(ctx, fns):
1988 def prep(ctx, fns):
1987 rev = ctx.rev()
1989 rev = ctx.rev()
1988 pctx = ctx.p1()
1990 pctx = ctx.p1()
1989 parent = pctx.rev()
1991 parent = pctx.rev()
1990 matches.setdefault(rev, {})
1992 matches.setdefault(rev, {})
1991 matches.setdefault(parent, {})
1993 matches.setdefault(parent, {})
1992 files = revfiles.setdefault(rev, [])
1994 files = revfiles.setdefault(rev, [])
1993 for fn in fns:
1995 for fn in fns:
1994 flog = getfile(fn)
1996 flog = getfile(fn)
1995 try:
1997 try:
1996 fnode = ctx.filenode(fn)
1998 fnode = ctx.filenode(fn)
1997 except error.LookupError:
1999 except error.LookupError:
1998 continue
2000 continue
1999
2001
2000 copied = flog.renamed(fnode)
2002 copied = flog.renamed(fnode)
2001 copy = follow and copied and copied[0]
2003 copy = follow and copied and copied[0]
2002 if copy:
2004 if copy:
2003 copies.setdefault(rev, {})[fn] = copy
2005 copies.setdefault(rev, {})[fn] = copy
2004 if fn in skip:
2006 if fn in skip:
2005 if copy:
2007 if copy:
2006 skip[copy] = True
2008 skip[copy] = True
2007 continue
2009 continue
2008 files.append(fn)
2010 files.append(fn)
2009
2011
2010 if fn not in matches[rev]:
2012 if fn not in matches[rev]:
2011 grepbody(fn, rev, flog.read(fnode))
2013 grepbody(fn, rev, flog.read(fnode))
2012
2014
2013 pfn = copy or fn
2015 pfn = copy or fn
2014 if pfn not in matches[parent]:
2016 if pfn not in matches[parent]:
2015 try:
2017 try:
2016 fnode = pctx.filenode(pfn)
2018 fnode = pctx.filenode(pfn)
2017 grepbody(pfn, parent, flog.read(fnode))
2019 grepbody(pfn, parent, flog.read(fnode))
2018 except error.LookupError:
2020 except error.LookupError:
2019 pass
2021 pass
2020
2022
2021 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2023 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2022 rev = ctx.rev()
2024 rev = ctx.rev()
2023 parent = ctx.p1().rev()
2025 parent = ctx.p1().rev()
2024 for fn in sorted(revfiles.get(rev, [])):
2026 for fn in sorted(revfiles.get(rev, [])):
2025 states = matches[rev][fn]
2027 states = matches[rev][fn]
2026 copy = copies.get(rev, {}).get(fn)
2028 copy = copies.get(rev, {}).get(fn)
2027 if fn in skip:
2029 if fn in skip:
2028 if copy:
2030 if copy:
2029 skip[copy] = True
2031 skip[copy] = True
2030 continue
2032 continue
2031 pstates = matches.get(parent, {}).get(copy or fn, [])
2033 pstates = matches.get(parent, {}).get(copy or fn, [])
2032 if pstates or states:
2034 if pstates or states:
2033 r = display(fn, ctx, pstates, states)
2035 r = display(fn, ctx, pstates, states)
2034 found = found or r
2036 found = found or r
2035 if r and not opts.get('all'):
2037 if r and not opts.get('all'):
2036 skip[fn] = True
2038 skip[fn] = True
2037 if copy:
2039 if copy:
2038 skip[copy] = True
2040 skip[copy] = True
2039 del matches[rev]
2041 del matches[rev]
2040 del revfiles[rev]
2042 del revfiles[rev]
2041
2043
2042 return not found
2044 return not found
2043
2045
2044 def heads(ui, repo, *branchrevs, **opts):
2046 def heads(ui, repo, *branchrevs, **opts):
2045 """show current repository heads or show branch heads
2047 """show current repository heads or show branch heads
2046
2048
2047 With no arguments, show all repository branch heads.
2049 With no arguments, show all repository branch heads.
2048
2050
2049 Repository "heads" are changesets with no child changesets. They are
2051 Repository "heads" are changesets with no child changesets. They are
2050 where development generally takes place and are the usual targets
2052 where development generally takes place and are the usual targets
2051 for update and merge operations. Branch heads are changesets that have
2053 for update and merge operations. Branch heads are changesets that have
2052 no child changeset on the same branch.
2054 no child changeset on the same branch.
2053
2055
2054 If one or more REVs are given, only branch heads on the branches
2056 If one or more REVs are given, only branch heads on the branches
2055 associated with the specified changesets are shown.
2057 associated with the specified changesets are shown.
2056
2058
2057 If -c/--closed is specified, also show branch heads marked closed
2059 If -c/--closed is specified, also show branch heads marked closed
2058 (see :hg:`commit --close-branch`).
2060 (see :hg:`commit --close-branch`).
2059
2061
2060 If STARTREV is specified, only those heads that are descendants of
2062 If STARTREV is specified, only those heads that are descendants of
2061 STARTREV will be displayed.
2063 STARTREV will be displayed.
2062
2064
2063 If -t/--topo is specified, named branch mechanics will be ignored and only
2065 If -t/--topo is specified, named branch mechanics will be ignored and only
2064 changesets without children will be shown.
2066 changesets without children will be shown.
2065
2067
2066 Returns 0 if matching heads are found, 1 if not.
2068 Returns 0 if matching heads are found, 1 if not.
2067 """
2069 """
2068
2070
2069 start = None
2071 start = None
2070 if 'rev' in opts:
2072 if 'rev' in opts:
2071 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2073 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2072
2074
2073 if opts.get('topo'):
2075 if opts.get('topo'):
2074 heads = [repo[h] for h in repo.heads(start)]
2076 heads = [repo[h] for h in repo.heads(start)]
2075 else:
2077 else:
2076 heads = []
2078 heads = []
2077 for b, ls in repo.branchmap().iteritems():
2079 for b, ls in repo.branchmap().iteritems():
2078 if start is None:
2080 if start is None:
2079 heads += [repo[h] for h in ls]
2081 heads += [repo[h] for h in ls]
2080 continue
2082 continue
2081 startrev = repo.changelog.rev(start)
2083 startrev = repo.changelog.rev(start)
2082 descendants = set(repo.changelog.descendants(startrev))
2084 descendants = set(repo.changelog.descendants(startrev))
2083 descendants.add(startrev)
2085 descendants.add(startrev)
2084 rev = repo.changelog.rev
2086 rev = repo.changelog.rev
2085 heads += [repo[h] for h in ls if rev(h) in descendants]
2087 heads += [repo[h] for h in ls if rev(h) in descendants]
2086
2088
2087 if branchrevs:
2089 if branchrevs:
2088 branches = set(repo[br].branch() for br in branchrevs)
2090 branches = set(repo[br].branch() for br in branchrevs)
2089 heads = [h for h in heads if h.branch() in branches]
2091 heads = [h for h in heads if h.branch() in branches]
2090
2092
2091 if not opts.get('closed'):
2093 if not opts.get('closed'):
2092 heads = [h for h in heads if not h.extra().get('close')]
2094 heads = [h for h in heads if not h.extra().get('close')]
2093
2095
2094 if opts.get('active') and branchrevs:
2096 if opts.get('active') and branchrevs:
2095 dagheads = repo.heads(start)
2097 dagheads = repo.heads(start)
2096 heads = [h for h in heads if h.node() in dagheads]
2098 heads = [h for h in heads if h.node() in dagheads]
2097
2099
2098 if branchrevs:
2100 if branchrevs:
2099 haveheads = set(h.branch() for h in heads)
2101 haveheads = set(h.branch() for h in heads)
2100 if branches - haveheads:
2102 if branches - haveheads:
2101 headless = ', '.join(b for b in branches - haveheads)
2103 headless = ', '.join(b for b in branches - haveheads)
2102 msg = _('no open branch heads found on branches %s')
2104 msg = _('no open branch heads found on branches %s')
2103 if opts.get('rev'):
2105 if opts.get('rev'):
2104 msg += _(' (started at %s)' % opts['rev'])
2106 msg += _(' (started at %s)' % opts['rev'])
2105 ui.warn((msg + '\n') % headless)
2107 ui.warn((msg + '\n') % headless)
2106
2108
2107 if not heads:
2109 if not heads:
2108 return 1
2110 return 1
2109
2111
2110 heads = sorted(heads, key=lambda x: -x.rev())
2112 heads = sorted(heads, key=lambda x: -x.rev())
2111 displayer = cmdutil.show_changeset(ui, repo, opts)
2113 displayer = cmdutil.show_changeset(ui, repo, opts)
2112 for ctx in heads:
2114 for ctx in heads:
2113 displayer.show(ctx)
2115 displayer.show(ctx)
2114 displayer.close()
2116 displayer.close()
2115
2117
2116 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2118 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2117 """show help for a given topic or a help overview
2119 """show help for a given topic or a help overview
2118
2120
2119 With no arguments, print a list of commands with short help messages.
2121 With no arguments, print a list of commands with short help messages.
2120
2122
2121 Given a topic, extension, or command name, print help for that
2123 Given a topic, extension, or command name, print help for that
2122 topic.
2124 topic.
2123
2125
2124 Returns 0 if successful.
2126 Returns 0 if successful.
2125 """
2127 """
2126 option_lists = []
2128 option_lists = []
2127 textwidth = min(ui.termwidth(), 80) - 2
2129 textwidth = min(ui.termwidth(), 80) - 2
2128
2130
2129 def addglobalopts(aliases):
2131 def addglobalopts(aliases):
2130 if ui.verbose:
2132 if ui.verbose:
2131 option_lists.append((_("global options:"), globalopts))
2133 option_lists.append((_("global options:"), globalopts))
2132 if name == 'shortlist':
2134 if name == 'shortlist':
2133 option_lists.append((_('use "hg help" for the full list '
2135 option_lists.append((_('use "hg help" for the full list '
2134 'of commands'), ()))
2136 'of commands'), ()))
2135 else:
2137 else:
2136 if name == 'shortlist':
2138 if name == 'shortlist':
2137 msg = _('use "hg help" for the full list of commands '
2139 msg = _('use "hg help" for the full list of commands '
2138 'or "hg -v" for details')
2140 'or "hg -v" for details')
2139 elif name and not full:
2141 elif name and not full:
2140 msg = _('use "hg help %s" to show the full help text' % name)
2142 msg = _('use "hg help %s" to show the full help text' % name)
2141 elif aliases:
2143 elif aliases:
2142 msg = _('use "hg -v help%s" to show builtin aliases and '
2144 msg = _('use "hg -v help%s" to show builtin aliases and '
2143 'global options') % (name and " " + name or "")
2145 'global options') % (name and " " + name or "")
2144 else:
2146 else:
2145 msg = _('use "hg -v help %s" to show global options') % name
2147 msg = _('use "hg -v help %s" to show global options') % name
2146 option_lists.append((msg, ()))
2148 option_lists.append((msg, ()))
2147
2149
2148 def helpcmd(name):
2150 def helpcmd(name):
2149 if with_version:
2151 if with_version:
2150 version_(ui)
2152 version_(ui)
2151 ui.write('\n')
2153 ui.write('\n')
2152
2154
2153 try:
2155 try:
2154 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2156 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2155 except error.AmbiguousCommand, inst:
2157 except error.AmbiguousCommand, inst:
2156 # py3k fix: except vars can't be used outside the scope of the
2158 # py3k fix: except vars can't be used outside the scope of the
2157 # except block, nor can be used inside a lambda. python issue4617
2159 # except block, nor can be used inside a lambda. python issue4617
2158 prefix = inst.args[0]
2160 prefix = inst.args[0]
2159 select = lambda c: c.lstrip('^').startswith(prefix)
2161 select = lambda c: c.lstrip('^').startswith(prefix)
2160 helplist(_('list of commands:\n\n'), select)
2162 helplist(_('list of commands:\n\n'), select)
2161 return
2163 return
2162
2164
2163 # check if it's an invalid alias and display its error if it is
2165 # check if it's an invalid alias and display its error if it is
2164 if getattr(entry[0], 'badalias', False):
2166 if getattr(entry[0], 'badalias', False):
2165 if not unknowncmd:
2167 if not unknowncmd:
2166 entry[0](ui)
2168 entry[0](ui)
2167 return
2169 return
2168
2170
2169 # synopsis
2171 # synopsis
2170 if len(entry) > 2:
2172 if len(entry) > 2:
2171 if entry[2].startswith('hg'):
2173 if entry[2].startswith('hg'):
2172 ui.write("%s\n" % entry[2])
2174 ui.write("%s\n" % entry[2])
2173 else:
2175 else:
2174 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2176 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2175 else:
2177 else:
2176 ui.write('hg %s\n' % aliases[0])
2178 ui.write('hg %s\n' % aliases[0])
2177
2179
2178 # aliases
2180 # aliases
2179 if full and not ui.quiet and len(aliases) > 1:
2181 if full and not ui.quiet and len(aliases) > 1:
2180 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2182 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2181
2183
2182 # description
2184 # description
2183 doc = gettext(entry[0].__doc__)
2185 doc = gettext(entry[0].__doc__)
2184 if not doc:
2186 if not doc:
2185 doc = _("(no help text available)")
2187 doc = _("(no help text available)")
2186 if hasattr(entry[0], 'definition'): # aliased command
2188 if hasattr(entry[0], 'definition'): # aliased command
2187 if entry[0].definition.startswith('!'): # shell alias
2189 if entry[0].definition.startswith('!'): # shell alias
2188 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2190 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2189 else:
2191 else:
2190 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2192 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2191 if ui.quiet or not full:
2193 if ui.quiet or not full:
2192 doc = doc.splitlines()[0]
2194 doc = doc.splitlines()[0]
2193 keep = ui.verbose and ['verbose'] or []
2195 keep = ui.verbose and ['verbose'] or []
2194 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2196 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2195 ui.write("\n%s\n" % formatted)
2197 ui.write("\n%s\n" % formatted)
2196 if pruned:
2198 if pruned:
2197 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2199 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2198
2200
2199 if not ui.quiet:
2201 if not ui.quiet:
2200 # options
2202 # options
2201 if entry[1]:
2203 if entry[1]:
2202 option_lists.append((_("options:\n"), entry[1]))
2204 option_lists.append((_("options:\n"), entry[1]))
2203
2205
2204 addglobalopts(False)
2206 addglobalopts(False)
2205
2207
2206 def helplist(header, select=None):
2208 def helplist(header, select=None):
2207 h = {}
2209 h = {}
2208 cmds = {}
2210 cmds = {}
2209 for c, e in table.iteritems():
2211 for c, e in table.iteritems():
2210 f = c.split("|", 1)[0]
2212 f = c.split("|", 1)[0]
2211 if select and not select(f):
2213 if select and not select(f):
2212 continue
2214 continue
2213 if (not select and name != 'shortlist' and
2215 if (not select and name != 'shortlist' and
2214 e[0].__module__ != __name__):
2216 e[0].__module__ != __name__):
2215 continue
2217 continue
2216 if name == "shortlist" and not f.startswith("^"):
2218 if name == "shortlist" and not f.startswith("^"):
2217 continue
2219 continue
2218 f = f.lstrip("^")
2220 f = f.lstrip("^")
2219 if not ui.debugflag and f.startswith("debug"):
2221 if not ui.debugflag and f.startswith("debug"):
2220 continue
2222 continue
2221 doc = e[0].__doc__
2223 doc = e[0].__doc__
2222 if doc and 'DEPRECATED' in doc and not ui.verbose:
2224 if doc and 'DEPRECATED' in doc and not ui.verbose:
2223 continue
2225 continue
2224 doc = gettext(doc)
2226 doc = gettext(doc)
2225 if not doc:
2227 if not doc:
2226 doc = _("(no help text available)")
2228 doc = _("(no help text available)")
2227 h[f] = doc.splitlines()[0].rstrip()
2229 h[f] = doc.splitlines()[0].rstrip()
2228 cmds[f] = c.lstrip("^")
2230 cmds[f] = c.lstrip("^")
2229
2231
2230 if not h:
2232 if not h:
2231 ui.status(_('no commands defined\n'))
2233 ui.status(_('no commands defined\n'))
2232 return
2234 return
2233
2235
2234 ui.status(header)
2236 ui.status(header)
2235 fns = sorted(h)
2237 fns = sorted(h)
2236 m = max(map(len, fns))
2238 m = max(map(len, fns))
2237 for f in fns:
2239 for f in fns:
2238 if ui.verbose:
2240 if ui.verbose:
2239 commands = cmds[f].replace("|",", ")
2241 commands = cmds[f].replace("|",", ")
2240 ui.write(" %s:\n %s\n"%(commands, h[f]))
2242 ui.write(" %s:\n %s\n"%(commands, h[f]))
2241 else:
2243 else:
2242 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2244 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2243 initindent=' %-*s ' % (m, f),
2245 initindent=' %-*s ' % (m, f),
2244 hangindent=' ' * (m + 4))))
2246 hangindent=' ' * (m + 4))))
2245
2247
2246 if not ui.quiet:
2248 if not ui.quiet:
2247 addglobalopts(True)
2249 addglobalopts(True)
2248
2250
2249 def helptopic(name):
2251 def helptopic(name):
2250 for names, header, doc in help.helptable:
2252 for names, header, doc in help.helptable:
2251 if name in names:
2253 if name in names:
2252 break
2254 break
2253 else:
2255 else:
2254 raise error.UnknownCommand(name)
2256 raise error.UnknownCommand(name)
2255
2257
2256 # description
2258 # description
2257 if not doc:
2259 if not doc:
2258 doc = _("(no help text available)")
2260 doc = _("(no help text available)")
2259 if hasattr(doc, '__call__'):
2261 if hasattr(doc, '__call__'):
2260 doc = doc()
2262 doc = doc()
2261
2263
2262 ui.write("%s\n\n" % header)
2264 ui.write("%s\n\n" % header)
2263 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2265 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2264
2266
2265 def helpext(name):
2267 def helpext(name):
2266 try:
2268 try:
2267 mod = extensions.find(name)
2269 mod = extensions.find(name)
2268 doc = gettext(mod.__doc__) or _('no help text available')
2270 doc = gettext(mod.__doc__) or _('no help text available')
2269 except KeyError:
2271 except KeyError:
2270 mod = None
2272 mod = None
2271 doc = extensions.disabledext(name)
2273 doc = extensions.disabledext(name)
2272 if not doc:
2274 if not doc:
2273 raise error.UnknownCommand(name)
2275 raise error.UnknownCommand(name)
2274
2276
2275 if '\n' not in doc:
2277 if '\n' not in doc:
2276 head, tail = doc, ""
2278 head, tail = doc, ""
2277 else:
2279 else:
2278 head, tail = doc.split('\n', 1)
2280 head, tail = doc.split('\n', 1)
2279 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2281 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2280 if tail:
2282 if tail:
2281 ui.write(minirst.format(tail, textwidth))
2283 ui.write(minirst.format(tail, textwidth))
2282 ui.status('\n\n')
2284 ui.status('\n\n')
2283
2285
2284 if mod:
2286 if mod:
2285 try:
2287 try:
2286 ct = mod.cmdtable
2288 ct = mod.cmdtable
2287 except AttributeError:
2289 except AttributeError:
2288 ct = {}
2290 ct = {}
2289 modcmds = set([c.split('|', 1)[0] for c in ct])
2291 modcmds = set([c.split('|', 1)[0] for c in ct])
2290 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2292 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2291 else:
2293 else:
2292 ui.write(_('use "hg help extensions" for information on enabling '
2294 ui.write(_('use "hg help extensions" for information on enabling '
2293 'extensions\n'))
2295 'extensions\n'))
2294
2296
2295 def helpextcmd(name):
2297 def helpextcmd(name):
2296 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2298 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2297 doc = gettext(mod.__doc__).splitlines()[0]
2299 doc = gettext(mod.__doc__).splitlines()[0]
2298
2300
2299 msg = help.listexts(_("'%s' is provided by the following "
2301 msg = help.listexts(_("'%s' is provided by the following "
2300 "extension:") % cmd, {ext: doc}, len(ext),
2302 "extension:") % cmd, {ext: doc}, len(ext),
2301 indent=4)
2303 indent=4)
2302 ui.write(minirst.format(msg, textwidth))
2304 ui.write(minirst.format(msg, textwidth))
2303 ui.write('\n\n')
2305 ui.write('\n\n')
2304 ui.write(_('use "hg help extensions" for information on enabling '
2306 ui.write(_('use "hg help extensions" for information on enabling '
2305 'extensions\n'))
2307 'extensions\n'))
2306
2308
2307 help.addtopichook('revsets', revset.makedoc)
2309 help.addtopichook('revsets', revset.makedoc)
2308 help.addtopichook('templates', templatekw.makedoc)
2310 help.addtopichook('templates', templatekw.makedoc)
2309 help.addtopichook('templates', templatefilters.makedoc)
2311 help.addtopichook('templates', templatefilters.makedoc)
2310
2312
2311 if name and name != 'shortlist':
2313 if name and name != 'shortlist':
2312 i = None
2314 i = None
2313 if unknowncmd:
2315 if unknowncmd:
2314 queries = (helpextcmd,)
2316 queries = (helpextcmd,)
2315 else:
2317 else:
2316 queries = (helptopic, helpcmd, helpext, helpextcmd)
2318 queries = (helptopic, helpcmd, helpext, helpextcmd)
2317 for f in queries:
2319 for f in queries:
2318 try:
2320 try:
2319 f(name)
2321 f(name)
2320 i = None
2322 i = None
2321 break
2323 break
2322 except error.UnknownCommand, inst:
2324 except error.UnknownCommand, inst:
2323 i = inst
2325 i = inst
2324 if i:
2326 if i:
2325 raise i
2327 raise i
2326
2328
2327 else:
2329 else:
2328 # program name
2330 # program name
2329 if ui.verbose or with_version:
2331 if ui.verbose or with_version:
2330 version_(ui)
2332 version_(ui)
2331 else:
2333 else:
2332 ui.status(_("Mercurial Distributed SCM\n"))
2334 ui.status(_("Mercurial Distributed SCM\n"))
2333 ui.status('\n')
2335 ui.status('\n')
2334
2336
2335 # list of commands
2337 # list of commands
2336 if name == "shortlist":
2338 if name == "shortlist":
2337 header = _('basic commands:\n\n')
2339 header = _('basic commands:\n\n')
2338 else:
2340 else:
2339 header = _('list of commands:\n\n')
2341 header = _('list of commands:\n\n')
2340
2342
2341 helplist(header)
2343 helplist(header)
2342 if name != 'shortlist':
2344 if name != 'shortlist':
2343 exts, maxlength = extensions.enabled()
2345 exts, maxlength = extensions.enabled()
2344 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2346 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2345 if text:
2347 if text:
2346 ui.write("\n%s\n" % minirst.format(text, textwidth))
2348 ui.write("\n%s\n" % minirst.format(text, textwidth))
2347
2349
2348 # list all option lists
2350 # list all option lists
2349 opt_output = []
2351 opt_output = []
2350 multioccur = False
2352 multioccur = False
2351 for title, options in option_lists:
2353 for title, options in option_lists:
2352 opt_output.append(("\n%s" % title, None))
2354 opt_output.append(("\n%s" % title, None))
2353 for option in options:
2355 for option in options:
2354 if len(option) == 5:
2356 if len(option) == 5:
2355 shortopt, longopt, default, desc, optlabel = option
2357 shortopt, longopt, default, desc, optlabel = option
2356 else:
2358 else:
2357 shortopt, longopt, default, desc = option
2359 shortopt, longopt, default, desc = option
2358 optlabel = _("VALUE") # default label
2360 optlabel = _("VALUE") # default label
2359
2361
2360 if _("DEPRECATED") in desc and not ui.verbose:
2362 if _("DEPRECATED") in desc and not ui.verbose:
2361 continue
2363 continue
2362 if isinstance(default, list):
2364 if isinstance(default, list):
2363 numqualifier = " %s [+]" % optlabel
2365 numqualifier = " %s [+]" % optlabel
2364 multioccur = True
2366 multioccur = True
2365 elif (default is not None) and not isinstance(default, bool):
2367 elif (default is not None) and not isinstance(default, bool):
2366 numqualifier = " %s" % optlabel
2368 numqualifier = " %s" % optlabel
2367 else:
2369 else:
2368 numqualifier = ""
2370 numqualifier = ""
2369 opt_output.append(("%2s%s" %
2371 opt_output.append(("%2s%s" %
2370 (shortopt and "-%s" % shortopt,
2372 (shortopt and "-%s" % shortopt,
2371 longopt and " --%s%s" %
2373 longopt and " --%s%s" %
2372 (longopt, numqualifier)),
2374 (longopt, numqualifier)),
2373 "%s%s" % (desc,
2375 "%s%s" % (desc,
2374 default
2376 default
2375 and _(" (default: %s)") % default
2377 and _(" (default: %s)") % default
2376 or "")))
2378 or "")))
2377 if multioccur:
2379 if multioccur:
2378 msg = _("\n[+] marked option can be specified multiple times")
2380 msg = _("\n[+] marked option can be specified multiple times")
2379 if ui.verbose and name != 'shortlist':
2381 if ui.verbose and name != 'shortlist':
2380 opt_output.append((msg, None))
2382 opt_output.append((msg, None))
2381 else:
2383 else:
2382 opt_output.insert(-1, (msg, None))
2384 opt_output.insert(-1, (msg, None))
2383
2385
2384 if not name:
2386 if not name:
2385 ui.write(_("\nadditional help topics:\n\n"))
2387 ui.write(_("\nadditional help topics:\n\n"))
2386 topics = []
2388 topics = []
2387 for names, header, doc in help.helptable:
2389 for names, header, doc in help.helptable:
2388 topics.append((sorted(names, key=len, reverse=True)[0], header))
2390 topics.append((sorted(names, key=len, reverse=True)[0], header))
2389 topics_len = max([len(s[0]) for s in topics])
2391 topics_len = max([len(s[0]) for s in topics])
2390 for t, desc in topics:
2392 for t, desc in topics:
2391 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2393 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2392
2394
2393 if opt_output:
2395 if opt_output:
2394 colwidth = encoding.colwidth
2396 colwidth = encoding.colwidth
2395 # normalize: (opt or message, desc or None, width of opt)
2397 # normalize: (opt or message, desc or None, width of opt)
2396 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2398 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2397 for opt, desc in opt_output]
2399 for opt, desc in opt_output]
2398 hanging = max([e[2] for e in entries])
2400 hanging = max([e[2] for e in entries])
2399 for opt, desc, width in entries:
2401 for opt, desc, width in entries:
2400 if desc:
2402 if desc:
2401 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2403 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2402 hangindent = ' ' * (hanging + 3)
2404 hangindent = ' ' * (hanging + 3)
2403 ui.write('%s\n' % (util.wrap(desc, textwidth,
2405 ui.write('%s\n' % (util.wrap(desc, textwidth,
2404 initindent=initindent,
2406 initindent=initindent,
2405 hangindent=hangindent)))
2407 hangindent=hangindent)))
2406 else:
2408 else:
2407 ui.write("%s\n" % opt)
2409 ui.write("%s\n" % opt)
2408
2410
2409 def identify(ui, repo, source=None, rev=None,
2411 def identify(ui, repo, source=None, rev=None,
2410 num=None, id=None, branch=None, tags=None, bookmarks=None):
2412 num=None, id=None, branch=None, tags=None, bookmarks=None):
2411 """identify the working copy or specified revision
2413 """identify the working copy or specified revision
2412
2414
2413 Print a summary identifying the repository state at REV using one or
2415 Print a summary identifying the repository state at REV using one or
2414 two parent hash identifiers, followed by a "+" if the working
2416 two parent hash identifiers, followed by a "+" if the working
2415 directory has uncommitted changes, the branch name (if not default),
2417 directory has uncommitted changes, the branch name (if not default),
2416 a list of tags, and a list of bookmarks.
2418 a list of tags, and a list of bookmarks.
2417
2419
2418 When REV is not given, print a summary of the current state of the
2420 When REV is not given, print a summary of the current state of the
2419 repository.
2421 repository.
2420
2422
2421 Specifying a path to a repository root or Mercurial bundle will
2423 Specifying a path to a repository root or Mercurial bundle will
2422 cause lookup to operate on that repository/bundle.
2424 cause lookup to operate on that repository/bundle.
2423
2425
2424 Returns 0 if successful.
2426 Returns 0 if successful.
2425 """
2427 """
2426
2428
2427 if not repo and not source:
2429 if not repo and not source:
2428 raise util.Abort(_("there is no Mercurial repository here "
2430 raise util.Abort(_("there is no Mercurial repository here "
2429 "(.hg not found)"))
2431 "(.hg not found)"))
2430
2432
2431 hexfunc = ui.debugflag and hex or short
2433 hexfunc = ui.debugflag and hex or short
2432 default = not (num or id or branch or tags or bookmarks)
2434 default = not (num or id or branch or tags or bookmarks)
2433 output = []
2435 output = []
2434 revs = []
2436 revs = []
2435
2437
2436 if source:
2438 if source:
2437 source, branches = hg.parseurl(ui.expandpath(source))
2439 source, branches = hg.parseurl(ui.expandpath(source))
2438 repo = hg.repository(ui, source)
2440 repo = hg.repository(ui, source)
2439 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2441 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2440
2442
2441 if not repo.local():
2443 if not repo.local():
2442 if num or branch or tags:
2444 if num or branch or tags:
2443 raise util.Abort(
2445 raise util.Abort(
2444 _("can't query remote revision number, branch, or tags"))
2446 _("can't query remote revision number, branch, or tags"))
2445 if not rev and revs:
2447 if not rev and revs:
2446 rev = revs[0]
2448 rev = revs[0]
2447 if not rev:
2449 if not rev:
2448 rev = "tip"
2450 rev = "tip"
2449
2451
2450 remoterev = repo.lookup(rev)
2452 remoterev = repo.lookup(rev)
2451 if default or id:
2453 if default or id:
2452 output = [hexfunc(remoterev)]
2454 output = [hexfunc(remoterev)]
2453
2455
2454 def getbms():
2456 def getbms():
2455 bms = []
2457 bms = []
2456
2458
2457 if 'bookmarks' in repo.listkeys('namespaces'):
2459 if 'bookmarks' in repo.listkeys('namespaces'):
2458 hexremoterev = hex(remoterev)
2460 hexremoterev = hex(remoterev)
2459 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2461 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2460 if bmr == hexremoterev]
2462 if bmr == hexremoterev]
2461
2463
2462 return bms
2464 return bms
2463
2465
2464 if bookmarks:
2466 if bookmarks:
2465 output.extend(getbms())
2467 output.extend(getbms())
2466 elif default and not ui.quiet:
2468 elif default and not ui.quiet:
2467 # multiple bookmarks for a single parent separated by '/'
2469 # multiple bookmarks for a single parent separated by '/'
2468 bm = '/'.join(getbms())
2470 bm = '/'.join(getbms())
2469 if bm:
2471 if bm:
2470 output.append(bm)
2472 output.append(bm)
2471 else:
2473 else:
2472 if not rev:
2474 if not rev:
2473 ctx = repo[None]
2475 ctx = repo[None]
2474 parents = ctx.parents()
2476 parents = ctx.parents()
2475 changed = ""
2477 changed = ""
2476 if default or id or num:
2478 if default or id or num:
2477 changed = util.any(repo.status()) and "+" or ""
2479 changed = util.any(repo.status()) and "+" or ""
2478 if default or id:
2480 if default or id:
2479 output = ["%s%s" %
2481 output = ["%s%s" %
2480 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2482 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2481 if num:
2483 if num:
2482 output.append("%s%s" %
2484 output.append("%s%s" %
2483 ('+'.join([str(p.rev()) for p in parents]), changed))
2485 ('+'.join([str(p.rev()) for p in parents]), changed))
2484 else:
2486 else:
2485 ctx = cmdutil.revsingle(repo, rev)
2487 ctx = cmdutil.revsingle(repo, rev)
2486 if default or id:
2488 if default or id:
2487 output = [hexfunc(ctx.node())]
2489 output = [hexfunc(ctx.node())]
2488 if num:
2490 if num:
2489 output.append(str(ctx.rev()))
2491 output.append(str(ctx.rev()))
2490
2492
2491 if default and not ui.quiet:
2493 if default and not ui.quiet:
2492 b = ctx.branch()
2494 b = ctx.branch()
2493 if b != 'default':
2495 if b != 'default':
2494 output.append("(%s)" % b)
2496 output.append("(%s)" % b)
2495
2497
2496 # multiple tags for a single parent separated by '/'
2498 # multiple tags for a single parent separated by '/'
2497 t = '/'.join(ctx.tags())
2499 t = '/'.join(ctx.tags())
2498 if t:
2500 if t:
2499 output.append(t)
2501 output.append(t)
2500
2502
2501 # multiple bookmarks for a single parent separated by '/'
2503 # multiple bookmarks for a single parent separated by '/'
2502 bm = '/'.join(ctx.bookmarks())
2504 bm = '/'.join(ctx.bookmarks())
2503 if bm:
2505 if bm:
2504 output.append(bm)
2506 output.append(bm)
2505 else:
2507 else:
2506 if branch:
2508 if branch:
2507 output.append(ctx.branch())
2509 output.append(ctx.branch())
2508
2510
2509 if tags:
2511 if tags:
2510 output.extend(ctx.tags())
2512 output.extend(ctx.tags())
2511
2513
2512 if bookmarks:
2514 if bookmarks:
2513 output.extend(ctx.bookmarks())
2515 output.extend(ctx.bookmarks())
2514
2516
2515 ui.write("%s\n" % ' '.join(output))
2517 ui.write("%s\n" % ' '.join(output))
2516
2518
2517 def import_(ui, repo, patch1, *patches, **opts):
2519 def import_(ui, repo, patch1, *patches, **opts):
2518 """import an ordered set of patches
2520 """import an ordered set of patches
2519
2521
2520 Import a list of patches and commit them individually (unless
2522 Import a list of patches and commit them individually (unless
2521 --no-commit is specified).
2523 --no-commit is specified).
2522
2524
2523 If there are outstanding changes in the working directory, import
2525 If there are outstanding changes in the working directory, import
2524 will abort unless given the -f/--force flag.
2526 will abort unless given the -f/--force flag.
2525
2527
2526 You can import a patch straight from a mail message. Even patches
2528 You can import a patch straight from a mail message. Even patches
2527 as attachments work (to use the body part, it must have type
2529 as attachments work (to use the body part, it must have type
2528 text/plain or text/x-patch). From and Subject headers of email
2530 text/plain or text/x-patch). From and Subject headers of email
2529 message are used as default committer and commit message. All
2531 message are used as default committer and commit message. All
2530 text/plain body parts before first diff are added to commit
2532 text/plain body parts before first diff are added to commit
2531 message.
2533 message.
2532
2534
2533 If the imported patch was generated by :hg:`export`, user and
2535 If the imported patch was generated by :hg:`export`, user and
2534 description from patch override values from message headers and
2536 description from patch override values from message headers and
2535 body. Values given on command line with -m/--message and -u/--user
2537 body. Values given on command line with -m/--message and -u/--user
2536 override these.
2538 override these.
2537
2539
2538 If --exact is specified, import will set the working directory to
2540 If --exact is specified, import will set the working directory to
2539 the parent of each patch before applying it, and will abort if the
2541 the parent of each patch before applying it, and will abort if the
2540 resulting changeset has a different ID than the one recorded in
2542 resulting changeset has a different ID than the one recorded in
2541 the patch. This may happen due to character set problems or other
2543 the patch. This may happen due to character set problems or other
2542 deficiencies in the text patch format.
2544 deficiencies in the text patch format.
2543
2545
2544 With -s/--similarity, hg will attempt to discover renames and
2546 With -s/--similarity, hg will attempt to discover renames and
2545 copies in the patch in the same way as 'addremove'.
2547 copies in the patch in the same way as 'addremove'.
2546
2548
2547 To read a patch from standard input, use "-" as the patch name. If
2549 To read a patch from standard input, use "-" as the patch name. If
2548 a URL is specified, the patch will be downloaded from it.
2550 a URL is specified, the patch will be downloaded from it.
2549 See :hg:`help dates` for a list of formats valid for -d/--date.
2551 See :hg:`help dates` for a list of formats valid for -d/--date.
2550
2552
2551 Returns 0 on success.
2553 Returns 0 on success.
2552 """
2554 """
2553 patches = (patch1,) + patches
2555 patches = (patch1,) + patches
2554
2556
2555 date = opts.get('date')
2557 date = opts.get('date')
2556 if date:
2558 if date:
2557 opts['date'] = util.parsedate(date)
2559 opts['date'] = util.parsedate(date)
2558
2560
2559 try:
2561 try:
2560 sim = float(opts.get('similarity') or 0)
2562 sim = float(opts.get('similarity') or 0)
2561 except ValueError:
2563 except ValueError:
2562 raise util.Abort(_('similarity must be a number'))
2564 raise util.Abort(_('similarity must be a number'))
2563 if sim < 0 or sim > 100:
2565 if sim < 0 or sim > 100:
2564 raise util.Abort(_('similarity must be between 0 and 100'))
2566 raise util.Abort(_('similarity must be between 0 and 100'))
2565
2567
2566 if opts.get('exact') or not opts.get('force'):
2568 if opts.get('exact') or not opts.get('force'):
2567 cmdutil.bail_if_changed(repo)
2569 cmdutil.bail_if_changed(repo)
2568
2570
2569 d = opts["base"]
2571 d = opts["base"]
2570 strip = opts["strip"]
2572 strip = opts["strip"]
2571 wlock = lock = None
2573 wlock = lock = None
2572 msgs = []
2574 msgs = []
2573
2575
2574 def tryone(ui, hunk):
2576 def tryone(ui, hunk):
2575 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2577 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2576 patch.extract(ui, hunk)
2578 patch.extract(ui, hunk)
2577
2579
2578 if not tmpname:
2580 if not tmpname:
2579 return None
2581 return None
2580 commitid = _('to working directory')
2582 commitid = _('to working directory')
2581
2583
2582 try:
2584 try:
2583 cmdline_message = cmdutil.logmessage(opts)
2585 cmdline_message = cmdutil.logmessage(opts)
2584 if cmdline_message:
2586 if cmdline_message:
2585 # pickup the cmdline msg
2587 # pickup the cmdline msg
2586 message = cmdline_message
2588 message = cmdline_message
2587 elif message:
2589 elif message:
2588 # pickup the patch msg
2590 # pickup the patch msg
2589 message = message.strip()
2591 message = message.strip()
2590 else:
2592 else:
2591 # launch the editor
2593 # launch the editor
2592 message = None
2594 message = None
2593 ui.debug('message:\n%s\n' % message)
2595 ui.debug('message:\n%s\n' % message)
2594
2596
2595 wp = repo.parents()
2597 wp = repo.parents()
2596 if opts.get('exact'):
2598 if opts.get('exact'):
2597 if not nodeid or not p1:
2599 if not nodeid or not p1:
2598 raise util.Abort(_('not a Mercurial patch'))
2600 raise util.Abort(_('not a Mercurial patch'))
2599 p1 = repo.lookup(p1)
2601 p1 = repo.lookup(p1)
2600 p2 = repo.lookup(p2 or hex(nullid))
2602 p2 = repo.lookup(p2 or hex(nullid))
2601
2603
2602 if p1 != wp[0].node():
2604 if p1 != wp[0].node():
2603 hg.clean(repo, p1)
2605 hg.clean(repo, p1)
2604 repo.dirstate.setparents(p1, p2)
2606 repo.dirstate.setparents(p1, p2)
2605 elif p2:
2607 elif p2:
2606 try:
2608 try:
2607 p1 = repo.lookup(p1)
2609 p1 = repo.lookup(p1)
2608 p2 = repo.lookup(p2)
2610 p2 = repo.lookup(p2)
2609 if p1 == wp[0].node():
2611 if p1 == wp[0].node():
2610 repo.dirstate.setparents(p1, p2)
2612 repo.dirstate.setparents(p1, p2)
2611 except error.RepoError:
2613 except error.RepoError:
2612 pass
2614 pass
2613 if opts.get('exact') or opts.get('import_branch'):
2615 if opts.get('exact') or opts.get('import_branch'):
2614 repo.dirstate.setbranch(branch or 'default')
2616 repo.dirstate.setbranch(branch or 'default')
2615
2617
2616 files = {}
2618 files = {}
2617 try:
2619 try:
2618 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2620 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2619 files=files, eolmode=None)
2621 files=files, eolmode=None)
2620 finally:
2622 finally:
2621 files = cmdutil.updatedir(ui, repo, files,
2623 files = cmdutil.updatedir(ui, repo, files,
2622 similarity=sim / 100.0)
2624 similarity=sim / 100.0)
2623 if opts.get('no_commit'):
2625 if opts.get('no_commit'):
2624 if message:
2626 if message:
2625 msgs.append(message)
2627 msgs.append(message)
2626 else:
2628 else:
2627 if opts.get('exact'):
2629 if opts.get('exact'):
2628 m = None
2630 m = None
2629 else:
2631 else:
2630 m = cmdutil.matchfiles(repo, files or [])
2632 m = cmdutil.matchfiles(repo, files or [])
2631 n = repo.commit(message, opts.get('user') or user,
2633 n = repo.commit(message, opts.get('user') or user,
2632 opts.get('date') or date, match=m,
2634 opts.get('date') or date, match=m,
2633 editor=cmdutil.commiteditor)
2635 editor=cmdutil.commiteditor)
2634 if opts.get('exact'):
2636 if opts.get('exact'):
2635 if hex(n) != nodeid:
2637 if hex(n) != nodeid:
2636 repo.rollback()
2638 repo.rollback()
2637 raise util.Abort(_('patch is damaged'
2639 raise util.Abort(_('patch is damaged'
2638 ' or loses information'))
2640 ' or loses information'))
2639 # Force a dirstate write so that the next transaction
2641 # Force a dirstate write so that the next transaction
2640 # backups an up-do-date file.
2642 # backups an up-do-date file.
2641 repo.dirstate.write()
2643 repo.dirstate.write()
2642 if n:
2644 if n:
2643 commitid = short(n)
2645 commitid = short(n)
2644
2646
2645 return commitid
2647 return commitid
2646 finally:
2648 finally:
2647 os.unlink(tmpname)
2649 os.unlink(tmpname)
2648
2650
2649 try:
2651 try:
2650 wlock = repo.wlock()
2652 wlock = repo.wlock()
2651 lock = repo.lock()
2653 lock = repo.lock()
2652 lastcommit = None
2654 lastcommit = None
2653 for p in patches:
2655 for p in patches:
2654 pf = os.path.join(d, p)
2656 pf = os.path.join(d, p)
2655
2657
2656 if pf == '-':
2658 if pf == '-':
2657 ui.status(_("applying patch from stdin\n"))
2659 ui.status(_("applying patch from stdin\n"))
2658 pf = sys.stdin
2660 pf = sys.stdin
2659 else:
2661 else:
2660 ui.status(_("applying %s\n") % p)
2662 ui.status(_("applying %s\n") % p)
2661 pf = url.open(ui, pf)
2663 pf = url.open(ui, pf)
2662
2664
2663 haspatch = False
2665 haspatch = False
2664 for hunk in patch.split(pf):
2666 for hunk in patch.split(pf):
2665 commitid = tryone(ui, hunk)
2667 commitid = tryone(ui, hunk)
2666 if commitid:
2668 if commitid:
2667 haspatch = True
2669 haspatch = True
2668 if lastcommit:
2670 if lastcommit:
2669 ui.status(_('applied %s\n') % lastcommit)
2671 ui.status(_('applied %s\n') % lastcommit)
2670 lastcommit = commitid
2672 lastcommit = commitid
2671
2673
2672 if not haspatch:
2674 if not haspatch:
2673 raise util.Abort(_('no diffs found'))
2675 raise util.Abort(_('no diffs found'))
2674
2676
2675 if msgs:
2677 if msgs:
2676 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2678 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2677 finally:
2679 finally:
2678 release(lock, wlock)
2680 release(lock, wlock)
2679
2681
2680 def incoming(ui, repo, source="default", **opts):
2682 def incoming(ui, repo, source="default", **opts):
2681 """show new changesets found in source
2683 """show new changesets found in source
2682
2684
2683 Show new changesets found in the specified path/URL or the default
2685 Show new changesets found in the specified path/URL or the default
2684 pull location. These are the changesets that would have been pulled
2686 pull location. These are the changesets that would have been pulled
2685 if a pull at the time you issued this command.
2687 if a pull at the time you issued this command.
2686
2688
2687 For remote repository, using --bundle avoids downloading the
2689 For remote repository, using --bundle avoids downloading the
2688 changesets twice if the incoming is followed by a pull.
2690 changesets twice if the incoming is followed by a pull.
2689
2691
2690 See pull for valid source format details.
2692 See pull for valid source format details.
2691
2693
2692 Returns 0 if there are incoming changes, 1 otherwise.
2694 Returns 0 if there are incoming changes, 1 otherwise.
2693 """
2695 """
2694 if opts.get('bundle') and opts.get('subrepos'):
2696 if opts.get('bundle') and opts.get('subrepos'):
2695 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2697 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2696
2698
2697 if opts.get('bookmarks'):
2699 if opts.get('bookmarks'):
2698 source, branches = hg.parseurl(ui.expandpath(source),
2700 source, branches = hg.parseurl(ui.expandpath(source),
2699 opts.get('branch'))
2701 opts.get('branch'))
2700 other = hg.repository(hg.remoteui(repo, opts), source)
2702 other = hg.repository(hg.remoteui(repo, opts), source)
2701 if 'bookmarks' not in other.listkeys('namespaces'):
2703 if 'bookmarks' not in other.listkeys('namespaces'):
2702 ui.warn(_("remote doesn't support bookmarks\n"))
2704 ui.warn(_("remote doesn't support bookmarks\n"))
2703 return 0
2705 return 0
2704 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2706 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2705 return bookmarks.diff(ui, repo, other)
2707 return bookmarks.diff(ui, repo, other)
2706
2708
2707 ret = hg.incoming(ui, repo, source, opts)
2709 ret = hg.incoming(ui, repo, source, opts)
2708 return ret
2710 return ret
2709
2711
2710 def init(ui, dest=".", **opts):
2712 def init(ui, dest=".", **opts):
2711 """create a new repository in the given directory
2713 """create a new repository in the given directory
2712
2714
2713 Initialize a new repository in the given directory. If the given
2715 Initialize a new repository in the given directory. If the given
2714 directory does not exist, it will be created.
2716 directory does not exist, it will be created.
2715
2717
2716 If no directory is given, the current directory is used.
2718 If no directory is given, the current directory is used.
2717
2719
2718 It is possible to specify an ``ssh://`` URL as the destination.
2720 It is possible to specify an ``ssh://`` URL as the destination.
2719 See :hg:`help urls` for more information.
2721 See :hg:`help urls` for more information.
2720
2722
2721 Returns 0 on success.
2723 Returns 0 on success.
2722 """
2724 """
2723 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2725 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2724
2726
2725 def locate(ui, repo, *pats, **opts):
2727 def locate(ui, repo, *pats, **opts):
2726 """locate files matching specific patterns
2728 """locate files matching specific patterns
2727
2729
2728 Print files under Mercurial control in the working directory whose
2730 Print files under Mercurial control in the working directory whose
2729 names match the given patterns.
2731 names match the given patterns.
2730
2732
2731 By default, this command searches all directories in the working
2733 By default, this command searches all directories in the working
2732 directory. To search just the current directory and its
2734 directory. To search just the current directory and its
2733 subdirectories, use "--include .".
2735 subdirectories, use "--include .".
2734
2736
2735 If no patterns are given to match, this command prints the names
2737 If no patterns are given to match, this command prints the names
2736 of all files under Mercurial control in the working directory.
2738 of all files under Mercurial control in the working directory.
2737
2739
2738 If you want to feed the output of this command into the "xargs"
2740 If you want to feed the output of this command into the "xargs"
2739 command, use the -0 option to both this command and "xargs". This
2741 command, use the -0 option to both this command and "xargs". This
2740 will avoid the problem of "xargs" treating single filenames that
2742 will avoid the problem of "xargs" treating single filenames that
2741 contain whitespace as multiple filenames.
2743 contain whitespace as multiple filenames.
2742
2744
2743 Returns 0 if a match is found, 1 otherwise.
2745 Returns 0 if a match is found, 1 otherwise.
2744 """
2746 """
2745 end = opts.get('print0') and '\0' or '\n'
2747 end = opts.get('print0') and '\0' or '\n'
2746 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2748 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2747
2749
2748 ret = 1
2750 ret = 1
2749 m = cmdutil.match(repo, pats, opts, default='relglob')
2751 m = cmdutil.match(repo, pats, opts, default='relglob')
2750 m.bad = lambda x, y: False
2752 m.bad = lambda x, y: False
2751 for abs in repo[rev].walk(m):
2753 for abs in repo[rev].walk(m):
2752 if not rev and abs not in repo.dirstate:
2754 if not rev and abs not in repo.dirstate:
2753 continue
2755 continue
2754 if opts.get('fullpath'):
2756 if opts.get('fullpath'):
2755 ui.write(repo.wjoin(abs), end)
2757 ui.write(repo.wjoin(abs), end)
2756 else:
2758 else:
2757 ui.write(((pats and m.rel(abs)) or abs), end)
2759 ui.write(((pats and m.rel(abs)) or abs), end)
2758 ret = 0
2760 ret = 0
2759
2761
2760 return ret
2762 return ret
2761
2763
2762 def log(ui, repo, *pats, **opts):
2764 def log(ui, repo, *pats, **opts):
2763 """show revision history of entire repository or files
2765 """show revision history of entire repository or files
2764
2766
2765 Print the revision history of the specified files or the entire
2767 Print the revision history of the specified files or the entire
2766 project.
2768 project.
2767
2769
2768 File history is shown without following rename or copy history of
2770 File history is shown without following rename or copy history of
2769 files. Use -f/--follow with a filename to follow history across
2771 files. Use -f/--follow with a filename to follow history across
2770 renames and copies. --follow without a filename will only show
2772 renames and copies. --follow without a filename will only show
2771 ancestors or descendants of the starting revision. --follow-first
2773 ancestors or descendants of the starting revision. --follow-first
2772 only follows the first parent of merge revisions.
2774 only follows the first parent of merge revisions.
2773
2775
2774 If no revision range is specified, the default is ``tip:0`` unless
2776 If no revision range is specified, the default is ``tip:0`` unless
2775 --follow is set, in which case the working directory parent is
2777 --follow is set, in which case the working directory parent is
2776 used as the starting revision. You can specify a revision set for
2778 used as the starting revision. You can specify a revision set for
2777 log, see :hg:`help revsets` for more information.
2779 log, see :hg:`help revsets` for more information.
2778
2780
2779 See :hg:`help dates` for a list of formats valid for -d/--date.
2781 See :hg:`help dates` for a list of formats valid for -d/--date.
2780
2782
2781 By default this command prints revision number and changeset id,
2783 By default this command prints revision number and changeset id,
2782 tags, non-trivial parents, user, date and time, and a summary for
2784 tags, non-trivial parents, user, date and time, and a summary for
2783 each commit. When the -v/--verbose switch is used, the list of
2785 each commit. When the -v/--verbose switch is used, the list of
2784 changed files and full commit message are shown.
2786 changed files and full commit message are shown.
2785
2787
2786 .. note::
2788 .. note::
2787 log -p/--patch may generate unexpected diff output for merge
2789 log -p/--patch may generate unexpected diff output for merge
2788 changesets, as it will only compare the merge changeset against
2790 changesets, as it will only compare the merge changeset against
2789 its first parent. Also, only files different from BOTH parents
2791 its first parent. Also, only files different from BOTH parents
2790 will appear in files:.
2792 will appear in files:.
2791
2793
2792 Returns 0 on success.
2794 Returns 0 on success.
2793 """
2795 """
2794
2796
2795 matchfn = cmdutil.match(repo, pats, opts)
2797 matchfn = cmdutil.match(repo, pats, opts)
2796 limit = cmdutil.loglimit(opts)
2798 limit = cmdutil.loglimit(opts)
2797 count = 0
2799 count = 0
2798
2800
2799 endrev = None
2801 endrev = None
2800 if opts.get('copies') and opts.get('rev'):
2802 if opts.get('copies') and opts.get('rev'):
2801 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2803 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2802
2804
2803 df = False
2805 df = False
2804 if opts["date"]:
2806 if opts["date"]:
2805 df = util.matchdate(opts["date"])
2807 df = util.matchdate(opts["date"])
2806
2808
2807 branches = opts.get('branch', []) + opts.get('only_branch', [])
2809 branches = opts.get('branch', []) + opts.get('only_branch', [])
2808 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2810 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2809
2811
2810 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2812 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2811 def prep(ctx, fns):
2813 def prep(ctx, fns):
2812 rev = ctx.rev()
2814 rev = ctx.rev()
2813 parents = [p for p in repo.changelog.parentrevs(rev)
2815 parents = [p for p in repo.changelog.parentrevs(rev)
2814 if p != nullrev]
2816 if p != nullrev]
2815 if opts.get('no_merges') and len(parents) == 2:
2817 if opts.get('no_merges') and len(parents) == 2:
2816 return
2818 return
2817 if opts.get('only_merges') and len(parents) != 2:
2819 if opts.get('only_merges') and len(parents) != 2:
2818 return
2820 return
2819 if opts.get('branch') and ctx.branch() not in opts['branch']:
2821 if opts.get('branch') and ctx.branch() not in opts['branch']:
2820 return
2822 return
2821 if df and not df(ctx.date()[0]):
2823 if df and not df(ctx.date()[0]):
2822 return
2824 return
2823 if opts['user'] and not [k for k in opts['user']
2825 if opts['user'] and not [k for k in opts['user']
2824 if k.lower() in ctx.user().lower()]:
2826 if k.lower() in ctx.user().lower()]:
2825 return
2827 return
2826 if opts.get('keyword'):
2828 if opts.get('keyword'):
2827 for k in [kw.lower() for kw in opts['keyword']]:
2829 for k in [kw.lower() for kw in opts['keyword']]:
2828 if (k in ctx.user().lower() or
2830 if (k in ctx.user().lower() or
2829 k in ctx.description().lower() or
2831 k in ctx.description().lower() or
2830 k in " ".join(ctx.files()).lower()):
2832 k in " ".join(ctx.files()).lower()):
2831 break
2833 break
2832 else:
2834 else:
2833 return
2835 return
2834
2836
2835 copies = None
2837 copies = None
2836 if opts.get('copies') and rev:
2838 if opts.get('copies') and rev:
2837 copies = []
2839 copies = []
2838 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2840 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2839 for fn in ctx.files():
2841 for fn in ctx.files():
2840 rename = getrenamed(fn, rev)
2842 rename = getrenamed(fn, rev)
2841 if rename:
2843 if rename:
2842 copies.append((fn, rename[0]))
2844 copies.append((fn, rename[0]))
2843
2845
2844 revmatchfn = None
2846 revmatchfn = None
2845 if opts.get('patch') or opts.get('stat'):
2847 if opts.get('patch') or opts.get('stat'):
2846 if opts.get('follow') or opts.get('follow_first'):
2848 if opts.get('follow') or opts.get('follow_first'):
2847 # note: this might be wrong when following through merges
2849 # note: this might be wrong when following through merges
2848 revmatchfn = cmdutil.match(repo, fns, default='path')
2850 revmatchfn = cmdutil.match(repo, fns, default='path')
2849 else:
2851 else:
2850 revmatchfn = matchfn
2852 revmatchfn = matchfn
2851
2853
2852 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2854 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2853
2855
2854 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2856 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2855 if count == limit:
2857 if count == limit:
2856 break
2858 break
2857 if displayer.flush(ctx.rev()):
2859 if displayer.flush(ctx.rev()):
2858 count += 1
2860 count += 1
2859 displayer.close()
2861 displayer.close()
2860
2862
2861 def manifest(ui, repo, node=None, rev=None):
2863 def manifest(ui, repo, node=None, rev=None):
2862 """output the current or given revision of the project manifest
2864 """output the current or given revision of the project manifest
2863
2865
2864 Print a list of version controlled files for the given revision.
2866 Print a list of version controlled files for the given revision.
2865 If no revision is given, the first parent of the working directory
2867 If no revision is given, the first parent of the working directory
2866 is used, or the null revision if no revision is checked out.
2868 is used, or the null revision if no revision is checked out.
2867
2869
2868 With -v, print file permissions, symlink and executable bits.
2870 With -v, print file permissions, symlink and executable bits.
2869 With --debug, print file revision hashes.
2871 With --debug, print file revision hashes.
2870
2872
2871 Returns 0 on success.
2873 Returns 0 on success.
2872 """
2874 """
2873
2875
2874 if rev and node:
2876 if rev and node:
2875 raise util.Abort(_("please specify just one revision"))
2877 raise util.Abort(_("please specify just one revision"))
2876
2878
2877 if not node:
2879 if not node:
2878 node = rev
2880 node = rev
2879
2881
2880 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2882 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2881 ctx = cmdutil.revsingle(repo, node)
2883 ctx = cmdutil.revsingle(repo, node)
2882 for f in ctx:
2884 for f in ctx:
2883 if ui.debugflag:
2885 if ui.debugflag:
2884 ui.write("%40s " % hex(ctx.manifest()[f]))
2886 ui.write("%40s " % hex(ctx.manifest()[f]))
2885 if ui.verbose:
2887 if ui.verbose:
2886 ui.write(decor[ctx.flags(f)])
2888 ui.write(decor[ctx.flags(f)])
2887 ui.write("%s\n" % f)
2889 ui.write("%s\n" % f)
2888
2890
2889 def merge(ui, repo, node=None, **opts):
2891 def merge(ui, repo, node=None, **opts):
2890 """merge working directory with another revision
2892 """merge working directory with another revision
2891
2893
2892 The current working directory is updated with all changes made in
2894 The current working directory is updated with all changes made in
2893 the requested revision since the last common predecessor revision.
2895 the requested revision since the last common predecessor revision.
2894
2896
2895 Files that changed between either parent are marked as changed for
2897 Files that changed between either parent are marked as changed for
2896 the next commit and a commit must be performed before any further
2898 the next commit and a commit must be performed before any further
2897 updates to the repository are allowed. The next commit will have
2899 updates to the repository are allowed. The next commit will have
2898 two parents.
2900 two parents.
2899
2901
2900 ``--tool`` can be used to specify the merge tool used for file
2902 ``--tool`` can be used to specify the merge tool used for file
2901 merges. It overrides the HGMERGE environment variable and your
2903 merges. It overrides the HGMERGE environment variable and your
2902 configuration files. See :hg:`help merge-tools` for options.
2904 configuration files. See :hg:`help merge-tools` for options.
2903
2905
2904 If no revision is specified, the working directory's parent is a
2906 If no revision is specified, the working directory's parent is a
2905 head revision, and the current branch contains exactly one other
2907 head revision, and the current branch contains exactly one other
2906 head, the other head is merged with by default. Otherwise, an
2908 head, the other head is merged with by default. Otherwise, an
2907 explicit revision with which to merge with must be provided.
2909 explicit revision with which to merge with must be provided.
2908
2910
2909 :hg:`resolve` must be used to resolve unresolved files.
2911 :hg:`resolve` must be used to resolve unresolved files.
2910
2912
2911 To undo an uncommitted merge, use :hg:`update --clean .` which
2913 To undo an uncommitted merge, use :hg:`update --clean .` which
2912 will check out a clean copy of the original merge parent, losing
2914 will check out a clean copy of the original merge parent, losing
2913 all changes.
2915 all changes.
2914
2916
2915 Returns 0 on success, 1 if there are unresolved files.
2917 Returns 0 on success, 1 if there are unresolved files.
2916 """
2918 """
2917
2919
2918 if opts.get('rev') and node:
2920 if opts.get('rev') and node:
2919 raise util.Abort(_("please specify just one revision"))
2921 raise util.Abort(_("please specify just one revision"))
2920 if not node:
2922 if not node:
2921 node = opts.get('rev')
2923 node = opts.get('rev')
2922
2924
2923 if not node:
2925 if not node:
2924 branch = repo[None].branch()
2926 branch = repo[None].branch()
2925 bheads = repo.branchheads(branch)
2927 bheads = repo.branchheads(branch)
2926 if len(bheads) > 2:
2928 if len(bheads) > 2:
2927 raise util.Abort(_("branch '%s' has %d heads - "
2929 raise util.Abort(_("branch '%s' has %d heads - "
2928 "please merge with an explicit rev")
2930 "please merge with an explicit rev")
2929 % (branch, len(bheads)),
2931 % (branch, len(bheads)),
2930 hint=_("run 'hg heads .' to see heads"))
2932 hint=_("run 'hg heads .' to see heads"))
2931
2933
2932 parent = repo.dirstate.p1()
2934 parent = repo.dirstate.p1()
2933 if len(bheads) == 1:
2935 if len(bheads) == 1:
2934 if len(repo.heads()) > 1:
2936 if len(repo.heads()) > 1:
2935 raise util.Abort(_("branch '%s' has one head - "
2937 raise util.Abort(_("branch '%s' has one head - "
2936 "please merge with an explicit rev")
2938 "please merge with an explicit rev")
2937 % branch,
2939 % branch,
2938 hint=_("run 'hg heads' to see all heads"))
2940 hint=_("run 'hg heads' to see all heads"))
2939 msg = _('there is nothing to merge')
2941 msg = _('there is nothing to merge')
2940 if parent != repo.lookup(repo[None].branch()):
2942 if parent != repo.lookup(repo[None].branch()):
2941 msg = _('%s - use "hg update" instead') % msg
2943 msg = _('%s - use "hg update" instead') % msg
2942 raise util.Abort(msg)
2944 raise util.Abort(msg)
2943
2945
2944 if parent not in bheads:
2946 if parent not in bheads:
2945 raise util.Abort(_('working directory not at a head revision'),
2947 raise util.Abort(_('working directory not at a head revision'),
2946 hint=_("use 'hg update' or merge with an "
2948 hint=_("use 'hg update' or merge with an "
2947 "explicit revision"))
2949 "explicit revision"))
2948 node = parent == bheads[0] and bheads[-1] or bheads[0]
2950 node = parent == bheads[0] and bheads[-1] or bheads[0]
2949 else:
2951 else:
2950 node = cmdutil.revsingle(repo, node).node()
2952 node = cmdutil.revsingle(repo, node).node()
2951
2953
2952 if opts.get('preview'):
2954 if opts.get('preview'):
2953 # find nodes that are ancestors of p2 but not of p1
2955 # find nodes that are ancestors of p2 but not of p1
2954 p1 = repo.lookup('.')
2956 p1 = repo.lookup('.')
2955 p2 = repo.lookup(node)
2957 p2 = repo.lookup(node)
2956 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2958 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2957
2959
2958 displayer = cmdutil.show_changeset(ui, repo, opts)
2960 displayer = cmdutil.show_changeset(ui, repo, opts)
2959 for node in nodes:
2961 for node in nodes:
2960 displayer.show(repo[node])
2962 displayer.show(repo[node])
2961 displayer.close()
2963 displayer.close()
2962 return 0
2964 return 0
2963
2965
2964 try:
2966 try:
2965 # ui.forcemerge is an internal variable, do not document
2967 # ui.forcemerge is an internal variable, do not document
2966 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2968 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2967 return hg.merge(repo, node, force=opts.get('force'))
2969 return hg.merge(repo, node, force=opts.get('force'))
2968 finally:
2970 finally:
2969 ui.setconfig('ui', 'forcemerge', '')
2971 ui.setconfig('ui', 'forcemerge', '')
2970
2972
2971 def outgoing(ui, repo, dest=None, **opts):
2973 def outgoing(ui, repo, dest=None, **opts):
2972 """show changesets not found in the destination
2974 """show changesets not found in the destination
2973
2975
2974 Show changesets not found in the specified destination repository
2976 Show changesets not found in the specified destination repository
2975 or the default push location. These are the changesets that would
2977 or the default push location. These are the changesets that would
2976 be pushed if a push was requested.
2978 be pushed if a push was requested.
2977
2979
2978 See pull for details of valid destination formats.
2980 See pull for details of valid destination formats.
2979
2981
2980 Returns 0 if there are outgoing changes, 1 otherwise.
2982 Returns 0 if there are outgoing changes, 1 otherwise.
2981 """
2983 """
2982
2984
2983 if opts.get('bookmarks'):
2985 if opts.get('bookmarks'):
2984 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2986 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2985 dest, branches = hg.parseurl(dest, opts.get('branch'))
2987 dest, branches = hg.parseurl(dest, opts.get('branch'))
2986 other = hg.repository(hg.remoteui(repo, opts), dest)
2988 other = hg.repository(hg.remoteui(repo, opts), dest)
2987 if 'bookmarks' not in other.listkeys('namespaces'):
2989 if 'bookmarks' not in other.listkeys('namespaces'):
2988 ui.warn(_("remote doesn't support bookmarks\n"))
2990 ui.warn(_("remote doesn't support bookmarks\n"))
2989 return 0
2991 return 0
2990 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2992 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2991 return bookmarks.diff(ui, other, repo)
2993 return bookmarks.diff(ui, other, repo)
2992
2994
2993 ret = hg.outgoing(ui, repo, dest, opts)
2995 ret = hg.outgoing(ui, repo, dest, opts)
2994 return ret
2996 return ret
2995
2997
2996 def parents(ui, repo, file_=None, **opts):
2998 def parents(ui, repo, file_=None, **opts):
2997 """show the parents of the working directory or revision
2999 """show the parents of the working directory or revision
2998
3000
2999 Print the working directory's parent revisions. If a revision is
3001 Print the working directory's parent revisions. If a revision is
3000 given via -r/--rev, the parent of that revision will be printed.
3002 given via -r/--rev, the parent of that revision will be printed.
3001 If a file argument is given, the revision in which the file was
3003 If a file argument is given, the revision in which the file was
3002 last changed (before the working directory revision or the
3004 last changed (before the working directory revision or the
3003 argument to --rev if given) is printed.
3005 argument to --rev if given) is printed.
3004
3006
3005 Returns 0 on success.
3007 Returns 0 on success.
3006 """
3008 """
3007
3009
3008 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3010 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3009
3011
3010 if file_:
3012 if file_:
3011 m = cmdutil.match(repo, (file_,), opts)
3013 m = cmdutil.match(repo, (file_,), opts)
3012 if m.anypats() or len(m.files()) != 1:
3014 if m.anypats() or len(m.files()) != 1:
3013 raise util.Abort(_('can only specify an explicit filename'))
3015 raise util.Abort(_('can only specify an explicit filename'))
3014 file_ = m.files()[0]
3016 file_ = m.files()[0]
3015 filenodes = []
3017 filenodes = []
3016 for cp in ctx.parents():
3018 for cp in ctx.parents():
3017 if not cp:
3019 if not cp:
3018 continue
3020 continue
3019 try:
3021 try:
3020 filenodes.append(cp.filenode(file_))
3022 filenodes.append(cp.filenode(file_))
3021 except error.LookupError:
3023 except error.LookupError:
3022 pass
3024 pass
3023 if not filenodes:
3025 if not filenodes:
3024 raise util.Abort(_("'%s' not found in manifest!") % file_)
3026 raise util.Abort(_("'%s' not found in manifest!") % file_)
3025 fl = repo.file(file_)
3027 fl = repo.file(file_)
3026 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3028 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3027 else:
3029 else:
3028 p = [cp.node() for cp in ctx.parents()]
3030 p = [cp.node() for cp in ctx.parents()]
3029
3031
3030 displayer = cmdutil.show_changeset(ui, repo, opts)
3032 displayer = cmdutil.show_changeset(ui, repo, opts)
3031 for n in p:
3033 for n in p:
3032 if n != nullid:
3034 if n != nullid:
3033 displayer.show(repo[n])
3035 displayer.show(repo[n])
3034 displayer.close()
3036 displayer.close()
3035
3037
3036 def paths(ui, repo, search=None):
3038 def paths(ui, repo, search=None):
3037 """show aliases for remote repositories
3039 """show aliases for remote repositories
3038
3040
3039 Show definition of symbolic path name NAME. If no name is given,
3041 Show definition of symbolic path name NAME. If no name is given,
3040 show definition of all available names.
3042 show definition of all available names.
3041
3043
3042 Path names are defined in the [paths] section of your
3044 Path names are defined in the [paths] section of your
3043 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3045 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3044 repository, ``.hg/hgrc`` is used, too.
3046 repository, ``.hg/hgrc`` is used, too.
3045
3047
3046 The path names ``default`` and ``default-push`` have a special
3048 The path names ``default`` and ``default-push`` have a special
3047 meaning. When performing a push or pull operation, they are used
3049 meaning. When performing a push or pull operation, they are used
3048 as fallbacks if no location is specified on the command-line.
3050 as fallbacks if no location is specified on the command-line.
3049 When ``default-push`` is set, it will be used for push and
3051 When ``default-push`` is set, it will be used for push and
3050 ``default`` will be used for pull; otherwise ``default`` is used
3052 ``default`` will be used for pull; otherwise ``default`` is used
3051 as the fallback for both. When cloning a repository, the clone
3053 as the fallback for both. When cloning a repository, the clone
3052 source is written as ``default`` in ``.hg/hgrc``. Note that
3054 source is written as ``default`` in ``.hg/hgrc``. Note that
3053 ``default`` and ``default-push`` apply to all inbound (e.g.
3055 ``default`` and ``default-push`` apply to all inbound (e.g.
3054 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3056 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3055 :hg:`bundle`) operations.
3057 :hg:`bundle`) operations.
3056
3058
3057 See :hg:`help urls` for more information.
3059 See :hg:`help urls` for more information.
3058
3060
3059 Returns 0 on success.
3061 Returns 0 on success.
3060 """
3062 """
3061 if search:
3063 if search:
3062 for name, path in ui.configitems("paths"):
3064 for name, path in ui.configitems("paths"):
3063 if name == search:
3065 if name == search:
3064 ui.write("%s\n" % util.hidepassword(path))
3066 ui.write("%s\n" % util.hidepassword(path))
3065 return
3067 return
3066 ui.warn(_("not found!\n"))
3068 ui.warn(_("not found!\n"))
3067 return 1
3069 return 1
3068 else:
3070 else:
3069 for name, path in ui.configitems("paths"):
3071 for name, path in ui.configitems("paths"):
3070 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3072 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3071
3073
3072 def postincoming(ui, repo, modheads, optupdate, checkout):
3074 def postincoming(ui, repo, modheads, optupdate, checkout):
3073 if modheads == 0:
3075 if modheads == 0:
3074 return
3076 return
3075 if optupdate:
3077 if optupdate:
3076 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3078 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3077 return hg.update(repo, checkout)
3079 return hg.update(repo, checkout)
3078 else:
3080 else:
3079 ui.status(_("not updating, since new heads added\n"))
3081 ui.status(_("not updating, since new heads added\n"))
3080 if modheads > 1:
3082 if modheads > 1:
3081 currentbranchheads = len(repo.branchheads())
3083 currentbranchheads = len(repo.branchheads())
3082 if currentbranchheads == modheads:
3084 if currentbranchheads == modheads:
3083 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3085 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3084 elif currentbranchheads > 1:
3086 elif currentbranchheads > 1:
3085 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3087 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3086 else:
3088 else:
3087 ui.status(_("(run 'hg heads' to see heads)\n"))
3089 ui.status(_("(run 'hg heads' to see heads)\n"))
3088 else:
3090 else:
3089 ui.status(_("(run 'hg update' to get a working copy)\n"))
3091 ui.status(_("(run 'hg update' to get a working copy)\n"))
3090
3092
3091 def pull(ui, repo, source="default", **opts):
3093 def pull(ui, repo, source="default", **opts):
3092 """pull changes from the specified source
3094 """pull changes from the specified source
3093
3095
3094 Pull changes from a remote repository to a local one.
3096 Pull changes from a remote repository to a local one.
3095
3097
3096 This finds all changes from the repository at the specified path
3098 This finds all changes from the repository at the specified path
3097 or URL and adds them to a local repository (the current one unless
3099 or URL and adds them to a local repository (the current one unless
3098 -R is specified). By default, this does not update the copy of the
3100 -R is specified). By default, this does not update the copy of the
3099 project in the working directory.
3101 project in the working directory.
3100
3102
3101 Use :hg:`incoming` if you want to see what would have been added
3103 Use :hg:`incoming` if you want to see what would have been added
3102 by a pull at the time you issued this command. If you then decide
3104 by a pull at the time you issued this command. If you then decide
3103 to add those changes to the repository, you should use :hg:`pull
3105 to add those changes to the repository, you should use :hg:`pull
3104 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3106 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3105
3107
3106 If SOURCE is omitted, the 'default' path will be used.
3108 If SOURCE is omitted, the 'default' path will be used.
3107 See :hg:`help urls` for more information.
3109 See :hg:`help urls` for more information.
3108
3110
3109 Returns 0 on success, 1 if an update had unresolved files.
3111 Returns 0 on success, 1 if an update had unresolved files.
3110 """
3112 """
3111 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3113 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3112 other = hg.repository(hg.remoteui(repo, opts), source)
3114 other = hg.repository(hg.remoteui(repo, opts), source)
3113 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3115 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3114 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3116 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3115
3117
3116 if opts.get('bookmark'):
3118 if opts.get('bookmark'):
3117 if not revs:
3119 if not revs:
3118 revs = []
3120 revs = []
3119 rb = other.listkeys('bookmarks')
3121 rb = other.listkeys('bookmarks')
3120 for b in opts['bookmark']:
3122 for b in opts['bookmark']:
3121 if b not in rb:
3123 if b not in rb:
3122 raise util.Abort(_('remote bookmark %s not found!') % b)
3124 raise util.Abort(_('remote bookmark %s not found!') % b)
3123 revs.append(rb[b])
3125 revs.append(rb[b])
3124
3126
3125 if revs:
3127 if revs:
3126 try:
3128 try:
3127 revs = [other.lookup(rev) for rev in revs]
3129 revs = [other.lookup(rev) for rev in revs]
3128 except error.CapabilityError:
3130 except error.CapabilityError:
3129 err = _("other repository doesn't support revision lookup, "
3131 err = _("other repository doesn't support revision lookup, "
3130 "so a rev cannot be specified.")
3132 "so a rev cannot be specified.")
3131 raise util.Abort(err)
3133 raise util.Abort(err)
3132
3134
3133 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3135 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3134 bookmarks.updatefromremote(ui, repo, other)
3136 bookmarks.updatefromremote(ui, repo, other)
3135 if checkout:
3137 if checkout:
3136 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3138 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3137 repo._subtoppath = source
3139 repo._subtoppath = source
3138 try:
3140 try:
3139 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3141 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3140
3142
3141 finally:
3143 finally:
3142 del repo._subtoppath
3144 del repo._subtoppath
3143
3145
3144 # update specified bookmarks
3146 # update specified bookmarks
3145 if opts.get('bookmark'):
3147 if opts.get('bookmark'):
3146 for b in opts['bookmark']:
3148 for b in opts['bookmark']:
3147 # explicit pull overrides local bookmark if any
3149 # explicit pull overrides local bookmark if any
3148 ui.status(_("importing bookmark %s\n") % b)
3150 ui.status(_("importing bookmark %s\n") % b)
3149 repo._bookmarks[b] = repo[rb[b]].node()
3151 repo._bookmarks[b] = repo[rb[b]].node()
3150 bookmarks.write(repo)
3152 bookmarks.write(repo)
3151
3153
3152 return ret
3154 return ret
3153
3155
3154 def push(ui, repo, dest=None, **opts):
3156 def push(ui, repo, dest=None, **opts):
3155 """push changes to the specified destination
3157 """push changes to the specified destination
3156
3158
3157 Push changesets from the local repository to the specified
3159 Push changesets from the local repository to the specified
3158 destination.
3160 destination.
3159
3161
3160 This operation is symmetrical to pull: it is identical to a pull
3162 This operation is symmetrical to pull: it is identical to a pull
3161 in the destination repository from the current one.
3163 in the destination repository from the current one.
3162
3164
3163 By default, push will not allow creation of new heads at the
3165 By default, push will not allow creation of new heads at the
3164 destination, since multiple heads would make it unclear which head
3166 destination, since multiple heads would make it unclear which head
3165 to use. In this situation, it is recommended to pull and merge
3167 to use. In this situation, it is recommended to pull and merge
3166 before pushing.
3168 before pushing.
3167
3169
3168 Use --new-branch if you want to allow push to create a new named
3170 Use --new-branch if you want to allow push to create a new named
3169 branch that is not present at the destination. This allows you to
3171 branch that is not present at the destination. This allows you to
3170 only create a new branch without forcing other changes.
3172 only create a new branch without forcing other changes.
3171
3173
3172 Use -f/--force to override the default behavior and push all
3174 Use -f/--force to override the default behavior and push all
3173 changesets on all branches.
3175 changesets on all branches.
3174
3176
3175 If -r/--rev is used, the specified revision and all its ancestors
3177 If -r/--rev is used, the specified revision and all its ancestors
3176 will be pushed to the remote repository.
3178 will be pushed to the remote repository.
3177
3179
3178 Please see :hg:`help urls` for important details about ``ssh://``
3180 Please see :hg:`help urls` for important details about ``ssh://``
3179 URLs. If DESTINATION is omitted, a default path will be used.
3181 URLs. If DESTINATION is omitted, a default path will be used.
3180
3182
3181 Returns 0 if push was successful, 1 if nothing to push.
3183 Returns 0 if push was successful, 1 if nothing to push.
3182 """
3184 """
3183
3185
3184 if opts.get('bookmark'):
3186 if opts.get('bookmark'):
3185 for b in opts['bookmark']:
3187 for b in opts['bookmark']:
3186 # translate -B options to -r so changesets get pushed
3188 # translate -B options to -r so changesets get pushed
3187 if b in repo._bookmarks:
3189 if b in repo._bookmarks:
3188 opts.setdefault('rev', []).append(b)
3190 opts.setdefault('rev', []).append(b)
3189 else:
3191 else:
3190 # if we try to push a deleted bookmark, translate it to null
3192 # if we try to push a deleted bookmark, translate it to null
3191 # this lets simultaneous -r, -b options continue working
3193 # this lets simultaneous -r, -b options continue working
3192 opts.setdefault('rev', []).append("null")
3194 opts.setdefault('rev', []).append("null")
3193
3195
3194 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3196 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3195 dest, branches = hg.parseurl(dest, opts.get('branch'))
3197 dest, branches = hg.parseurl(dest, opts.get('branch'))
3196 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3198 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3197 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3199 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3198 other = hg.repository(hg.remoteui(repo, opts), dest)
3200 other = hg.repository(hg.remoteui(repo, opts), dest)
3199 if revs:
3201 if revs:
3200 revs = [repo.lookup(rev) for rev in revs]
3202 revs = [repo.lookup(rev) for rev in revs]
3201
3203
3202 repo._subtoppath = dest
3204 repo._subtoppath = dest
3203 try:
3205 try:
3204 # push subrepos depth-first for coherent ordering
3206 # push subrepos depth-first for coherent ordering
3205 c = repo['']
3207 c = repo['']
3206 subs = c.substate # only repos that are committed
3208 subs = c.substate # only repos that are committed
3207 for s in sorted(subs):
3209 for s in sorted(subs):
3208 if not c.sub(s).push(opts.get('force')):
3210 if not c.sub(s).push(opts.get('force')):
3209 return False
3211 return False
3210 finally:
3212 finally:
3211 del repo._subtoppath
3213 del repo._subtoppath
3212 result = repo.push(other, opts.get('force'), revs=revs,
3214 result = repo.push(other, opts.get('force'), revs=revs,
3213 newbranch=opts.get('new_branch'))
3215 newbranch=opts.get('new_branch'))
3214
3216
3215 result = (result == 0)
3217 result = (result == 0)
3216
3218
3217 if opts.get('bookmark'):
3219 if opts.get('bookmark'):
3218 rb = other.listkeys('bookmarks')
3220 rb = other.listkeys('bookmarks')
3219 for b in opts['bookmark']:
3221 for b in opts['bookmark']:
3220 # explicit push overrides remote bookmark if any
3222 # explicit push overrides remote bookmark if any
3221 if b in repo._bookmarks:
3223 if b in repo._bookmarks:
3222 ui.status(_("exporting bookmark %s\n") % b)
3224 ui.status(_("exporting bookmark %s\n") % b)
3223 new = repo[b].hex()
3225 new = repo[b].hex()
3224 elif b in rb:
3226 elif b in rb:
3225 ui.status(_("deleting remote bookmark %s\n") % b)
3227 ui.status(_("deleting remote bookmark %s\n") % b)
3226 new = '' # delete
3228 new = '' # delete
3227 else:
3229 else:
3228 ui.warn(_('bookmark %s does not exist on the local '
3230 ui.warn(_('bookmark %s does not exist on the local '
3229 'or remote repository!\n') % b)
3231 'or remote repository!\n') % b)
3230 return 2
3232 return 2
3231 old = rb.get(b, '')
3233 old = rb.get(b, '')
3232 r = other.pushkey('bookmarks', b, old, new)
3234 r = other.pushkey('bookmarks', b, old, new)
3233 if not r:
3235 if not r:
3234 ui.warn(_('updating bookmark %s failed!\n') % b)
3236 ui.warn(_('updating bookmark %s failed!\n') % b)
3235 if not result:
3237 if not result:
3236 result = 2
3238 result = 2
3237
3239
3238 return result
3240 return result
3239
3241
3240 def recover(ui, repo):
3242 def recover(ui, repo):
3241 """roll back an interrupted transaction
3243 """roll back an interrupted transaction
3242
3244
3243 Recover from an interrupted commit or pull.
3245 Recover from an interrupted commit or pull.
3244
3246
3245 This command tries to fix the repository status after an
3247 This command tries to fix the repository status after an
3246 interrupted operation. It should only be necessary when Mercurial
3248 interrupted operation. It should only be necessary when Mercurial
3247 suggests it.
3249 suggests it.
3248
3250
3249 Returns 0 if successful, 1 if nothing to recover or verify fails.
3251 Returns 0 if successful, 1 if nothing to recover or verify fails.
3250 """
3252 """
3251 if repo.recover():
3253 if repo.recover():
3252 return hg.verify(repo)
3254 return hg.verify(repo)
3253 return 1
3255 return 1
3254
3256
3255 def remove(ui, repo, *pats, **opts):
3257 def remove(ui, repo, *pats, **opts):
3256 """remove the specified files on the next commit
3258 """remove the specified files on the next commit
3257
3259
3258 Schedule the indicated files for removal from the repository.
3260 Schedule the indicated files for removal from the repository.
3259
3261
3260 This only removes files from the current branch, not from the
3262 This only removes files from the current branch, not from the
3261 entire project history. -A/--after can be used to remove only
3263 entire project history. -A/--after can be used to remove only
3262 files that have already been deleted, -f/--force can be used to
3264 files that have already been deleted, -f/--force can be used to
3263 force deletion, and -Af can be used to remove files from the next
3265 force deletion, and -Af can be used to remove files from the next
3264 revision without deleting them from the working directory.
3266 revision without deleting them from the working directory.
3265
3267
3266 The following table details the behavior of remove for different
3268 The following table details the behavior of remove for different
3267 file states (columns) and option combinations (rows). The file
3269 file states (columns) and option combinations (rows). The file
3268 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3270 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3269 reported by :hg:`status`). The actions are Warn, Remove (from
3271 reported by :hg:`status`). The actions are Warn, Remove (from
3270 branch) and Delete (from disk)::
3272 branch) and Delete (from disk)::
3271
3273
3272 A C M !
3274 A C M !
3273 none W RD W R
3275 none W RD W R
3274 -f R RD RD R
3276 -f R RD RD R
3275 -A W W W R
3277 -A W W W R
3276 -Af R R R R
3278 -Af R R R R
3277
3279
3278 This command schedules the files to be removed at the next commit.
3280 This command schedules the files to be removed at the next commit.
3279 To undo a remove before that, see :hg:`revert`.
3281 To undo a remove before that, see :hg:`revert`.
3280
3282
3281 Returns 0 on success, 1 if any warnings encountered.
3283 Returns 0 on success, 1 if any warnings encountered.
3282 """
3284 """
3283
3285
3284 ret = 0
3286 ret = 0
3285 after, force = opts.get('after'), opts.get('force')
3287 after, force = opts.get('after'), opts.get('force')
3286 if not pats and not after:
3288 if not pats and not after:
3287 raise util.Abort(_('no files specified'))
3289 raise util.Abort(_('no files specified'))
3288
3290
3289 m = cmdutil.match(repo, pats, opts)
3291 m = cmdutil.match(repo, pats, opts)
3290 s = repo.status(match=m, clean=True)
3292 s = repo.status(match=m, clean=True)
3291 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3293 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3292
3294
3293 for f in m.files():
3295 for f in m.files():
3294 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3296 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3295 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3297 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3296 ret = 1
3298 ret = 1
3297
3299
3298 if force:
3300 if force:
3299 remove, forget = modified + deleted + clean, added
3301 remove, forget = modified + deleted + clean, added
3300 elif after:
3302 elif after:
3301 remove, forget = deleted, []
3303 remove, forget = deleted, []
3302 for f in modified + added + clean:
3304 for f in modified + added + clean:
3303 ui.warn(_('not removing %s: file still exists (use -f'
3305 ui.warn(_('not removing %s: file still exists (use -f'
3304 ' to force removal)\n') % m.rel(f))
3306 ' to force removal)\n') % m.rel(f))
3305 ret = 1
3307 ret = 1
3306 else:
3308 else:
3307 remove, forget = deleted + clean, []
3309 remove, forget = deleted + clean, []
3308 for f in modified:
3310 for f in modified:
3309 ui.warn(_('not removing %s: file is modified (use -f'
3311 ui.warn(_('not removing %s: file is modified (use -f'
3310 ' to force removal)\n') % m.rel(f))
3312 ' to force removal)\n') % m.rel(f))
3311 ret = 1
3313 ret = 1
3312 for f in added:
3314 for f in added:
3313 ui.warn(_('not removing %s: file has been marked for add (use -f'
3315 ui.warn(_('not removing %s: file has been marked for add (use -f'
3314 ' to force removal)\n') % m.rel(f))
3316 ' to force removal)\n') % m.rel(f))
3315 ret = 1
3317 ret = 1
3316
3318
3317 for f in sorted(remove + forget):
3319 for f in sorted(remove + forget):
3318 if ui.verbose or not m.exact(f):
3320 if ui.verbose or not m.exact(f):
3319 ui.status(_('removing %s\n') % m.rel(f))
3321 ui.status(_('removing %s\n') % m.rel(f))
3320
3322
3321 repo[None].forget(forget)
3323 repo[None].forget(forget)
3322 repo[None].remove(remove, unlink=not after)
3324 repo[None].remove(remove, unlink=not after)
3323 return ret
3325 return ret
3324
3326
3325 def rename(ui, repo, *pats, **opts):
3327 def rename(ui, repo, *pats, **opts):
3326 """rename files; equivalent of copy + remove
3328 """rename files; equivalent of copy + remove
3327
3329
3328 Mark dest as copies of sources; mark sources for deletion. If dest
3330 Mark dest as copies of sources; mark sources for deletion. If dest
3329 is a directory, copies are put in that directory. If dest is a
3331 is a directory, copies are put in that directory. If dest is a
3330 file, there can only be one source.
3332 file, there can only be one source.
3331
3333
3332 By default, this command copies the contents of files as they
3334 By default, this command copies the contents of files as they
3333 exist in the working directory. If invoked with -A/--after, the
3335 exist in the working directory. If invoked with -A/--after, the
3334 operation is recorded, but no copying is performed.
3336 operation is recorded, but no copying is performed.
3335
3337
3336 This command takes effect at the next commit. To undo a rename
3338 This command takes effect at the next commit. To undo a rename
3337 before that, see :hg:`revert`.
3339 before that, see :hg:`revert`.
3338
3340
3339 Returns 0 on success, 1 if errors are encountered.
3341 Returns 0 on success, 1 if errors are encountered.
3340 """
3342 """
3341 wlock = repo.wlock(False)
3343 wlock = repo.wlock(False)
3342 try:
3344 try:
3343 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3345 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3344 finally:
3346 finally:
3345 wlock.release()
3347 wlock.release()
3346
3348
3347 def resolve(ui, repo, *pats, **opts):
3349 def resolve(ui, repo, *pats, **opts):
3348 """redo merges or set/view the merge status of files
3350 """redo merges or set/view the merge status of files
3349
3351
3350 Merges with unresolved conflicts are often the result of
3352 Merges with unresolved conflicts are often the result of
3351 non-interactive merging using the ``internal:merge`` configuration
3353 non-interactive merging using the ``internal:merge`` configuration
3352 setting, or a command-line merge tool like ``diff3``. The resolve
3354 setting, or a command-line merge tool like ``diff3``. The resolve
3353 command is used to manage the files involved in a merge, after
3355 command is used to manage the files involved in a merge, after
3354 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3356 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3355 working directory must have two parents).
3357 working directory must have two parents).
3356
3358
3357 The resolve command can be used in the following ways:
3359 The resolve command can be used in the following ways:
3358
3360
3359 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3361 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3360 files, discarding any previous merge attempts. Re-merging is not
3362 files, discarding any previous merge attempts. Re-merging is not
3361 performed for files already marked as resolved. Use ``--all/-a``
3363 performed for files already marked as resolved. Use ``--all/-a``
3362 to selects all unresolved files. ``--tool`` can be used to specify
3364 to selects all unresolved files. ``--tool`` can be used to specify
3363 the merge tool used for the given files. It overrides the HGMERGE
3365 the merge tool used for the given files. It overrides the HGMERGE
3364 environment variable and your configuration files.
3366 environment variable and your configuration files.
3365
3367
3366 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3368 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3367 (e.g. after having manually fixed-up the files). The default is
3369 (e.g. after having manually fixed-up the files). The default is
3368 to mark all unresolved files.
3370 to mark all unresolved files.
3369
3371
3370 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3372 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3371 default is to mark all resolved files.
3373 default is to mark all resolved files.
3372
3374
3373 - :hg:`resolve -l`: list files which had or still have conflicts.
3375 - :hg:`resolve -l`: list files which had or still have conflicts.
3374 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3376 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3375
3377
3376 Note that Mercurial will not let you commit files with unresolved
3378 Note that Mercurial will not let you commit files with unresolved
3377 merge conflicts. You must use :hg:`resolve -m ...` before you can
3379 merge conflicts. You must use :hg:`resolve -m ...` before you can
3378 commit after a conflicting merge.
3380 commit after a conflicting merge.
3379
3381
3380 Returns 0 on success, 1 if any files fail a resolve attempt.
3382 Returns 0 on success, 1 if any files fail a resolve attempt.
3381 """
3383 """
3382
3384
3383 all, mark, unmark, show, nostatus = \
3385 all, mark, unmark, show, nostatus = \
3384 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3386 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3385
3387
3386 if (show and (mark or unmark)) or (mark and unmark):
3388 if (show and (mark or unmark)) or (mark and unmark):
3387 raise util.Abort(_("too many options specified"))
3389 raise util.Abort(_("too many options specified"))
3388 if pats and all:
3390 if pats and all:
3389 raise util.Abort(_("can't specify --all and patterns"))
3391 raise util.Abort(_("can't specify --all and patterns"))
3390 if not (all or pats or show or mark or unmark):
3392 if not (all or pats or show or mark or unmark):
3391 raise util.Abort(_('no files or directories specified; '
3393 raise util.Abort(_('no files or directories specified; '
3392 'use --all to remerge all files'))
3394 'use --all to remerge all files'))
3393
3395
3394 ms = mergemod.mergestate(repo)
3396 ms = mergemod.mergestate(repo)
3395 m = cmdutil.match(repo, pats, opts)
3397 m = cmdutil.match(repo, pats, opts)
3396 ret = 0
3398 ret = 0
3397
3399
3398 for f in ms:
3400 for f in ms:
3399 if m(f):
3401 if m(f):
3400 if show:
3402 if show:
3401 if nostatus:
3403 if nostatus:
3402 ui.write("%s\n" % f)
3404 ui.write("%s\n" % f)
3403 else:
3405 else:
3404 ui.write("%s %s\n" % (ms[f].upper(), f),
3406 ui.write("%s %s\n" % (ms[f].upper(), f),
3405 label='resolve.' +
3407 label='resolve.' +
3406 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3408 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3407 elif mark:
3409 elif mark:
3408 ms.mark(f, "r")
3410 ms.mark(f, "r")
3409 elif unmark:
3411 elif unmark:
3410 ms.mark(f, "u")
3412 ms.mark(f, "u")
3411 else:
3413 else:
3412 wctx = repo[None]
3414 wctx = repo[None]
3413 mctx = wctx.parents()[-1]
3415 mctx = wctx.parents()[-1]
3414
3416
3415 # backup pre-resolve (merge uses .orig for its own purposes)
3417 # backup pre-resolve (merge uses .orig for its own purposes)
3416 a = repo.wjoin(f)
3418 a = repo.wjoin(f)
3417 util.copyfile(a, a + ".resolve")
3419 util.copyfile(a, a + ".resolve")
3418
3420
3419 try:
3421 try:
3420 # resolve file
3422 # resolve file
3421 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3423 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3422 if ms.resolve(f, wctx, mctx):
3424 if ms.resolve(f, wctx, mctx):
3423 ret = 1
3425 ret = 1
3424 finally:
3426 finally:
3425 ui.setconfig('ui', 'forcemerge', '')
3427 ui.setconfig('ui', 'forcemerge', '')
3426
3428
3427 # replace filemerge's .orig file with our resolve file
3429 # replace filemerge's .orig file with our resolve file
3428 util.rename(a + ".resolve", a + ".orig")
3430 util.rename(a + ".resolve", a + ".orig")
3429
3431
3430 ms.commit()
3432 ms.commit()
3431 return ret
3433 return ret
3432
3434
3433 def revert(ui, repo, *pats, **opts):
3435 def revert(ui, repo, *pats, **opts):
3434 """restore individual files or directories to an earlier state
3436 """restore individual files or directories to an earlier state
3435
3437
3436 .. note::
3438 .. note::
3437 This command is most likely not what you are looking for.
3439 This command is most likely not what you are looking for.
3438 Revert will partially overwrite content in the working
3440 Revert will partially overwrite content in the working
3439 directory without changing the working directory parents. Use
3441 directory without changing the working directory parents. Use
3440 :hg:`update -r rev` to check out earlier revisions, or
3442 :hg:`update -r rev` to check out earlier revisions, or
3441 :hg:`update --clean .` to undo a merge which has added another
3443 :hg:`update --clean .` to undo a merge which has added another
3442 parent.
3444 parent.
3443
3445
3444 With no revision specified, revert the named files or directories
3446 With no revision specified, revert the named files or directories
3445 to the contents they had in the parent of the working directory.
3447 to the contents they had in the parent of the working directory.
3446 This restores the contents of the affected files to an unmodified
3448 This restores the contents of the affected files to an unmodified
3447 state and unschedules adds, removes, copies, and renames. If the
3449 state and unschedules adds, removes, copies, and renames. If the
3448 working directory has two parents, you must explicitly specify a
3450 working directory has two parents, you must explicitly specify a
3449 revision.
3451 revision.
3450
3452
3451 Using the -r/--rev option, revert the given files or directories
3453 Using the -r/--rev option, revert the given files or directories
3452 to their contents as of a specific revision. This can be helpful
3454 to their contents as of a specific revision. This can be helpful
3453 to "roll back" some or all of an earlier change. See :hg:`help
3455 to "roll back" some or all of an earlier change. See :hg:`help
3454 dates` for a list of formats valid for -d/--date.
3456 dates` for a list of formats valid for -d/--date.
3455
3457
3456 Revert modifies the working directory. It does not commit any
3458 Revert modifies the working directory. It does not commit any
3457 changes, or change the parent of the working directory. If you
3459 changes, or change the parent of the working directory. If you
3458 revert to a revision other than the parent of the working
3460 revert to a revision other than the parent of the working
3459 directory, the reverted files will thus appear modified
3461 directory, the reverted files will thus appear modified
3460 afterwards.
3462 afterwards.
3461
3463
3462 If a file has been deleted, it is restored. Files scheduled for
3464 If a file has been deleted, it is restored. Files scheduled for
3463 addition are just unscheduled and left as they are. If the
3465 addition are just unscheduled and left as they are. If the
3464 executable mode of a file was changed, it is reset.
3466 executable mode of a file was changed, it is reset.
3465
3467
3466 If names are given, all files matching the names are reverted.
3468 If names are given, all files matching the names are reverted.
3467 If no arguments are given, no files are reverted.
3469 If no arguments are given, no files are reverted.
3468
3470
3469 Modified files are saved with a .orig suffix before reverting.
3471 Modified files are saved with a .orig suffix before reverting.
3470 To disable these backups, use --no-backup.
3472 To disable these backups, use --no-backup.
3471
3473
3472 Returns 0 on success.
3474 Returns 0 on success.
3473 """
3475 """
3474
3476
3475 if opts.get("date"):
3477 if opts.get("date"):
3476 if opts.get("rev"):
3478 if opts.get("rev"):
3477 raise util.Abort(_("you can't specify a revision and a date"))
3479 raise util.Abort(_("you can't specify a revision and a date"))
3478 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3480 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3479
3481
3480 parent, p2 = repo.dirstate.parents()
3482 parent, p2 = repo.dirstate.parents()
3481 if not opts.get('rev') and p2 != nullid:
3483 if not opts.get('rev') and p2 != nullid:
3482 raise util.Abort(_('uncommitted merge - '
3484 raise util.Abort(_('uncommitted merge - '
3483 'use "hg update", see "hg help revert"'))
3485 'use "hg update", see "hg help revert"'))
3484
3486
3485 if not pats and not opts.get('all'):
3487 if not pats and not opts.get('all'):
3486 raise util.Abort(_('no files or directories specified; '
3488 raise util.Abort(_('no files or directories specified; '
3487 'use --all to revert the whole repo'))
3489 'use --all to revert the whole repo'))
3488
3490
3489 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3491 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3490 node = ctx.node()
3492 node = ctx.node()
3491 mf = ctx.manifest()
3493 mf = ctx.manifest()
3492 if node == parent:
3494 if node == parent:
3493 pmf = mf
3495 pmf = mf
3494 else:
3496 else:
3495 pmf = None
3497 pmf = None
3496
3498
3497 # need all matching names in dirstate and manifest of target rev,
3499 # need all matching names in dirstate and manifest of target rev,
3498 # so have to walk both. do not print errors if files exist in one
3500 # so have to walk both. do not print errors if files exist in one
3499 # but not other.
3501 # but not other.
3500
3502
3501 names = {}
3503 names = {}
3502
3504
3503 wlock = repo.wlock()
3505 wlock = repo.wlock()
3504 try:
3506 try:
3505 # walk dirstate.
3507 # walk dirstate.
3506
3508
3507 m = cmdutil.match(repo, pats, opts)
3509 m = cmdutil.match(repo, pats, opts)
3508 m.bad = lambda x, y: False
3510 m.bad = lambda x, y: False
3509 for abs in repo.walk(m):
3511 for abs in repo.walk(m):
3510 names[abs] = m.rel(abs), m.exact(abs)
3512 names[abs] = m.rel(abs), m.exact(abs)
3511
3513
3512 # walk target manifest.
3514 # walk target manifest.
3513
3515
3514 def badfn(path, msg):
3516 def badfn(path, msg):
3515 if path in names:
3517 if path in names:
3516 return
3518 return
3517 path_ = path + '/'
3519 path_ = path + '/'
3518 for f in names:
3520 for f in names:
3519 if f.startswith(path_):
3521 if f.startswith(path_):
3520 return
3522 return
3521 ui.warn("%s: %s\n" % (m.rel(path), msg))
3523 ui.warn("%s: %s\n" % (m.rel(path), msg))
3522
3524
3523 m = cmdutil.match(repo, pats, opts)
3525 m = cmdutil.match(repo, pats, opts)
3524 m.bad = badfn
3526 m.bad = badfn
3525 for abs in repo[node].walk(m):
3527 for abs in repo[node].walk(m):
3526 if abs not in names:
3528 if abs not in names:
3527 names[abs] = m.rel(abs), m.exact(abs)
3529 names[abs] = m.rel(abs), m.exact(abs)
3528
3530
3529 m = cmdutil.matchfiles(repo, names)
3531 m = cmdutil.matchfiles(repo, names)
3530 changes = repo.status(match=m)[:4]
3532 changes = repo.status(match=m)[:4]
3531 modified, added, removed, deleted = map(set, changes)
3533 modified, added, removed, deleted = map(set, changes)
3532
3534
3533 # if f is a rename, also revert the source
3535 # if f is a rename, also revert the source
3534 cwd = repo.getcwd()
3536 cwd = repo.getcwd()
3535 for f in added:
3537 for f in added:
3536 src = repo.dirstate.copied(f)
3538 src = repo.dirstate.copied(f)
3537 if src and src not in names and repo.dirstate[src] == 'r':
3539 if src and src not in names and repo.dirstate[src] == 'r':
3538 removed.add(src)
3540 removed.add(src)
3539 names[src] = (repo.pathto(src, cwd), True)
3541 names[src] = (repo.pathto(src, cwd), True)
3540
3542
3541 def removeforget(abs):
3543 def removeforget(abs):
3542 if repo.dirstate[abs] == 'a':
3544 if repo.dirstate[abs] == 'a':
3543 return _('forgetting %s\n')
3545 return _('forgetting %s\n')
3544 return _('removing %s\n')
3546 return _('removing %s\n')
3545
3547
3546 revert = ([], _('reverting %s\n'))
3548 revert = ([], _('reverting %s\n'))
3547 add = ([], _('adding %s\n'))
3549 add = ([], _('adding %s\n'))
3548 remove = ([], removeforget)
3550 remove = ([], removeforget)
3549 undelete = ([], _('undeleting %s\n'))
3551 undelete = ([], _('undeleting %s\n'))
3550
3552
3551 disptable = (
3553 disptable = (
3552 # dispatch table:
3554 # dispatch table:
3553 # file state
3555 # file state
3554 # action if in target manifest
3556 # action if in target manifest
3555 # action if not in target manifest
3557 # action if not in target manifest
3556 # make backup if in target manifest
3558 # make backup if in target manifest
3557 # make backup if not in target manifest
3559 # make backup if not in target manifest
3558 (modified, revert, remove, True, True),
3560 (modified, revert, remove, True, True),
3559 (added, revert, remove, True, False),
3561 (added, revert, remove, True, False),
3560 (removed, undelete, None, False, False),
3562 (removed, undelete, None, False, False),
3561 (deleted, revert, remove, False, False),
3563 (deleted, revert, remove, False, False),
3562 )
3564 )
3563
3565
3564 for abs, (rel, exact) in sorted(names.items()):
3566 for abs, (rel, exact) in sorted(names.items()):
3565 mfentry = mf.get(abs)
3567 mfentry = mf.get(abs)
3566 target = repo.wjoin(abs)
3568 target = repo.wjoin(abs)
3567 def handle(xlist, dobackup):
3569 def handle(xlist, dobackup):
3568 xlist[0].append(abs)
3570 xlist[0].append(abs)
3569 if (dobackup and not opts.get('no_backup') and
3571 if (dobackup and not opts.get('no_backup') and
3570 os.path.lexists(target)):
3572 os.path.lexists(target)):
3571 bakname = "%s.orig" % rel
3573 bakname = "%s.orig" % rel
3572 ui.note(_('saving current version of %s as %s\n') %
3574 ui.note(_('saving current version of %s as %s\n') %
3573 (rel, bakname))
3575 (rel, bakname))
3574 if not opts.get('dry_run'):
3576 if not opts.get('dry_run'):
3575 util.rename(target, bakname)
3577 util.rename(target, bakname)
3576 if ui.verbose or not exact:
3578 if ui.verbose or not exact:
3577 msg = xlist[1]
3579 msg = xlist[1]
3578 if not isinstance(msg, basestring):
3580 if not isinstance(msg, basestring):
3579 msg = msg(abs)
3581 msg = msg(abs)
3580 ui.status(msg % rel)
3582 ui.status(msg % rel)
3581 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3583 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3582 if abs not in table:
3584 if abs not in table:
3583 continue
3585 continue
3584 # file has changed in dirstate
3586 # file has changed in dirstate
3585 if mfentry:
3587 if mfentry:
3586 handle(hitlist, backuphit)
3588 handle(hitlist, backuphit)
3587 elif misslist is not None:
3589 elif misslist is not None:
3588 handle(misslist, backupmiss)
3590 handle(misslist, backupmiss)
3589 break
3591 break
3590 else:
3592 else:
3591 if abs not in repo.dirstate:
3593 if abs not in repo.dirstate:
3592 if mfentry:
3594 if mfentry:
3593 handle(add, True)
3595 handle(add, True)
3594 elif exact:
3596 elif exact:
3595 ui.warn(_('file not managed: %s\n') % rel)
3597 ui.warn(_('file not managed: %s\n') % rel)
3596 continue
3598 continue
3597 # file has not changed in dirstate
3599 # file has not changed in dirstate
3598 if node == parent:
3600 if node == parent:
3599 if exact:
3601 if exact:
3600 ui.warn(_('no changes needed to %s\n') % rel)
3602 ui.warn(_('no changes needed to %s\n') % rel)
3601 continue
3603 continue
3602 if pmf is None:
3604 if pmf is None:
3603 # only need parent manifest in this unlikely case,
3605 # only need parent manifest in this unlikely case,
3604 # so do not read by default
3606 # so do not read by default
3605 pmf = repo[parent].manifest()
3607 pmf = repo[parent].manifest()
3606 if abs in pmf:
3608 if abs in pmf:
3607 if mfentry:
3609 if mfentry:
3608 # if version of file is same in parent and target
3610 # if version of file is same in parent and target
3609 # manifests, do nothing
3611 # manifests, do nothing
3610 if (pmf[abs] != mfentry or
3612 if (pmf[abs] != mfentry or
3611 pmf.flags(abs) != mf.flags(abs)):
3613 pmf.flags(abs) != mf.flags(abs)):
3612 handle(revert, False)
3614 handle(revert, False)
3613 else:
3615 else:
3614 handle(remove, False)
3616 handle(remove, False)
3615
3617
3616 if not opts.get('dry_run'):
3618 if not opts.get('dry_run'):
3617 def checkout(f):
3619 def checkout(f):
3618 fc = ctx[f]
3620 fc = ctx[f]
3619 repo.wwrite(f, fc.data(), fc.flags())
3621 repo.wwrite(f, fc.data(), fc.flags())
3620
3622
3621 audit_path = scmutil.path_auditor(repo.root)
3623 audit_path = scmutil.path_auditor(repo.root)
3622 for f in remove[0]:
3624 for f in remove[0]:
3623 if repo.dirstate[f] == 'a':
3625 if repo.dirstate[f] == 'a':
3624 repo.dirstate.forget(f)
3626 repo.dirstate.forget(f)
3625 continue
3627 continue
3626 audit_path(f)
3628 audit_path(f)
3627 try:
3629 try:
3628 util.unlinkpath(repo.wjoin(f))
3630 util.unlinkpath(repo.wjoin(f))
3629 except OSError:
3631 except OSError:
3630 pass
3632 pass
3631 repo.dirstate.remove(f)
3633 repo.dirstate.remove(f)
3632
3634
3633 normal = None
3635 normal = None
3634 if node == parent:
3636 if node == parent:
3635 # We're reverting to our parent. If possible, we'd like status
3637 # We're reverting to our parent. If possible, we'd like status
3636 # to report the file as clean. We have to use normallookup for
3638 # to report the file as clean. We have to use normallookup for
3637 # merges to avoid losing information about merged/dirty files.
3639 # merges to avoid losing information about merged/dirty files.
3638 if p2 != nullid:
3640 if p2 != nullid:
3639 normal = repo.dirstate.normallookup
3641 normal = repo.dirstate.normallookup
3640 else:
3642 else:
3641 normal = repo.dirstate.normal
3643 normal = repo.dirstate.normal
3642 for f in revert[0]:
3644 for f in revert[0]:
3643 checkout(f)
3645 checkout(f)
3644 if normal:
3646 if normal:
3645 normal(f)
3647 normal(f)
3646
3648
3647 for f in add[0]:
3649 for f in add[0]:
3648 checkout(f)
3650 checkout(f)
3649 repo.dirstate.add(f)
3651 repo.dirstate.add(f)
3650
3652
3651 normal = repo.dirstate.normallookup
3653 normal = repo.dirstate.normallookup
3652 if node == parent and p2 == nullid:
3654 if node == parent and p2 == nullid:
3653 normal = repo.dirstate.normal
3655 normal = repo.dirstate.normal
3654 for f in undelete[0]:
3656 for f in undelete[0]:
3655 checkout(f)
3657 checkout(f)
3656 normal(f)
3658 normal(f)
3657
3659
3658 finally:
3660 finally:
3659 wlock.release()
3661 wlock.release()
3660
3662
3661 def rollback(ui, repo, **opts):
3663 def rollback(ui, repo, **opts):
3662 """roll back the last transaction (dangerous)
3664 """roll back the last transaction (dangerous)
3663
3665
3664 This command should be used with care. There is only one level of
3666 This command should be used with care. There is only one level of
3665 rollback, and there is no way to undo a rollback. It will also
3667 rollback, and there is no way to undo a rollback. It will also
3666 restore the dirstate at the time of the last transaction, losing
3668 restore the dirstate at the time of the last transaction, losing
3667 any dirstate changes since that time. This command does not alter
3669 any dirstate changes since that time. This command does not alter
3668 the working directory.
3670 the working directory.
3669
3671
3670 Transactions are used to encapsulate the effects of all commands
3672 Transactions are used to encapsulate the effects of all commands
3671 that create new changesets or propagate existing changesets into a
3673 that create new changesets or propagate existing changesets into a
3672 repository. For example, the following commands are transactional,
3674 repository. For example, the following commands are transactional,
3673 and their effects can be rolled back:
3675 and their effects can be rolled back:
3674
3676
3675 - commit
3677 - commit
3676 - import
3678 - import
3677 - pull
3679 - pull
3678 - push (with this repository as the destination)
3680 - push (with this repository as the destination)
3679 - unbundle
3681 - unbundle
3680
3682
3681 This command is not intended for use on public repositories. Once
3683 This command is not intended for use on public repositories. Once
3682 changes are visible for pull by other users, rolling a transaction
3684 changes are visible for pull by other users, rolling a transaction
3683 back locally is ineffective (someone else may already have pulled
3685 back locally is ineffective (someone else may already have pulled
3684 the changes). Furthermore, a race is possible with readers of the
3686 the changes). Furthermore, a race is possible with readers of the
3685 repository; for example an in-progress pull from the repository
3687 repository; for example an in-progress pull from the repository
3686 may fail if a rollback is performed.
3688 may fail if a rollback is performed.
3687
3689
3688 Returns 0 on success, 1 if no rollback data is available.
3690 Returns 0 on success, 1 if no rollback data is available.
3689 """
3691 """
3690 return repo.rollback(opts.get('dry_run'))
3692 return repo.rollback(opts.get('dry_run'))
3691
3693
3692 def root(ui, repo):
3694 def root(ui, repo):
3693 """print the root (top) of the current working directory
3695 """print the root (top) of the current working directory
3694
3696
3695 Print the root directory of the current repository.
3697 Print the root directory of the current repository.
3696
3698
3697 Returns 0 on success.
3699 Returns 0 on success.
3698 """
3700 """
3699 ui.write(repo.root + "\n")
3701 ui.write(repo.root + "\n")
3700
3702
3701 def serve(ui, repo, **opts):
3703 def serve(ui, repo, **opts):
3702 """start stand-alone webserver
3704 """start stand-alone webserver
3703
3705
3704 Start a local HTTP repository browser and pull server. You can use
3706 Start a local HTTP repository browser and pull server. You can use
3705 this for ad-hoc sharing and browsing of repositories. It is
3707 this for ad-hoc sharing and browsing of repositories. It is
3706 recommended to use a real web server to serve a repository for
3708 recommended to use a real web server to serve a repository for
3707 longer periods of time.
3709 longer periods of time.
3708
3710
3709 Please note that the server does not implement access control.
3711 Please note that the server does not implement access control.
3710 This means that, by default, anybody can read from the server and
3712 This means that, by default, anybody can read from the server and
3711 nobody can write to it by default. Set the ``web.allow_push``
3713 nobody can write to it by default. Set the ``web.allow_push``
3712 option to ``*`` to allow everybody to push to the server. You
3714 option to ``*`` to allow everybody to push to the server. You
3713 should use a real web server if you need to authenticate users.
3715 should use a real web server if you need to authenticate users.
3714
3716
3715 By default, the server logs accesses to stdout and errors to
3717 By default, the server logs accesses to stdout and errors to
3716 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3718 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3717 files.
3719 files.
3718
3720
3719 To have the server choose a free port number to listen on, specify
3721 To have the server choose a free port number to listen on, specify
3720 a port number of 0; in this case, the server will print the port
3722 a port number of 0; in this case, the server will print the port
3721 number it uses.
3723 number it uses.
3722
3724
3723 Returns 0 on success.
3725 Returns 0 on success.
3724 """
3726 """
3725
3727
3726 if opts["stdio"]:
3728 if opts["stdio"]:
3727 if repo is None:
3729 if repo is None:
3728 raise error.RepoError(_("There is no Mercurial repository here"
3730 raise error.RepoError(_("There is no Mercurial repository here"
3729 " (.hg not found)"))
3731 " (.hg not found)"))
3730 s = sshserver.sshserver(ui, repo)
3732 s = sshserver.sshserver(ui, repo)
3731 s.serve_forever()
3733 s.serve_forever()
3732
3734
3733 # this way we can check if something was given in the command-line
3735 # this way we can check if something was given in the command-line
3734 if opts.get('port'):
3736 if opts.get('port'):
3735 opts['port'] = util.getport(opts.get('port'))
3737 opts['port'] = util.getport(opts.get('port'))
3736
3738
3737 baseui = repo and repo.baseui or ui
3739 baseui = repo and repo.baseui or ui
3738 optlist = ("name templates style address port prefix ipv6"
3740 optlist = ("name templates style address port prefix ipv6"
3739 " accesslog errorlog certificate encoding")
3741 " accesslog errorlog certificate encoding")
3740 for o in optlist.split():
3742 for o in optlist.split():
3741 val = opts.get(o, '')
3743 val = opts.get(o, '')
3742 if val in (None, ''): # should check against default options instead
3744 if val in (None, ''): # should check against default options instead
3743 continue
3745 continue
3744 baseui.setconfig("web", o, val)
3746 baseui.setconfig("web", o, val)
3745 if repo and repo.ui != baseui:
3747 if repo and repo.ui != baseui:
3746 repo.ui.setconfig("web", o, val)
3748 repo.ui.setconfig("web", o, val)
3747
3749
3748 o = opts.get('web_conf') or opts.get('webdir_conf')
3750 o = opts.get('web_conf') or opts.get('webdir_conf')
3749 if not o:
3751 if not o:
3750 if not repo:
3752 if not repo:
3751 raise error.RepoError(_("There is no Mercurial repository"
3753 raise error.RepoError(_("There is no Mercurial repository"
3752 " here (.hg not found)"))
3754 " here (.hg not found)"))
3753 o = repo.root
3755 o = repo.root
3754
3756
3755 app = hgweb.hgweb(o, baseui=ui)
3757 app = hgweb.hgweb(o, baseui=ui)
3756
3758
3757 class service(object):
3759 class service(object):
3758 def init(self):
3760 def init(self):
3759 util.set_signal_handler()
3761 util.set_signal_handler()
3760 self.httpd = hgweb.server.create_server(ui, app)
3762 self.httpd = hgweb.server.create_server(ui, app)
3761
3763
3762 if opts['port'] and not ui.verbose:
3764 if opts['port'] and not ui.verbose:
3763 return
3765 return
3764
3766
3765 if self.httpd.prefix:
3767 if self.httpd.prefix:
3766 prefix = self.httpd.prefix.strip('/') + '/'
3768 prefix = self.httpd.prefix.strip('/') + '/'
3767 else:
3769 else:
3768 prefix = ''
3770 prefix = ''
3769
3771
3770 port = ':%d' % self.httpd.port
3772 port = ':%d' % self.httpd.port
3771 if port == ':80':
3773 if port == ':80':
3772 port = ''
3774 port = ''
3773
3775
3774 bindaddr = self.httpd.addr
3776 bindaddr = self.httpd.addr
3775 if bindaddr == '0.0.0.0':
3777 if bindaddr == '0.0.0.0':
3776 bindaddr = '*'
3778 bindaddr = '*'
3777 elif ':' in bindaddr: # IPv6
3779 elif ':' in bindaddr: # IPv6
3778 bindaddr = '[%s]' % bindaddr
3780 bindaddr = '[%s]' % bindaddr
3779
3781
3780 fqaddr = self.httpd.fqaddr
3782 fqaddr = self.httpd.fqaddr
3781 if ':' in fqaddr:
3783 if ':' in fqaddr:
3782 fqaddr = '[%s]' % fqaddr
3784 fqaddr = '[%s]' % fqaddr
3783 if opts['port']:
3785 if opts['port']:
3784 write = ui.status
3786 write = ui.status
3785 else:
3787 else:
3786 write = ui.write
3788 write = ui.write
3787 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3789 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3788 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3790 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3789
3791
3790 def run(self):
3792 def run(self):
3791 self.httpd.serve_forever()
3793 self.httpd.serve_forever()
3792
3794
3793 service = service()
3795 service = service()
3794
3796
3795 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3797 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3796
3798
3797 def status(ui, repo, *pats, **opts):
3799 def status(ui, repo, *pats, **opts):
3798 """show changed files in the working directory
3800 """show changed files in the working directory
3799
3801
3800 Show status of files in the repository. If names are given, only
3802 Show status of files in the repository. If names are given, only
3801 files that match are shown. Files that are clean or ignored or
3803 files that match are shown. Files that are clean or ignored or
3802 the source of a copy/move operation, are not listed unless
3804 the source of a copy/move operation, are not listed unless
3803 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3805 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3804 Unless options described with "show only ..." are given, the
3806 Unless options described with "show only ..." are given, the
3805 options -mardu are used.
3807 options -mardu are used.
3806
3808
3807 Option -q/--quiet hides untracked (unknown and ignored) files
3809 Option -q/--quiet hides untracked (unknown and ignored) files
3808 unless explicitly requested with -u/--unknown or -i/--ignored.
3810 unless explicitly requested with -u/--unknown or -i/--ignored.
3809
3811
3810 .. note::
3812 .. note::
3811 status may appear to disagree with diff if permissions have
3813 status may appear to disagree with diff if permissions have
3812 changed or a merge has occurred. The standard diff format does
3814 changed or a merge has occurred. The standard diff format does
3813 not report permission changes and diff only reports changes
3815 not report permission changes and diff only reports changes
3814 relative to one merge parent.
3816 relative to one merge parent.
3815
3817
3816 If one revision is given, it is used as the base revision.
3818 If one revision is given, it is used as the base revision.
3817 If two revisions are given, the differences between them are
3819 If two revisions are given, the differences between them are
3818 shown. The --change option can also be used as a shortcut to list
3820 shown. The --change option can also be used as a shortcut to list
3819 the changed files of a revision from its first parent.
3821 the changed files of a revision from its first parent.
3820
3822
3821 The codes used to show the status of files are::
3823 The codes used to show the status of files are::
3822
3824
3823 M = modified
3825 M = modified
3824 A = added
3826 A = added
3825 R = removed
3827 R = removed
3826 C = clean
3828 C = clean
3827 ! = missing (deleted by non-hg command, but still tracked)
3829 ! = missing (deleted by non-hg command, but still tracked)
3828 ? = not tracked
3830 ? = not tracked
3829 I = ignored
3831 I = ignored
3830 = origin of the previous file listed as A (added)
3832 = origin of the previous file listed as A (added)
3831
3833
3832 Returns 0 on success.
3834 Returns 0 on success.
3833 """
3835 """
3834
3836
3835 revs = opts.get('rev')
3837 revs = opts.get('rev')
3836 change = opts.get('change')
3838 change = opts.get('change')
3837
3839
3838 if revs and change:
3840 if revs and change:
3839 msg = _('cannot specify --rev and --change at the same time')
3841 msg = _('cannot specify --rev and --change at the same time')
3840 raise util.Abort(msg)
3842 raise util.Abort(msg)
3841 elif change:
3843 elif change:
3842 node2 = repo.lookup(change)
3844 node2 = repo.lookup(change)
3843 node1 = repo[node2].p1().node()
3845 node1 = repo[node2].p1().node()
3844 else:
3846 else:
3845 node1, node2 = cmdutil.revpair(repo, revs)
3847 node1, node2 = cmdutil.revpair(repo, revs)
3846
3848
3847 cwd = (pats and repo.getcwd()) or ''
3849 cwd = (pats and repo.getcwd()) or ''
3848 end = opts.get('print0') and '\0' or '\n'
3850 end = opts.get('print0') and '\0' or '\n'
3849 copy = {}
3851 copy = {}
3850 states = 'modified added removed deleted unknown ignored clean'.split()
3852 states = 'modified added removed deleted unknown ignored clean'.split()
3851 show = [k for k in states if opts.get(k)]
3853 show = [k for k in states if opts.get(k)]
3852 if opts.get('all'):
3854 if opts.get('all'):
3853 show += ui.quiet and (states[:4] + ['clean']) or states
3855 show += ui.quiet and (states[:4] + ['clean']) or states
3854 if not show:
3856 if not show:
3855 show = ui.quiet and states[:4] or states[:5]
3857 show = ui.quiet and states[:4] or states[:5]
3856
3858
3857 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3859 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3858 'ignored' in show, 'clean' in show, 'unknown' in show,
3860 'ignored' in show, 'clean' in show, 'unknown' in show,
3859 opts.get('subrepos'))
3861 opts.get('subrepos'))
3860 changestates = zip(states, 'MAR!?IC', stat)
3862 changestates = zip(states, 'MAR!?IC', stat)
3861
3863
3862 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3864 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3863 ctxn = repo[nullid]
3865 ctxn = repo[nullid]
3864 ctx1 = repo[node1]
3866 ctx1 = repo[node1]
3865 ctx2 = repo[node2]
3867 ctx2 = repo[node2]
3866 added = stat[1]
3868 added = stat[1]
3867 if node2 is None:
3869 if node2 is None:
3868 added = stat[0] + stat[1] # merged?
3870 added = stat[0] + stat[1] # merged?
3869
3871
3870 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3872 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3871 if k in added:
3873 if k in added:
3872 copy[k] = v
3874 copy[k] = v
3873 elif v in added:
3875 elif v in added:
3874 copy[v] = k
3876 copy[v] = k
3875
3877
3876 for state, char, files in changestates:
3878 for state, char, files in changestates:
3877 if state in show:
3879 if state in show:
3878 format = "%s %%s%s" % (char, end)
3880 format = "%s %%s%s" % (char, end)
3879 if opts.get('no_status'):
3881 if opts.get('no_status'):
3880 format = "%%s%s" % end
3882 format = "%%s%s" % end
3881
3883
3882 for f in files:
3884 for f in files:
3883 ui.write(format % repo.pathto(f, cwd),
3885 ui.write(format % repo.pathto(f, cwd),
3884 label='status.' + state)
3886 label='status.' + state)
3885 if f in copy:
3887 if f in copy:
3886 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3888 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3887 label='status.copied')
3889 label='status.copied')
3888
3890
3889 def summary(ui, repo, **opts):
3891 def summary(ui, repo, **opts):
3890 """summarize working directory state
3892 """summarize working directory state
3891
3893
3892 This generates a brief summary of the working directory state,
3894 This generates a brief summary of the working directory state,
3893 including parents, branch, commit status, and available updates.
3895 including parents, branch, commit status, and available updates.
3894
3896
3895 With the --remote option, this will check the default paths for
3897 With the --remote option, this will check the default paths for
3896 incoming and outgoing changes. This can be time-consuming.
3898 incoming and outgoing changes. This can be time-consuming.
3897
3899
3898 Returns 0 on success.
3900 Returns 0 on success.
3899 """
3901 """
3900
3902
3901 ctx = repo[None]
3903 ctx = repo[None]
3902 parents = ctx.parents()
3904 parents = ctx.parents()
3903 pnode = parents[0].node()
3905 pnode = parents[0].node()
3904
3906
3905 for p in parents:
3907 for p in parents:
3906 # label with log.changeset (instead of log.parent) since this
3908 # label with log.changeset (instead of log.parent) since this
3907 # shows a working directory parent *changeset*:
3909 # shows a working directory parent *changeset*:
3908 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3910 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3909 label='log.changeset')
3911 label='log.changeset')
3910 ui.write(' '.join(p.tags()), label='log.tag')
3912 ui.write(' '.join(p.tags()), label='log.tag')
3911 if p.bookmarks():
3913 if p.bookmarks():
3912 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3914 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3913 if p.rev() == -1:
3915 if p.rev() == -1:
3914 if not len(repo):
3916 if not len(repo):
3915 ui.write(_(' (empty repository)'))
3917 ui.write(_(' (empty repository)'))
3916 else:
3918 else:
3917 ui.write(_(' (no revision checked out)'))
3919 ui.write(_(' (no revision checked out)'))
3918 ui.write('\n')
3920 ui.write('\n')
3919 if p.description():
3921 if p.description():
3920 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3922 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3921 label='log.summary')
3923 label='log.summary')
3922
3924
3923 branch = ctx.branch()
3925 branch = ctx.branch()
3924 bheads = repo.branchheads(branch)
3926 bheads = repo.branchheads(branch)
3925 m = _('branch: %s\n') % branch
3927 m = _('branch: %s\n') % branch
3926 if branch != 'default':
3928 if branch != 'default':
3927 ui.write(m, label='log.branch')
3929 ui.write(m, label='log.branch')
3928 else:
3930 else:
3929 ui.status(m, label='log.branch')
3931 ui.status(m, label='log.branch')
3930
3932
3931 st = list(repo.status(unknown=True))[:6]
3933 st = list(repo.status(unknown=True))[:6]
3932
3934
3933 c = repo.dirstate.copies()
3935 c = repo.dirstate.copies()
3934 copied, renamed = [], []
3936 copied, renamed = [], []
3935 for d, s in c.iteritems():
3937 for d, s in c.iteritems():
3936 if s in st[2]:
3938 if s in st[2]:
3937 st[2].remove(s)
3939 st[2].remove(s)
3938 renamed.append(d)
3940 renamed.append(d)
3939 else:
3941 else:
3940 copied.append(d)
3942 copied.append(d)
3941 if d in st[1]:
3943 if d in st[1]:
3942 st[1].remove(d)
3944 st[1].remove(d)
3943 st.insert(3, renamed)
3945 st.insert(3, renamed)
3944 st.insert(4, copied)
3946 st.insert(4, copied)
3945
3947
3946 ms = mergemod.mergestate(repo)
3948 ms = mergemod.mergestate(repo)
3947 st.append([f for f in ms if ms[f] == 'u'])
3949 st.append([f for f in ms if ms[f] == 'u'])
3948
3950
3949 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3951 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3950 st.append(subs)
3952 st.append(subs)
3951
3953
3952 labels = [ui.label(_('%d modified'), 'status.modified'),
3954 labels = [ui.label(_('%d modified'), 'status.modified'),
3953 ui.label(_('%d added'), 'status.added'),
3955 ui.label(_('%d added'), 'status.added'),
3954 ui.label(_('%d removed'), 'status.removed'),
3956 ui.label(_('%d removed'), 'status.removed'),
3955 ui.label(_('%d renamed'), 'status.copied'),
3957 ui.label(_('%d renamed'), 'status.copied'),
3956 ui.label(_('%d copied'), 'status.copied'),
3958 ui.label(_('%d copied'), 'status.copied'),
3957 ui.label(_('%d deleted'), 'status.deleted'),
3959 ui.label(_('%d deleted'), 'status.deleted'),
3958 ui.label(_('%d unknown'), 'status.unknown'),
3960 ui.label(_('%d unknown'), 'status.unknown'),
3959 ui.label(_('%d ignored'), 'status.ignored'),
3961 ui.label(_('%d ignored'), 'status.ignored'),
3960 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3962 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3961 ui.label(_('%d subrepos'), 'status.modified')]
3963 ui.label(_('%d subrepos'), 'status.modified')]
3962 t = []
3964 t = []
3963 for s, l in zip(st, labels):
3965 for s, l in zip(st, labels):
3964 if s:
3966 if s:
3965 t.append(l % len(s))
3967 t.append(l % len(s))
3966
3968
3967 t = ', '.join(t)
3969 t = ', '.join(t)
3968 cleanworkdir = False
3970 cleanworkdir = False
3969
3971
3970 if len(parents) > 1:
3972 if len(parents) > 1:
3971 t += _(' (merge)')
3973 t += _(' (merge)')
3972 elif branch != parents[0].branch():
3974 elif branch != parents[0].branch():
3973 t += _(' (new branch)')
3975 t += _(' (new branch)')
3974 elif (parents[0].extra().get('close') and
3976 elif (parents[0].extra().get('close') and
3975 pnode in repo.branchheads(branch, closed=True)):
3977 pnode in repo.branchheads(branch, closed=True)):
3976 t += _(' (head closed)')
3978 t += _(' (head closed)')
3977 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3979 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3978 t += _(' (clean)')
3980 t += _(' (clean)')
3979 cleanworkdir = True
3981 cleanworkdir = True
3980 elif pnode not in bheads:
3982 elif pnode not in bheads:
3981 t += _(' (new branch head)')
3983 t += _(' (new branch head)')
3982
3984
3983 if cleanworkdir:
3985 if cleanworkdir:
3984 ui.status(_('commit: %s\n') % t.strip())
3986 ui.status(_('commit: %s\n') % t.strip())
3985 else:
3987 else:
3986 ui.write(_('commit: %s\n') % t.strip())
3988 ui.write(_('commit: %s\n') % t.strip())
3987
3989
3988 # all ancestors of branch heads - all ancestors of parent = new csets
3990 # all ancestors of branch heads - all ancestors of parent = new csets
3989 new = [0] * len(repo)
3991 new = [0] * len(repo)
3990 cl = repo.changelog
3992 cl = repo.changelog
3991 for a in [cl.rev(n) for n in bheads]:
3993 for a in [cl.rev(n) for n in bheads]:
3992 new[a] = 1
3994 new[a] = 1
3993 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3995 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3994 new[a] = 1
3996 new[a] = 1
3995 for a in [p.rev() for p in parents]:
3997 for a in [p.rev() for p in parents]:
3996 if a >= 0:
3998 if a >= 0:
3997 new[a] = 0
3999 new[a] = 0
3998 for a in cl.ancestors(*[p.rev() for p in parents]):
4000 for a in cl.ancestors(*[p.rev() for p in parents]):
3999 new[a] = 0
4001 new[a] = 0
4000 new = sum(new)
4002 new = sum(new)
4001
4003
4002 if new == 0:
4004 if new == 0:
4003 ui.status(_('update: (current)\n'))
4005 ui.status(_('update: (current)\n'))
4004 elif pnode not in bheads:
4006 elif pnode not in bheads:
4005 ui.write(_('update: %d new changesets (update)\n') % new)
4007 ui.write(_('update: %d new changesets (update)\n') % new)
4006 else:
4008 else:
4007 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4009 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4008 (new, len(bheads)))
4010 (new, len(bheads)))
4009
4011
4010 if opts.get('remote'):
4012 if opts.get('remote'):
4011 t = []
4013 t = []
4012 source, branches = hg.parseurl(ui.expandpath('default'))
4014 source, branches = hg.parseurl(ui.expandpath('default'))
4013 other = hg.repository(hg.remoteui(repo, {}), source)
4015 other = hg.repository(hg.remoteui(repo, {}), source)
4014 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4016 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4015 ui.debug('comparing with %s\n' % util.hidepassword(source))
4017 ui.debug('comparing with %s\n' % util.hidepassword(source))
4016 repo.ui.pushbuffer()
4018 repo.ui.pushbuffer()
4017 common, incoming, rheads = discovery.findcommonincoming(repo, other)
4019 common, incoming, rheads = discovery.findcommonincoming(repo, other)
4018 repo.ui.popbuffer()
4020 repo.ui.popbuffer()
4019 if incoming:
4021 if incoming:
4020 t.append(_('1 or more incoming'))
4022 t.append(_('1 or more incoming'))
4021
4023
4022 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4024 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4023 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4025 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4024 other = hg.repository(hg.remoteui(repo, {}), dest)
4026 other = hg.repository(hg.remoteui(repo, {}), dest)
4025 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4027 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4026 repo.ui.pushbuffer()
4028 repo.ui.pushbuffer()
4027 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
4029 common, outheads = discovery.findcommonoutgoing(repo, other)
4028 repo.ui.popbuffer()
4030 repo.ui.popbuffer()
4029 o = repo.changelog.findmissing(common=common)
4031 o = repo.changelog.findmissing(common=common, heads=outheads)
4030 if o:
4032 if o:
4031 t.append(_('%d outgoing') % len(o))
4033 t.append(_('%d outgoing') % len(o))
4032 if 'bookmarks' in other.listkeys('namespaces'):
4034 if 'bookmarks' in other.listkeys('namespaces'):
4033 lmarks = repo.listkeys('bookmarks')
4035 lmarks = repo.listkeys('bookmarks')
4034 rmarks = other.listkeys('bookmarks')
4036 rmarks = other.listkeys('bookmarks')
4035 diff = set(rmarks) - set(lmarks)
4037 diff = set(rmarks) - set(lmarks)
4036 if len(diff) > 0:
4038 if len(diff) > 0:
4037 t.append(_('%d incoming bookmarks') % len(diff))
4039 t.append(_('%d incoming bookmarks') % len(diff))
4038 diff = set(lmarks) - set(rmarks)
4040 diff = set(lmarks) - set(rmarks)
4039 if len(diff) > 0:
4041 if len(diff) > 0:
4040 t.append(_('%d outgoing bookmarks') % len(diff))
4042 t.append(_('%d outgoing bookmarks') % len(diff))
4041
4043
4042 if t:
4044 if t:
4043 ui.write(_('remote: %s\n') % (', '.join(t)))
4045 ui.write(_('remote: %s\n') % (', '.join(t)))
4044 else:
4046 else:
4045 ui.status(_('remote: (synced)\n'))
4047 ui.status(_('remote: (synced)\n'))
4046
4048
4047 def tag(ui, repo, name1, *names, **opts):
4049 def tag(ui, repo, name1, *names, **opts):
4048 """add one or more tags for the current or given revision
4050 """add one or more tags for the current or given revision
4049
4051
4050 Name a particular revision using <name>.
4052 Name a particular revision using <name>.
4051
4053
4052 Tags are used to name particular revisions of the repository and are
4054 Tags are used to name particular revisions of the repository and are
4053 very useful to compare different revisions, to go back to significant
4055 very useful to compare different revisions, to go back to significant
4054 earlier versions or to mark branch points as releases, etc. Changing
4056 earlier versions or to mark branch points as releases, etc. Changing
4055 an existing tag is normally disallowed; use -f/--force to override.
4057 an existing tag is normally disallowed; use -f/--force to override.
4056
4058
4057 If no revision is given, the parent of the working directory is
4059 If no revision is given, the parent of the working directory is
4058 used, or tip if no revision is checked out.
4060 used, or tip if no revision is checked out.
4059
4061
4060 To facilitate version control, distribution, and merging of tags,
4062 To facilitate version control, distribution, and merging of tags,
4061 they are stored as a file named ".hgtags" which is managed similarly
4063 they are stored as a file named ".hgtags" which is managed similarly
4062 to other project files and can be hand-edited if necessary. This
4064 to other project files and can be hand-edited if necessary. This
4063 also means that tagging creates a new commit. The file
4065 also means that tagging creates a new commit. The file
4064 ".hg/localtags" is used for local tags (not shared among
4066 ".hg/localtags" is used for local tags (not shared among
4065 repositories).
4067 repositories).
4066
4068
4067 Tag commits are usually made at the head of a branch. If the parent
4069 Tag commits are usually made at the head of a branch. If the parent
4068 of the working directory is not a branch head, :hg:`tag` aborts; use
4070 of the working directory is not a branch head, :hg:`tag` aborts; use
4069 -f/--force to force the tag commit to be based on a non-head
4071 -f/--force to force the tag commit to be based on a non-head
4070 changeset.
4072 changeset.
4071
4073
4072 See :hg:`help dates` for a list of formats valid for -d/--date.
4074 See :hg:`help dates` for a list of formats valid for -d/--date.
4073
4075
4074 Since tag names have priority over branch names during revision
4076 Since tag names have priority over branch names during revision
4075 lookup, using an existing branch name as a tag name is discouraged.
4077 lookup, using an existing branch name as a tag name is discouraged.
4076
4078
4077 Returns 0 on success.
4079 Returns 0 on success.
4078 """
4080 """
4079
4081
4080 rev_ = "."
4082 rev_ = "."
4081 names = [t.strip() for t in (name1,) + names]
4083 names = [t.strip() for t in (name1,) + names]
4082 if len(names) != len(set(names)):
4084 if len(names) != len(set(names)):
4083 raise util.Abort(_('tag names must be unique'))
4085 raise util.Abort(_('tag names must be unique'))
4084 for n in names:
4086 for n in names:
4085 if n in ['tip', '.', 'null']:
4087 if n in ['tip', '.', 'null']:
4086 raise util.Abort(_("the name '%s' is reserved") % n)
4088 raise util.Abort(_("the name '%s' is reserved") % n)
4087 if not n:
4089 if not n:
4088 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4090 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4089 if opts.get('rev') and opts.get('remove'):
4091 if opts.get('rev') and opts.get('remove'):
4090 raise util.Abort(_("--rev and --remove are incompatible"))
4092 raise util.Abort(_("--rev and --remove are incompatible"))
4091 if opts.get('rev'):
4093 if opts.get('rev'):
4092 rev_ = opts['rev']
4094 rev_ = opts['rev']
4093 message = opts.get('message')
4095 message = opts.get('message')
4094 if opts.get('remove'):
4096 if opts.get('remove'):
4095 expectedtype = opts.get('local') and 'local' or 'global'
4097 expectedtype = opts.get('local') and 'local' or 'global'
4096 for n in names:
4098 for n in names:
4097 if not repo.tagtype(n):
4099 if not repo.tagtype(n):
4098 raise util.Abort(_("tag '%s' does not exist") % n)
4100 raise util.Abort(_("tag '%s' does not exist") % n)
4099 if repo.tagtype(n) != expectedtype:
4101 if repo.tagtype(n) != expectedtype:
4100 if expectedtype == 'global':
4102 if expectedtype == 'global':
4101 raise util.Abort(_("tag '%s' is not a global tag") % n)
4103 raise util.Abort(_("tag '%s' is not a global tag") % n)
4102 else:
4104 else:
4103 raise util.Abort(_("tag '%s' is not a local tag") % n)
4105 raise util.Abort(_("tag '%s' is not a local tag") % n)
4104 rev_ = nullid
4106 rev_ = nullid
4105 if not message:
4107 if not message:
4106 # we don't translate commit messages
4108 # we don't translate commit messages
4107 message = 'Removed tag %s' % ', '.join(names)
4109 message = 'Removed tag %s' % ', '.join(names)
4108 elif not opts.get('force'):
4110 elif not opts.get('force'):
4109 for n in names:
4111 for n in names:
4110 if n in repo.tags():
4112 if n in repo.tags():
4111 raise util.Abort(_("tag '%s' already exists "
4113 raise util.Abort(_("tag '%s' already exists "
4112 "(use -f to force)") % n)
4114 "(use -f to force)") % n)
4113 if not opts.get('local'):
4115 if not opts.get('local'):
4114 p1, p2 = repo.dirstate.parents()
4116 p1, p2 = repo.dirstate.parents()
4115 if p2 != nullid:
4117 if p2 != nullid:
4116 raise util.Abort(_('uncommitted merge'))
4118 raise util.Abort(_('uncommitted merge'))
4117 bheads = repo.branchheads()
4119 bheads = repo.branchheads()
4118 if not opts.get('force') and bheads and p1 not in bheads:
4120 if not opts.get('force') and bheads and p1 not in bheads:
4119 raise util.Abort(_('not at a branch head (use -f to force)'))
4121 raise util.Abort(_('not at a branch head (use -f to force)'))
4120 r = cmdutil.revsingle(repo, rev_).node()
4122 r = cmdutil.revsingle(repo, rev_).node()
4121
4123
4122 if not message:
4124 if not message:
4123 # we don't translate commit messages
4125 # we don't translate commit messages
4124 message = ('Added tag %s for changeset %s' %
4126 message = ('Added tag %s for changeset %s' %
4125 (', '.join(names), short(r)))
4127 (', '.join(names), short(r)))
4126
4128
4127 date = opts.get('date')
4129 date = opts.get('date')
4128 if date:
4130 if date:
4129 date = util.parsedate(date)
4131 date = util.parsedate(date)
4130
4132
4131 if opts.get('edit'):
4133 if opts.get('edit'):
4132 message = ui.edit(message, ui.username())
4134 message = ui.edit(message, ui.username())
4133
4135
4134 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4136 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4135
4137
4136 def tags(ui, repo):
4138 def tags(ui, repo):
4137 """list repository tags
4139 """list repository tags
4138
4140
4139 This lists both regular and local tags. When the -v/--verbose
4141 This lists both regular and local tags. When the -v/--verbose
4140 switch is used, a third column "local" is printed for local tags.
4142 switch is used, a third column "local" is printed for local tags.
4141
4143
4142 Returns 0 on success.
4144 Returns 0 on success.
4143 """
4145 """
4144
4146
4145 hexfunc = ui.debugflag and hex or short
4147 hexfunc = ui.debugflag and hex or short
4146 tagtype = ""
4148 tagtype = ""
4147
4149
4148 for t, n in reversed(repo.tagslist()):
4150 for t, n in reversed(repo.tagslist()):
4149 if ui.quiet:
4151 if ui.quiet:
4150 ui.write("%s\n" % t)
4152 ui.write("%s\n" % t)
4151 continue
4153 continue
4152
4154
4153 hn = hexfunc(n)
4155 hn = hexfunc(n)
4154 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4156 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4155 spaces = " " * (30 - encoding.colwidth(t))
4157 spaces = " " * (30 - encoding.colwidth(t))
4156
4158
4157 if ui.verbose:
4159 if ui.verbose:
4158 if repo.tagtype(t) == 'local':
4160 if repo.tagtype(t) == 'local':
4159 tagtype = " local"
4161 tagtype = " local"
4160 else:
4162 else:
4161 tagtype = ""
4163 tagtype = ""
4162 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4164 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4163
4165
4164 def tip(ui, repo, **opts):
4166 def tip(ui, repo, **opts):
4165 """show the tip revision
4167 """show the tip revision
4166
4168
4167 The tip revision (usually just called the tip) is the changeset
4169 The tip revision (usually just called the tip) is the changeset
4168 most recently added to the repository (and therefore the most
4170 most recently added to the repository (and therefore the most
4169 recently changed head).
4171 recently changed head).
4170
4172
4171 If you have just made a commit, that commit will be the tip. If
4173 If you have just made a commit, that commit will be the tip. If
4172 you have just pulled changes from another repository, the tip of
4174 you have just pulled changes from another repository, the tip of
4173 that repository becomes the current tip. The "tip" tag is special
4175 that repository becomes the current tip. The "tip" tag is special
4174 and cannot be renamed or assigned to a different changeset.
4176 and cannot be renamed or assigned to a different changeset.
4175
4177
4176 Returns 0 on success.
4178 Returns 0 on success.
4177 """
4179 """
4178 displayer = cmdutil.show_changeset(ui, repo, opts)
4180 displayer = cmdutil.show_changeset(ui, repo, opts)
4179 displayer.show(repo[len(repo) - 1])
4181 displayer.show(repo[len(repo) - 1])
4180 displayer.close()
4182 displayer.close()
4181
4183
4182 def unbundle(ui, repo, fname1, *fnames, **opts):
4184 def unbundle(ui, repo, fname1, *fnames, **opts):
4183 """apply one or more changegroup files
4185 """apply one or more changegroup files
4184
4186
4185 Apply one or more compressed changegroup files generated by the
4187 Apply one or more compressed changegroup files generated by the
4186 bundle command.
4188 bundle command.
4187
4189
4188 Returns 0 on success, 1 if an update has unresolved files.
4190 Returns 0 on success, 1 if an update has unresolved files.
4189 """
4191 """
4190 fnames = (fname1,) + fnames
4192 fnames = (fname1,) + fnames
4191
4193
4192 lock = repo.lock()
4194 lock = repo.lock()
4193 wc = repo['.']
4195 wc = repo['.']
4194 try:
4196 try:
4195 for fname in fnames:
4197 for fname in fnames:
4196 f = url.open(ui, fname)
4198 f = url.open(ui, fname)
4197 gen = changegroup.readbundle(f, fname)
4199 gen = changegroup.readbundle(f, fname)
4198 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4200 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4199 lock=lock)
4201 lock=lock)
4200 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4202 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4201 finally:
4203 finally:
4202 lock.release()
4204 lock.release()
4203 return postincoming(ui, repo, modheads, opts.get('update'), None)
4205 return postincoming(ui, repo, modheads, opts.get('update'), None)
4204
4206
4205 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4207 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4206 """update working directory (or switch revisions)
4208 """update working directory (or switch revisions)
4207
4209
4208 Update the repository's working directory to the specified
4210 Update the repository's working directory to the specified
4209 changeset. If no changeset is specified, update to the tip of the
4211 changeset. If no changeset is specified, update to the tip of the
4210 current named branch.
4212 current named branch.
4211
4213
4212 If the changeset is not a descendant of the working directory's
4214 If the changeset is not a descendant of the working directory's
4213 parent, the update is aborted. With the -c/--check option, the
4215 parent, the update is aborted. With the -c/--check option, the
4214 working directory is checked for uncommitted changes; if none are
4216 working directory is checked for uncommitted changes; if none are
4215 found, the working directory is updated to the specified
4217 found, the working directory is updated to the specified
4216 changeset.
4218 changeset.
4217
4219
4218 The following rules apply when the working directory contains
4220 The following rules apply when the working directory contains
4219 uncommitted changes:
4221 uncommitted changes:
4220
4222
4221 1. If neither -c/--check nor -C/--clean is specified, and if
4223 1. If neither -c/--check nor -C/--clean is specified, and if
4222 the requested changeset is an ancestor or descendant of
4224 the requested changeset is an ancestor or descendant of
4223 the working directory's parent, the uncommitted changes
4225 the working directory's parent, the uncommitted changes
4224 are merged into the requested changeset and the merged
4226 are merged into the requested changeset and the merged
4225 result is left uncommitted. If the requested changeset is
4227 result is left uncommitted. If the requested changeset is
4226 not an ancestor or descendant (that is, it is on another
4228 not an ancestor or descendant (that is, it is on another
4227 branch), the update is aborted and the uncommitted changes
4229 branch), the update is aborted and the uncommitted changes
4228 are preserved.
4230 are preserved.
4229
4231
4230 2. With the -c/--check option, the update is aborted and the
4232 2. With the -c/--check option, the update is aborted and the
4231 uncommitted changes are preserved.
4233 uncommitted changes are preserved.
4232
4234
4233 3. With the -C/--clean option, uncommitted changes are discarded and
4235 3. With the -C/--clean option, uncommitted changes are discarded and
4234 the working directory is updated to the requested changeset.
4236 the working directory is updated to the requested changeset.
4235
4237
4236 Use null as the changeset to remove the working directory (like
4238 Use null as the changeset to remove the working directory (like
4237 :hg:`clone -U`).
4239 :hg:`clone -U`).
4238
4240
4239 If you want to update just one file to an older changeset, use
4241 If you want to update just one file to an older changeset, use
4240 :hg:`revert`.
4242 :hg:`revert`.
4241
4243
4242 See :hg:`help dates` for a list of formats valid for -d/--date.
4244 See :hg:`help dates` for a list of formats valid for -d/--date.
4243
4245
4244 Returns 0 on success, 1 if there are unresolved files.
4246 Returns 0 on success, 1 if there are unresolved files.
4245 """
4247 """
4246 if rev and node:
4248 if rev and node:
4247 raise util.Abort(_("please specify just one revision"))
4249 raise util.Abort(_("please specify just one revision"))
4248
4250
4249 if rev is None or rev == '':
4251 if rev is None or rev == '':
4250 rev = node
4252 rev = node
4251
4253
4252 # if we defined a bookmark, we have to remember the original bookmark name
4254 # if we defined a bookmark, we have to remember the original bookmark name
4253 brev = rev
4255 brev = rev
4254 rev = cmdutil.revsingle(repo, rev, rev).rev()
4256 rev = cmdutil.revsingle(repo, rev, rev).rev()
4255
4257
4256 if check and clean:
4258 if check and clean:
4257 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4259 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4258
4260
4259 if check:
4261 if check:
4260 # we could use dirty() but we can ignore merge and branch trivia
4262 # we could use dirty() but we can ignore merge and branch trivia
4261 c = repo[None]
4263 c = repo[None]
4262 if c.modified() or c.added() or c.removed():
4264 if c.modified() or c.added() or c.removed():
4263 raise util.Abort(_("uncommitted local changes"))
4265 raise util.Abort(_("uncommitted local changes"))
4264
4266
4265 if date:
4267 if date:
4266 if rev is not None:
4268 if rev is not None:
4267 raise util.Abort(_("you can't specify a revision and a date"))
4269 raise util.Abort(_("you can't specify a revision and a date"))
4268 rev = cmdutil.finddate(ui, repo, date)
4270 rev = cmdutil.finddate(ui, repo, date)
4269
4271
4270 if clean or check:
4272 if clean or check:
4271 ret = hg.clean(repo, rev)
4273 ret = hg.clean(repo, rev)
4272 else:
4274 else:
4273 ret = hg.update(repo, rev)
4275 ret = hg.update(repo, rev)
4274
4276
4275 if brev in repo._bookmarks:
4277 if brev in repo._bookmarks:
4276 bookmarks.setcurrent(repo, brev)
4278 bookmarks.setcurrent(repo, brev)
4277
4279
4278 return ret
4280 return ret
4279
4281
4280 def verify(ui, repo):
4282 def verify(ui, repo):
4281 """verify the integrity of the repository
4283 """verify the integrity of the repository
4282
4284
4283 Verify the integrity of the current repository.
4285 Verify the integrity of the current repository.
4284
4286
4285 This will perform an extensive check of the repository's
4287 This will perform an extensive check of the repository's
4286 integrity, validating the hashes and checksums of each entry in
4288 integrity, validating the hashes and checksums of each entry in
4287 the changelog, manifest, and tracked files, as well as the
4289 the changelog, manifest, and tracked files, as well as the
4288 integrity of their crosslinks and indices.
4290 integrity of their crosslinks and indices.
4289
4291
4290 Returns 0 on success, 1 if errors are encountered.
4292 Returns 0 on success, 1 if errors are encountered.
4291 """
4293 """
4292 return hg.verify(repo)
4294 return hg.verify(repo)
4293
4295
4294 def version_(ui):
4296 def version_(ui):
4295 """output version and copyright information"""
4297 """output version and copyright information"""
4296 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4298 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4297 % util.version())
4299 % util.version())
4298 ui.status(_(
4300 ui.status(_(
4299 "(see http://mercurial.selenic.com for more information)\n"
4301 "(see http://mercurial.selenic.com for more information)\n"
4300 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4302 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4301 "This is free software; see the source for copying conditions. "
4303 "This is free software; see the source for copying conditions. "
4302 "There is NO\nwarranty; "
4304 "There is NO\nwarranty; "
4303 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4305 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4304 ))
4306 ))
4305
4307
4306 # Command options and aliases are listed here, alphabetically
4308 # Command options and aliases are listed here, alphabetically
4307
4309
4308 globalopts = [
4310 globalopts = [
4309 ('R', 'repository', '',
4311 ('R', 'repository', '',
4310 _('repository root directory or name of overlay bundle file'),
4312 _('repository root directory or name of overlay bundle file'),
4311 _('REPO')),
4313 _('REPO')),
4312 ('', 'cwd', '',
4314 ('', 'cwd', '',
4313 _('change working directory'), _('DIR')),
4315 _('change working directory'), _('DIR')),
4314 ('y', 'noninteractive', None,
4316 ('y', 'noninteractive', None,
4315 _('do not prompt, assume \'yes\' for any required answers')),
4317 _('do not prompt, assume \'yes\' for any required answers')),
4316 ('q', 'quiet', None, _('suppress output')),
4318 ('q', 'quiet', None, _('suppress output')),
4317 ('v', 'verbose', None, _('enable additional output')),
4319 ('v', 'verbose', None, _('enable additional output')),
4318 ('', 'config', [],
4320 ('', 'config', [],
4319 _('set/override config option (use \'section.name=value\')'),
4321 _('set/override config option (use \'section.name=value\')'),
4320 _('CONFIG')),
4322 _('CONFIG')),
4321 ('', 'debug', None, _('enable debugging output')),
4323 ('', 'debug', None, _('enable debugging output')),
4322 ('', 'debugger', None, _('start debugger')),
4324 ('', 'debugger', None, _('start debugger')),
4323 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4325 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4324 _('ENCODE')),
4326 _('ENCODE')),
4325 ('', 'encodingmode', encoding.encodingmode,
4327 ('', 'encodingmode', encoding.encodingmode,
4326 _('set the charset encoding mode'), _('MODE')),
4328 _('set the charset encoding mode'), _('MODE')),
4327 ('', 'traceback', None, _('always print a traceback on exception')),
4329 ('', 'traceback', None, _('always print a traceback on exception')),
4328 ('', 'time', None, _('time how long the command takes')),
4330 ('', 'time', None, _('time how long the command takes')),
4329 ('', 'profile', None, _('print command execution profile')),
4331 ('', 'profile', None, _('print command execution profile')),
4330 ('', 'version', None, _('output version information and exit')),
4332 ('', 'version', None, _('output version information and exit')),
4331 ('h', 'help', None, _('display help and exit')),
4333 ('h', 'help', None, _('display help and exit')),
4332 ]
4334 ]
4333
4335
4334 dryrunopts = [('n', 'dry-run', None,
4336 dryrunopts = [('n', 'dry-run', None,
4335 _('do not perform actions, just print output'))]
4337 _('do not perform actions, just print output'))]
4336
4338
4337 remoteopts = [
4339 remoteopts = [
4338 ('e', 'ssh', '',
4340 ('e', 'ssh', '',
4339 _('specify ssh command to use'), _('CMD')),
4341 _('specify ssh command to use'), _('CMD')),
4340 ('', 'remotecmd', '',
4342 ('', 'remotecmd', '',
4341 _('specify hg command to run on the remote side'), _('CMD')),
4343 _('specify hg command to run on the remote side'), _('CMD')),
4342 ('', 'insecure', None,
4344 ('', 'insecure', None,
4343 _('do not verify server certificate (ignoring web.cacerts config)')),
4345 _('do not verify server certificate (ignoring web.cacerts config)')),
4344 ]
4346 ]
4345
4347
4346 walkopts = [
4348 walkopts = [
4347 ('I', 'include', [],
4349 ('I', 'include', [],
4348 _('include names matching the given patterns'), _('PATTERN')),
4350 _('include names matching the given patterns'), _('PATTERN')),
4349 ('X', 'exclude', [],
4351 ('X', 'exclude', [],
4350 _('exclude names matching the given patterns'), _('PATTERN')),
4352 _('exclude names matching the given patterns'), _('PATTERN')),
4351 ]
4353 ]
4352
4354
4353 commitopts = [
4355 commitopts = [
4354 ('m', 'message', '',
4356 ('m', 'message', '',
4355 _('use text as commit message'), _('TEXT')),
4357 _('use text as commit message'), _('TEXT')),
4356 ('l', 'logfile', '',
4358 ('l', 'logfile', '',
4357 _('read commit message from file'), _('FILE')),
4359 _('read commit message from file'), _('FILE')),
4358 ]
4360 ]
4359
4361
4360 commitopts2 = [
4362 commitopts2 = [
4361 ('d', 'date', '',
4363 ('d', 'date', '',
4362 _('record the specified date as commit date'), _('DATE')),
4364 _('record the specified date as commit date'), _('DATE')),
4363 ('u', 'user', '',
4365 ('u', 'user', '',
4364 _('record the specified user as committer'), _('USER')),
4366 _('record the specified user as committer'), _('USER')),
4365 ]
4367 ]
4366
4368
4367 templateopts = [
4369 templateopts = [
4368 ('', 'style', '',
4370 ('', 'style', '',
4369 _('display using template map file'), _('STYLE')),
4371 _('display using template map file'), _('STYLE')),
4370 ('', 'template', '',
4372 ('', 'template', '',
4371 _('display with template'), _('TEMPLATE')),
4373 _('display with template'), _('TEMPLATE')),
4372 ]
4374 ]
4373
4375
4374 logopts = [
4376 logopts = [
4375 ('p', 'patch', None, _('show patch')),
4377 ('p', 'patch', None, _('show patch')),
4376 ('g', 'git', None, _('use git extended diff format')),
4378 ('g', 'git', None, _('use git extended diff format')),
4377 ('l', 'limit', '',
4379 ('l', 'limit', '',
4378 _('limit number of changes displayed'), _('NUM')),
4380 _('limit number of changes displayed'), _('NUM')),
4379 ('M', 'no-merges', None, _('do not show merges')),
4381 ('M', 'no-merges', None, _('do not show merges')),
4380 ('', 'stat', None, _('output diffstat-style summary of changes')),
4382 ('', 'stat', None, _('output diffstat-style summary of changes')),
4381 ] + templateopts
4383 ] + templateopts
4382
4384
4383 diffopts = [
4385 diffopts = [
4384 ('a', 'text', None, _('treat all files as text')),
4386 ('a', 'text', None, _('treat all files as text')),
4385 ('g', 'git', None, _('use git extended diff format')),
4387 ('g', 'git', None, _('use git extended diff format')),
4386 ('', 'nodates', None, _('omit dates from diff headers'))
4388 ('', 'nodates', None, _('omit dates from diff headers'))
4387 ]
4389 ]
4388
4390
4389 diffopts2 = [
4391 diffopts2 = [
4390 ('p', 'show-function', None, _('show which function each change is in')),
4392 ('p', 'show-function', None, _('show which function each change is in')),
4391 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4393 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4392 ('w', 'ignore-all-space', None,
4394 ('w', 'ignore-all-space', None,
4393 _('ignore white space when comparing lines')),
4395 _('ignore white space when comparing lines')),
4394 ('b', 'ignore-space-change', None,
4396 ('b', 'ignore-space-change', None,
4395 _('ignore changes in the amount of white space')),
4397 _('ignore changes in the amount of white space')),
4396 ('B', 'ignore-blank-lines', None,
4398 ('B', 'ignore-blank-lines', None,
4397 _('ignore changes whose lines are all blank')),
4399 _('ignore changes whose lines are all blank')),
4398 ('U', 'unified', '',
4400 ('U', 'unified', '',
4399 _('number of lines of context to show'), _('NUM')),
4401 _('number of lines of context to show'), _('NUM')),
4400 ('', 'stat', None, _('output diffstat-style summary of changes')),
4402 ('', 'stat', None, _('output diffstat-style summary of changes')),
4401 ]
4403 ]
4402
4404
4403 similarityopts = [
4405 similarityopts = [
4404 ('s', 'similarity', '',
4406 ('s', 'similarity', '',
4405 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4407 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4406 ]
4408 ]
4407
4409
4408 subrepoopts = [
4410 subrepoopts = [
4409 ('S', 'subrepos', None,
4411 ('S', 'subrepos', None,
4410 _('recurse into subrepositories'))
4412 _('recurse into subrepositories'))
4411 ]
4413 ]
4412
4414
4413 table = {
4415 table = {
4414 "^add": (add, walkopts + subrepoopts + dryrunopts,
4416 "^add": (add, walkopts + subrepoopts + dryrunopts,
4415 _('[OPTION]... [FILE]...')),
4417 _('[OPTION]... [FILE]...')),
4416 "addremove":
4418 "addremove":
4417 (addremove, similarityopts + walkopts + dryrunopts,
4419 (addremove, similarityopts + walkopts + dryrunopts,
4418 _('[OPTION]... [FILE]...')),
4420 _('[OPTION]... [FILE]...')),
4419 "^annotate|blame":
4421 "^annotate|blame":
4420 (annotate,
4422 (annotate,
4421 [('r', 'rev', '',
4423 [('r', 'rev', '',
4422 _('annotate the specified revision'), _('REV')),
4424 _('annotate the specified revision'), _('REV')),
4423 ('', 'follow', None,
4425 ('', 'follow', None,
4424 _('follow copies/renames and list the filename (DEPRECATED)')),
4426 _('follow copies/renames and list the filename (DEPRECATED)')),
4425 ('', 'no-follow', None, _("don't follow copies and renames")),
4427 ('', 'no-follow', None, _("don't follow copies and renames")),
4426 ('a', 'text', None, _('treat all files as text')),
4428 ('a', 'text', None, _('treat all files as text')),
4427 ('u', 'user', None, _('list the author (long with -v)')),
4429 ('u', 'user', None, _('list the author (long with -v)')),
4428 ('f', 'file', None, _('list the filename')),
4430 ('f', 'file', None, _('list the filename')),
4429 ('d', 'date', None, _('list the date (short with -q)')),
4431 ('d', 'date', None, _('list the date (short with -q)')),
4430 ('n', 'number', None, _('list the revision number (default)')),
4432 ('n', 'number', None, _('list the revision number (default)')),
4431 ('c', 'changeset', None, _('list the changeset')),
4433 ('c', 'changeset', None, _('list the changeset')),
4432 ('l', 'line-number', None,
4434 ('l', 'line-number', None,
4433 _('show line number at the first appearance'))
4435 _('show line number at the first appearance'))
4434 ] + walkopts,
4436 ] + walkopts,
4435 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4437 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4436 "archive":
4438 "archive":
4437 (archive,
4439 (archive,
4438 [('', 'no-decode', None, _('do not pass files through decoders')),
4440 [('', 'no-decode', None, _('do not pass files through decoders')),
4439 ('p', 'prefix', '',
4441 ('p', 'prefix', '',
4440 _('directory prefix for files in archive'), _('PREFIX')),
4442 _('directory prefix for files in archive'), _('PREFIX')),
4441 ('r', 'rev', '',
4443 ('r', 'rev', '',
4442 _('revision to distribute'), _('REV')),
4444 _('revision to distribute'), _('REV')),
4443 ('t', 'type', '',
4445 ('t', 'type', '',
4444 _('type of distribution to create'), _('TYPE')),
4446 _('type of distribution to create'), _('TYPE')),
4445 ] + subrepoopts + walkopts,
4447 ] + subrepoopts + walkopts,
4446 _('[OPTION]... DEST')),
4448 _('[OPTION]... DEST')),
4447 "backout":
4449 "backout":
4448 (backout,
4450 (backout,
4449 [('', 'merge', None,
4451 [('', 'merge', None,
4450 _('merge with old dirstate parent after backout')),
4452 _('merge with old dirstate parent after backout')),
4451 ('', 'parent', '',
4453 ('', 'parent', '',
4452 _('parent to choose when backing out merge'), _('REV')),
4454 _('parent to choose when backing out merge'), _('REV')),
4453 ('t', 'tool', '',
4455 ('t', 'tool', '',
4454 _('specify merge tool')),
4456 _('specify merge tool')),
4455 ('r', 'rev', '',
4457 ('r', 'rev', '',
4456 _('revision to backout'), _('REV')),
4458 _('revision to backout'), _('REV')),
4457 ] + walkopts + commitopts + commitopts2,
4459 ] + walkopts + commitopts + commitopts2,
4458 _('[OPTION]... [-r] REV')),
4460 _('[OPTION]... [-r] REV')),
4459 "bisect":
4461 "bisect":
4460 (bisect,
4462 (bisect,
4461 [('r', 'reset', False, _('reset bisect state')),
4463 [('r', 'reset', False, _('reset bisect state')),
4462 ('g', 'good', False, _('mark changeset good')),
4464 ('g', 'good', False, _('mark changeset good')),
4463 ('b', 'bad', False, _('mark changeset bad')),
4465 ('b', 'bad', False, _('mark changeset bad')),
4464 ('s', 'skip', False, _('skip testing changeset')),
4466 ('s', 'skip', False, _('skip testing changeset')),
4465 ('e', 'extend', False, _('extend the bisect range')),
4467 ('e', 'extend', False, _('extend the bisect range')),
4466 ('c', 'command', '',
4468 ('c', 'command', '',
4467 _('use command to check changeset state'), _('CMD')),
4469 _('use command to check changeset state'), _('CMD')),
4468 ('U', 'noupdate', False, _('do not update to target'))],
4470 ('U', 'noupdate', False, _('do not update to target'))],
4469 _("[-gbsr] [-U] [-c CMD] [REV]")),
4471 _("[-gbsr] [-U] [-c CMD] [REV]")),
4470 "bookmarks":
4472 "bookmarks":
4471 (bookmark,
4473 (bookmark,
4472 [('f', 'force', False, _('force')),
4474 [('f', 'force', False, _('force')),
4473 ('r', 'rev', '', _('revision'), _('REV')),
4475 ('r', 'rev', '', _('revision'), _('REV')),
4474 ('d', 'delete', False, _('delete a given bookmark')),
4476 ('d', 'delete', False, _('delete a given bookmark')),
4475 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4477 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4476 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4478 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4477 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4479 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4478 "branch":
4480 "branch":
4479 (branch,
4481 (branch,
4480 [('f', 'force', None,
4482 [('f', 'force', None,
4481 _('set branch name even if it shadows an existing branch')),
4483 _('set branch name even if it shadows an existing branch')),
4482 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4484 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4483 _('[-fC] [NAME]')),
4485 _('[-fC] [NAME]')),
4484 "branches":
4486 "branches":
4485 (branches,
4487 (branches,
4486 [('a', 'active', False,
4488 [('a', 'active', False,
4487 _('show only branches that have unmerged heads')),
4489 _('show only branches that have unmerged heads')),
4488 ('c', 'closed', False,
4490 ('c', 'closed', False,
4489 _('show normal and closed branches'))],
4491 _('show normal and closed branches'))],
4490 _('[-ac]')),
4492 _('[-ac]')),
4491 "bundle":
4493 "bundle":
4492 (bundle,
4494 (bundle,
4493 [('f', 'force', None,
4495 [('f', 'force', None,
4494 _('run even when the destination is unrelated')),
4496 _('run even when the destination is unrelated')),
4495 ('r', 'rev', [],
4497 ('r', 'rev', [],
4496 _('a changeset intended to be added to the destination'),
4498 _('a changeset intended to be added to the destination'),
4497 _('REV')),
4499 _('REV')),
4498 ('b', 'branch', [],
4500 ('b', 'branch', [],
4499 _('a specific branch you would like to bundle'),
4501 _('a specific branch you would like to bundle'),
4500 _('BRANCH')),
4502 _('BRANCH')),
4501 ('', 'base', [],
4503 ('', 'base', [],
4502 _('a base changeset assumed to be available at the destination'),
4504 _('a base changeset assumed to be available at the destination'),
4503 _('REV')),
4505 _('REV')),
4504 ('a', 'all', None, _('bundle all changesets in the repository')),
4506 ('a', 'all', None, _('bundle all changesets in the repository')),
4505 ('t', 'type', 'bzip2',
4507 ('t', 'type', 'bzip2',
4506 _('bundle compression type to use'), _('TYPE')),
4508 _('bundle compression type to use'), _('TYPE')),
4507 ] + remoteopts,
4509 ] + remoteopts,
4508 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4510 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4509 "cat":
4511 "cat":
4510 (cat,
4512 (cat,
4511 [('o', 'output', '',
4513 [('o', 'output', '',
4512 _('print output to file with formatted name'), _('FORMAT')),
4514 _('print output to file with formatted name'), _('FORMAT')),
4513 ('r', 'rev', '',
4515 ('r', 'rev', '',
4514 _('print the given revision'), _('REV')),
4516 _('print the given revision'), _('REV')),
4515 ('', 'decode', None, _('apply any matching decode filter')),
4517 ('', 'decode', None, _('apply any matching decode filter')),
4516 ] + walkopts,
4518 ] + walkopts,
4517 _('[OPTION]... FILE...')),
4519 _('[OPTION]... FILE...')),
4518 "^clone":
4520 "^clone":
4519 (clone,
4521 (clone,
4520 [('U', 'noupdate', None,
4522 [('U', 'noupdate', None,
4521 _('the clone will include an empty working copy (only a repository)')),
4523 _('the clone will include an empty working copy (only a repository)')),
4522 ('u', 'updaterev', '',
4524 ('u', 'updaterev', '',
4523 _('revision, tag or branch to check out'), _('REV')),
4525 _('revision, tag or branch to check out'), _('REV')),
4524 ('r', 'rev', [],
4526 ('r', 'rev', [],
4525 _('include the specified changeset'), _('REV')),
4527 _('include the specified changeset'), _('REV')),
4526 ('b', 'branch', [],
4528 ('b', 'branch', [],
4527 _('clone only the specified branch'), _('BRANCH')),
4529 _('clone only the specified branch'), _('BRANCH')),
4528 ('', 'pull', None, _('use pull protocol to copy metadata')),
4530 ('', 'pull', None, _('use pull protocol to copy metadata')),
4529 ('', 'uncompressed', None,
4531 ('', 'uncompressed', None,
4530 _('use uncompressed transfer (fast over LAN)')),
4532 _('use uncompressed transfer (fast over LAN)')),
4531 ] + remoteopts,
4533 ] + remoteopts,
4532 _('[OPTION]... SOURCE [DEST]')),
4534 _('[OPTION]... SOURCE [DEST]')),
4533 "^commit|ci":
4535 "^commit|ci":
4534 (commit,
4536 (commit,
4535 [('A', 'addremove', None,
4537 [('A', 'addremove', None,
4536 _('mark new/missing files as added/removed before committing')),
4538 _('mark new/missing files as added/removed before committing')),
4537 ('', 'close-branch', None,
4539 ('', 'close-branch', None,
4538 _('mark a branch as closed, hiding it from the branch list')),
4540 _('mark a branch as closed, hiding it from the branch list')),
4539 ] + walkopts + commitopts + commitopts2,
4541 ] + walkopts + commitopts + commitopts2,
4540 _('[OPTION]... [FILE]...')),
4542 _('[OPTION]... [FILE]...')),
4541 "copy|cp":
4543 "copy|cp":
4542 (copy,
4544 (copy,
4543 [('A', 'after', None, _('record a copy that has already occurred')),
4545 [('A', 'after', None, _('record a copy that has already occurred')),
4544 ('f', 'force', None,
4546 ('f', 'force', None,
4545 _('forcibly copy over an existing managed file')),
4547 _('forcibly copy over an existing managed file')),
4546 ] + walkopts + dryrunopts,
4548 ] + walkopts + dryrunopts,
4547 _('[OPTION]... [SOURCE]... DEST')),
4549 _('[OPTION]... [SOURCE]... DEST')),
4548 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4550 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4549 "debugbuilddag":
4551 "debugbuilddag":
4550 (debugbuilddag,
4552 (debugbuilddag,
4551 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4553 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4552 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4554 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4553 ('n', 'new-file', None, _('add new file at each rev')),
4555 ('n', 'new-file', None, _('add new file at each rev')),
4554 ],
4556 ],
4555 _('[OPTION]... TEXT')),
4557 _('[OPTION]... TEXT')),
4556 "debugbundle":
4558 "debugbundle":
4557 (debugbundle,
4559 (debugbundle,
4558 [('a', 'all', None, _('show all details')),
4560 [('a', 'all', None, _('show all details')),
4559 ],
4561 ],
4560 _('FILE')),
4562 _('FILE')),
4561 "debugcheckstate": (debugcheckstate, [], ''),
4563 "debugcheckstate": (debugcheckstate, [], ''),
4562 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4564 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4563 "debugcomplete":
4565 "debugcomplete":
4564 (debugcomplete,
4566 (debugcomplete,
4565 [('o', 'options', None, _('show the command options'))],
4567 [('o', 'options', None, _('show the command options'))],
4566 _('[-o] CMD')),
4568 _('[-o] CMD')),
4567 "debugdag":
4569 "debugdag":
4568 (debugdag,
4570 (debugdag,
4569 [('t', 'tags', None, _('use tags as labels')),
4571 [('t', 'tags', None, _('use tags as labels')),
4570 ('b', 'branches', None, _('annotate with branch names')),
4572 ('b', 'branches', None, _('annotate with branch names')),
4571 ('', 'dots', None, _('use dots for runs')),
4573 ('', 'dots', None, _('use dots for runs')),
4572 ('s', 'spaces', None, _('separate elements by spaces')),
4574 ('s', 'spaces', None, _('separate elements by spaces')),
4573 ],
4575 ],
4574 _('[OPTION]... [FILE [REV]...]')),
4576 _('[OPTION]... [FILE [REV]...]')),
4575 "debugdate":
4577 "debugdate":
4576 (debugdate,
4578 (debugdate,
4577 [('e', 'extended', None, _('try extended date formats'))],
4579 [('e', 'extended', None, _('try extended date formats'))],
4578 _('[-e] DATE [RANGE]')),
4580 _('[-e] DATE [RANGE]')),
4579 "debugdata": (debugdata, [], _('FILE REV')),
4581 "debugdata": (debugdata, [], _('FILE REV')),
4580 "debugdiscovery": (debugdiscovery,
4582 "debugdiscovery": (debugdiscovery,
4581 [('', 'old', None,
4583 [('', 'old', None,
4582 _('use old-style discovery')),
4584 _('use old-style discovery')),
4583 ('', 'nonheads', None,
4585 ('', 'nonheads', None,
4584 _('use old-style discovery with non-heads included')),
4586 _('use old-style discovery with non-heads included')),
4585 ] + remoteopts,
4587 ] + remoteopts,
4586 _('[-l REV] [-r REV] [-b BRANCH]...'
4588 _('[-l REV] [-r REV] [-b BRANCH]...'
4587 ' [OTHER]')),
4589 ' [OTHER]')),
4588 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4590 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4589 "debuggetbundle":
4591 "debuggetbundle":
4590 (debuggetbundle,
4592 (debuggetbundle,
4591 [('H', 'head', [], _('id of head node'), _('ID')),
4593 [('H', 'head', [], _('id of head node'), _('ID')),
4592 ('C', 'common', [], _('id of common node'), _('ID')),
4594 ('C', 'common', [], _('id of common node'), _('ID')),
4593 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4595 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4594 ],
4596 ],
4595 _('REPO FILE [-H|-C ID]...')),
4597 _('REPO FILE [-H|-C ID]...')),
4596 "debugignore": (debugignore, [], ''),
4598 "debugignore": (debugignore, [], ''),
4597 "debugindex": (debugindex,
4599 "debugindex": (debugindex,
4598 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4600 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4599 _('FILE')),
4601 _('FILE')),
4600 "debugindexdot": (debugindexdot, [], _('FILE')),
4602 "debugindexdot": (debugindexdot, [], _('FILE')),
4601 "debuginstall": (debuginstall, [], ''),
4603 "debuginstall": (debuginstall, [], ''),
4602 "debugknown": (debugknown, [], _('REPO ID...')),
4604 "debugknown": (debugknown, [], _('REPO ID...')),
4603 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4605 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4604 "debugrebuildstate":
4606 "debugrebuildstate":
4605 (debugrebuildstate,
4607 (debugrebuildstate,
4606 [('r', 'rev', '',
4608 [('r', 'rev', '',
4607 _('revision to rebuild to'), _('REV'))],
4609 _('revision to rebuild to'), _('REV'))],
4608 _('[-r REV] [REV]')),
4610 _('[-r REV] [REV]')),
4609 "debugrename":
4611 "debugrename":
4610 (debugrename,
4612 (debugrename,
4611 [('r', 'rev', '',
4613 [('r', 'rev', '',
4612 _('revision to debug'), _('REV'))],
4614 _('revision to debug'), _('REV'))],
4613 _('[-r REV] FILE')),
4615 _('[-r REV] FILE')),
4614 "debugrevspec":
4616 "debugrevspec":
4615 (debugrevspec, [], ('REVSPEC')),
4617 (debugrevspec, [], ('REVSPEC')),
4616 "debugsetparents":
4618 "debugsetparents":
4617 (debugsetparents, [], _('REV1 [REV2]')),
4619 (debugsetparents, [], _('REV1 [REV2]')),
4618 "debugstate":
4620 "debugstate":
4619 (debugstate,
4621 (debugstate,
4620 [('', 'nodates', None, _('do not display the saved mtime')),
4622 [('', 'nodates', None, _('do not display the saved mtime')),
4621 ('', 'datesort', None, _('sort by saved mtime'))],
4623 ('', 'datesort', None, _('sort by saved mtime'))],
4622 _('[OPTION]...')),
4624 _('[OPTION]...')),
4623 "debugsub":
4625 "debugsub":
4624 (debugsub,
4626 (debugsub,
4625 [('r', 'rev', '',
4627 [('r', 'rev', '',
4626 _('revision to check'), _('REV'))],
4628 _('revision to check'), _('REV'))],
4627 _('[-r REV] [REV]')),
4629 _('[-r REV] [REV]')),
4628 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4630 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4629 "debugwireargs":
4631 "debugwireargs":
4630 (debugwireargs,
4632 (debugwireargs,
4631 [('', 'three', '', 'three'),
4633 [('', 'three', '', 'three'),
4632 ('', 'four', '', 'four'),
4634 ('', 'four', '', 'four'),
4633 ('', 'five', '', 'five'),
4635 ('', 'five', '', 'five'),
4634 ] + remoteopts,
4636 ] + remoteopts,
4635 _('REPO [OPTIONS]... [ONE [TWO]]')),
4637 _('REPO [OPTIONS]... [ONE [TWO]]')),
4636 "^diff":
4638 "^diff":
4637 (diff,
4639 (diff,
4638 [('r', 'rev', [],
4640 [('r', 'rev', [],
4639 _('revision'), _('REV')),
4641 _('revision'), _('REV')),
4640 ('c', 'change', '',
4642 ('c', 'change', '',
4641 _('change made by revision'), _('REV'))
4643 _('change made by revision'), _('REV'))
4642 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4644 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4643 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4645 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4644 "^export":
4646 "^export":
4645 (export,
4647 (export,
4646 [('o', 'output', '',
4648 [('o', 'output', '',
4647 _('print output to file with formatted name'), _('FORMAT')),
4649 _('print output to file with formatted name'), _('FORMAT')),
4648 ('', 'switch-parent', None, _('diff against the second parent')),
4650 ('', 'switch-parent', None, _('diff against the second parent')),
4649 ('r', 'rev', [],
4651 ('r', 'rev', [],
4650 _('revisions to export'), _('REV')),
4652 _('revisions to export'), _('REV')),
4651 ] + diffopts,
4653 ] + diffopts,
4652 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4654 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4653 "^forget":
4655 "^forget":
4654 (forget,
4656 (forget,
4655 [] + walkopts,
4657 [] + walkopts,
4656 _('[OPTION]... FILE...')),
4658 _('[OPTION]... FILE...')),
4657 "grep":
4659 "grep":
4658 (grep,
4660 (grep,
4659 [('0', 'print0', None, _('end fields with NUL')),
4661 [('0', 'print0', None, _('end fields with NUL')),
4660 ('', 'all', None, _('print all revisions that match')),
4662 ('', 'all', None, _('print all revisions that match')),
4661 ('a', 'text', None, _('treat all files as text')),
4663 ('a', 'text', None, _('treat all files as text')),
4662 ('f', 'follow', None,
4664 ('f', 'follow', None,
4663 _('follow changeset history,'
4665 _('follow changeset history,'
4664 ' or file history across copies and renames')),
4666 ' or file history across copies and renames')),
4665 ('i', 'ignore-case', None, _('ignore case when matching')),
4667 ('i', 'ignore-case', None, _('ignore case when matching')),
4666 ('l', 'files-with-matches', None,
4668 ('l', 'files-with-matches', None,
4667 _('print only filenames and revisions that match')),
4669 _('print only filenames and revisions that match')),
4668 ('n', 'line-number', None, _('print matching line numbers')),
4670 ('n', 'line-number', None, _('print matching line numbers')),
4669 ('r', 'rev', [],
4671 ('r', 'rev', [],
4670 _('only search files changed within revision range'), _('REV')),
4672 _('only search files changed within revision range'), _('REV')),
4671 ('u', 'user', None, _('list the author (long with -v)')),
4673 ('u', 'user', None, _('list the author (long with -v)')),
4672 ('d', 'date', None, _('list the date (short with -q)')),
4674 ('d', 'date', None, _('list the date (short with -q)')),
4673 ] + walkopts,
4675 ] + walkopts,
4674 _('[OPTION]... PATTERN [FILE]...')),
4676 _('[OPTION]... PATTERN [FILE]...')),
4675 "heads":
4677 "heads":
4676 (heads,
4678 (heads,
4677 [('r', 'rev', '',
4679 [('r', 'rev', '',
4678 _('show only heads which are descendants of STARTREV'),
4680 _('show only heads which are descendants of STARTREV'),
4679 _('STARTREV')),
4681 _('STARTREV')),
4680 ('t', 'topo', False, _('show topological heads only')),
4682 ('t', 'topo', False, _('show topological heads only')),
4681 ('a', 'active', False,
4683 ('a', 'active', False,
4682 _('show active branchheads only (DEPRECATED)')),
4684 _('show active branchheads only (DEPRECATED)')),
4683 ('c', 'closed', False,
4685 ('c', 'closed', False,
4684 _('show normal and closed branch heads')),
4686 _('show normal and closed branch heads')),
4685 ] + templateopts,
4687 ] + templateopts,
4686 _('[-ac] [-r STARTREV] [REV]...')),
4688 _('[-ac] [-r STARTREV] [REV]...')),
4687 "help": (help_, [], _('[TOPIC]')),
4689 "help": (help_, [], _('[TOPIC]')),
4688 "identify|id":
4690 "identify|id":
4689 (identify,
4691 (identify,
4690 [('r', 'rev', '',
4692 [('r', 'rev', '',
4691 _('identify the specified revision'), _('REV')),
4693 _('identify the specified revision'), _('REV')),
4692 ('n', 'num', None, _('show local revision number')),
4694 ('n', 'num', None, _('show local revision number')),
4693 ('i', 'id', None, _('show global revision id')),
4695 ('i', 'id', None, _('show global revision id')),
4694 ('b', 'branch', None, _('show branch')),
4696 ('b', 'branch', None, _('show branch')),
4695 ('t', 'tags', None, _('show tags')),
4697 ('t', 'tags', None, _('show tags')),
4696 ('B', 'bookmarks', None, _('show bookmarks'))],
4698 ('B', 'bookmarks', None, _('show bookmarks'))],
4697 _('[-nibtB] [-r REV] [SOURCE]')),
4699 _('[-nibtB] [-r REV] [SOURCE]')),
4698 "import|patch":
4700 "import|patch":
4699 (import_,
4701 (import_,
4700 [('p', 'strip', 1,
4702 [('p', 'strip', 1,
4701 _('directory strip option for patch. This has the same '
4703 _('directory strip option for patch. This has the same '
4702 'meaning as the corresponding patch option'),
4704 'meaning as the corresponding patch option'),
4703 _('NUM')),
4705 _('NUM')),
4704 ('b', 'base', '',
4706 ('b', 'base', '',
4705 _('base path'), _('PATH')),
4707 _('base path'), _('PATH')),
4706 ('f', 'force', None,
4708 ('f', 'force', None,
4707 _('skip check for outstanding uncommitted changes')),
4709 _('skip check for outstanding uncommitted changes')),
4708 ('', 'no-commit', None,
4710 ('', 'no-commit', None,
4709 _("don't commit, just update the working directory")),
4711 _("don't commit, just update the working directory")),
4710 ('', 'exact', None,
4712 ('', 'exact', None,
4711 _('apply patch to the nodes from which it was generated')),
4713 _('apply patch to the nodes from which it was generated')),
4712 ('', 'import-branch', None,
4714 ('', 'import-branch', None,
4713 _('use any branch information in patch (implied by --exact)'))] +
4715 _('use any branch information in patch (implied by --exact)'))] +
4714 commitopts + commitopts2 + similarityopts,
4716 commitopts + commitopts2 + similarityopts,
4715 _('[OPTION]... PATCH...')),
4717 _('[OPTION]... PATCH...')),
4716 "incoming|in":
4718 "incoming|in":
4717 (incoming,
4719 (incoming,
4718 [('f', 'force', None,
4720 [('f', 'force', None,
4719 _('run even if remote repository is unrelated')),
4721 _('run even if remote repository is unrelated')),
4720 ('n', 'newest-first', None, _('show newest record first')),
4722 ('n', 'newest-first', None, _('show newest record first')),
4721 ('', 'bundle', '',
4723 ('', 'bundle', '',
4722 _('file to store the bundles into'), _('FILE')),
4724 _('file to store the bundles into'), _('FILE')),
4723 ('r', 'rev', [],
4725 ('r', 'rev', [],
4724 _('a remote changeset intended to be added'), _('REV')),
4726 _('a remote changeset intended to be added'), _('REV')),
4725 ('B', 'bookmarks', False, _("compare bookmarks")),
4727 ('B', 'bookmarks', False, _("compare bookmarks")),
4726 ('b', 'branch', [],
4728 ('b', 'branch', [],
4727 _('a specific branch you would like to pull'), _('BRANCH')),
4729 _('a specific branch you would like to pull'), _('BRANCH')),
4728 ] + logopts + remoteopts + subrepoopts,
4730 ] + logopts + remoteopts + subrepoopts,
4729 _('[-p] [-n] [-M] [-f] [-r REV]...'
4731 _('[-p] [-n] [-M] [-f] [-r REV]...'
4730 ' [--bundle FILENAME] [SOURCE]')),
4732 ' [--bundle FILENAME] [SOURCE]')),
4731 "^init":
4733 "^init":
4732 (init,
4734 (init,
4733 remoteopts,
4735 remoteopts,
4734 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4736 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4735 "locate":
4737 "locate":
4736 (locate,
4738 (locate,
4737 [('r', 'rev', '',
4739 [('r', 'rev', '',
4738 _('search the repository as it is in REV'), _('REV')),
4740 _('search the repository as it is in REV'), _('REV')),
4739 ('0', 'print0', None,
4741 ('0', 'print0', None,
4740 _('end filenames with NUL, for use with xargs')),
4742 _('end filenames with NUL, for use with xargs')),
4741 ('f', 'fullpath', None,
4743 ('f', 'fullpath', None,
4742 _('print complete paths from the filesystem root')),
4744 _('print complete paths from the filesystem root')),
4743 ] + walkopts,
4745 ] + walkopts,
4744 _('[OPTION]... [PATTERN]...')),
4746 _('[OPTION]... [PATTERN]...')),
4745 "^log|history":
4747 "^log|history":
4746 (log,
4748 (log,
4747 [('f', 'follow', None,
4749 [('f', 'follow', None,
4748 _('follow changeset history,'
4750 _('follow changeset history,'
4749 ' or file history across copies and renames')),
4751 ' or file history across copies and renames')),
4750 ('', 'follow-first', None,
4752 ('', 'follow-first', None,
4751 _('only follow the first parent of merge changesets')),
4753 _('only follow the first parent of merge changesets')),
4752 ('d', 'date', '',
4754 ('d', 'date', '',
4753 _('show revisions matching date spec'), _('DATE')),
4755 _('show revisions matching date spec'), _('DATE')),
4754 ('C', 'copies', None, _('show copied files')),
4756 ('C', 'copies', None, _('show copied files')),
4755 ('k', 'keyword', [],
4757 ('k', 'keyword', [],
4756 _('do case-insensitive search for a given text'), _('TEXT')),
4758 _('do case-insensitive search for a given text'), _('TEXT')),
4757 ('r', 'rev', [],
4759 ('r', 'rev', [],
4758 _('show the specified revision or range'), _('REV')),
4760 _('show the specified revision or range'), _('REV')),
4759 ('', 'removed', None, _('include revisions where files were removed')),
4761 ('', 'removed', None, _('include revisions where files were removed')),
4760 ('m', 'only-merges', None, _('show only merges')),
4762 ('m', 'only-merges', None, _('show only merges')),
4761 ('u', 'user', [],
4763 ('u', 'user', [],
4762 _('revisions committed by user'), _('USER')),
4764 _('revisions committed by user'), _('USER')),
4763 ('', 'only-branch', [],
4765 ('', 'only-branch', [],
4764 _('show only changesets within the given named branch (DEPRECATED)'),
4766 _('show only changesets within the given named branch (DEPRECATED)'),
4765 _('BRANCH')),
4767 _('BRANCH')),
4766 ('b', 'branch', [],
4768 ('b', 'branch', [],
4767 _('show changesets within the given named branch'), _('BRANCH')),
4769 _('show changesets within the given named branch'), _('BRANCH')),
4768 ('P', 'prune', [],
4770 ('P', 'prune', [],
4769 _('do not display revision or any of its ancestors'), _('REV')),
4771 _('do not display revision or any of its ancestors'), _('REV')),
4770 ] + logopts + walkopts,
4772 ] + logopts + walkopts,
4771 _('[OPTION]... [FILE]')),
4773 _('[OPTION]... [FILE]')),
4772 "manifest":
4774 "manifest":
4773 (manifest,
4775 (manifest,
4774 [('r', 'rev', '',
4776 [('r', 'rev', '',
4775 _('revision to display'), _('REV'))],
4777 _('revision to display'), _('REV'))],
4776 _('[-r REV]')),
4778 _('[-r REV]')),
4777 "^merge":
4779 "^merge":
4778 (merge,
4780 (merge,
4779 [('f', 'force', None, _('force a merge with outstanding changes')),
4781 [('f', 'force', None, _('force a merge with outstanding changes')),
4780 ('t', 'tool', '', _('specify merge tool')),
4782 ('t', 'tool', '', _('specify merge tool')),
4781 ('r', 'rev', '',
4783 ('r', 'rev', '',
4782 _('revision to merge'), _('REV')),
4784 _('revision to merge'), _('REV')),
4783 ('P', 'preview', None,
4785 ('P', 'preview', None,
4784 _('review revisions to merge (no merge is performed)'))],
4786 _('review revisions to merge (no merge is performed)'))],
4785 _('[-P] [-f] [[-r] REV]')),
4787 _('[-P] [-f] [[-r] REV]')),
4786 "outgoing|out":
4788 "outgoing|out":
4787 (outgoing,
4789 (outgoing,
4788 [('f', 'force', None,
4790 [('f', 'force', None,
4789 _('run even when the destination is unrelated')),
4791 _('run even when the destination is unrelated')),
4790 ('r', 'rev', [],
4792 ('r', 'rev', [],
4791 _('a changeset intended to be included in the destination'),
4793 _('a changeset intended to be included in the destination'),
4792 _('REV')),
4794 _('REV')),
4793 ('n', 'newest-first', None, _('show newest record first')),
4795 ('n', 'newest-first', None, _('show newest record first')),
4794 ('B', 'bookmarks', False, _("compare bookmarks")),
4796 ('B', 'bookmarks', False, _("compare bookmarks")),
4795 ('b', 'branch', [],
4797 ('b', 'branch', [],
4796 _('a specific branch you would like to push'), _('BRANCH')),
4798 _('a specific branch you would like to push'), _('BRANCH')),
4797 ] + logopts + remoteopts + subrepoopts,
4799 ] + logopts + remoteopts + subrepoopts,
4798 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4800 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4799 "parents":
4801 "parents":
4800 (parents,
4802 (parents,
4801 [('r', 'rev', '',
4803 [('r', 'rev', '',
4802 _('show parents of the specified revision'), _('REV')),
4804 _('show parents of the specified revision'), _('REV')),
4803 ] + templateopts,
4805 ] + templateopts,
4804 _('[-r REV] [FILE]')),
4806 _('[-r REV] [FILE]')),
4805 "paths": (paths, [], _('[NAME]')),
4807 "paths": (paths, [], _('[NAME]')),
4806 "^pull":
4808 "^pull":
4807 (pull,
4809 (pull,
4808 [('u', 'update', None,
4810 [('u', 'update', None,
4809 _('update to new branch head if changesets were pulled')),
4811 _('update to new branch head if changesets were pulled')),
4810 ('f', 'force', None,
4812 ('f', 'force', None,
4811 _('run even when remote repository is unrelated')),
4813 _('run even when remote repository is unrelated')),
4812 ('r', 'rev', [],
4814 ('r', 'rev', [],
4813 _('a remote changeset intended to be added'), _('REV')),
4815 _('a remote changeset intended to be added'), _('REV')),
4814 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4816 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4815 ('b', 'branch', [],
4817 ('b', 'branch', [],
4816 _('a specific branch you would like to pull'), _('BRANCH')),
4818 _('a specific branch you would like to pull'), _('BRANCH')),
4817 ] + remoteopts,
4819 ] + remoteopts,
4818 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4820 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4819 "^push":
4821 "^push":
4820 (push,
4822 (push,
4821 [('f', 'force', None, _('force push')),
4823 [('f', 'force', None, _('force push')),
4822 ('r', 'rev', [],
4824 ('r', 'rev', [],
4823 _('a changeset intended to be included in the destination'),
4825 _('a changeset intended to be included in the destination'),
4824 _('REV')),
4826 _('REV')),
4825 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4827 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4826 ('b', 'branch', [],
4828 ('b', 'branch', [],
4827 _('a specific branch you would like to push'), _('BRANCH')),
4829 _('a specific branch you would like to push'), _('BRANCH')),
4828 ('', 'new-branch', False, _('allow pushing a new branch')),
4830 ('', 'new-branch', False, _('allow pushing a new branch')),
4829 ] + remoteopts,
4831 ] + remoteopts,
4830 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4832 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4831 "recover": (recover, []),
4833 "recover": (recover, []),
4832 "^remove|rm":
4834 "^remove|rm":
4833 (remove,
4835 (remove,
4834 [('A', 'after', None, _('record delete for missing files')),
4836 [('A', 'after', None, _('record delete for missing files')),
4835 ('f', 'force', None,
4837 ('f', 'force', None,
4836 _('remove (and delete) file even if added or modified')),
4838 _('remove (and delete) file even if added or modified')),
4837 ] + walkopts,
4839 ] + walkopts,
4838 _('[OPTION]... FILE...')),
4840 _('[OPTION]... FILE...')),
4839 "rename|move|mv":
4841 "rename|move|mv":
4840 (rename,
4842 (rename,
4841 [('A', 'after', None, _('record a rename that has already occurred')),
4843 [('A', 'after', None, _('record a rename that has already occurred')),
4842 ('f', 'force', None,
4844 ('f', 'force', None,
4843 _('forcibly copy over an existing managed file')),
4845 _('forcibly copy over an existing managed file')),
4844 ] + walkopts + dryrunopts,
4846 ] + walkopts + dryrunopts,
4845 _('[OPTION]... SOURCE... DEST')),
4847 _('[OPTION]... SOURCE... DEST')),
4846 "resolve":
4848 "resolve":
4847 (resolve,
4849 (resolve,
4848 [('a', 'all', None, _('select all unresolved files')),
4850 [('a', 'all', None, _('select all unresolved files')),
4849 ('l', 'list', None, _('list state of files needing merge')),
4851 ('l', 'list', None, _('list state of files needing merge')),
4850 ('m', 'mark', None, _('mark files as resolved')),
4852 ('m', 'mark', None, _('mark files as resolved')),
4851 ('u', 'unmark', None, _('mark files as unresolved')),
4853 ('u', 'unmark', None, _('mark files as unresolved')),
4852 ('t', 'tool', '', _('specify merge tool')),
4854 ('t', 'tool', '', _('specify merge tool')),
4853 ('n', 'no-status', None, _('hide status prefix'))]
4855 ('n', 'no-status', None, _('hide status prefix'))]
4854 + walkopts,
4856 + walkopts,
4855 _('[OPTION]... [FILE]...')),
4857 _('[OPTION]... [FILE]...')),
4856 "revert":
4858 "revert":
4857 (revert,
4859 (revert,
4858 [('a', 'all', None, _('revert all changes when no arguments given')),
4860 [('a', 'all', None, _('revert all changes when no arguments given')),
4859 ('d', 'date', '',
4861 ('d', 'date', '',
4860 _('tipmost revision matching date'), _('DATE')),
4862 _('tipmost revision matching date'), _('DATE')),
4861 ('r', 'rev', '',
4863 ('r', 'rev', '',
4862 _('revert to the specified revision'), _('REV')),
4864 _('revert to the specified revision'), _('REV')),
4863 ('', 'no-backup', None, _('do not save backup copies of files')),
4865 ('', 'no-backup', None, _('do not save backup copies of files')),
4864 ] + walkopts + dryrunopts,
4866 ] + walkopts + dryrunopts,
4865 _('[OPTION]... [-r REV] [NAME]...')),
4867 _('[OPTION]... [-r REV] [NAME]...')),
4866 "rollback": (rollback, dryrunopts),
4868 "rollback": (rollback, dryrunopts),
4867 "root": (root, []),
4869 "root": (root, []),
4868 "^serve":
4870 "^serve":
4869 (serve,
4871 (serve,
4870 [('A', 'accesslog', '',
4872 [('A', 'accesslog', '',
4871 _('name of access log file to write to'), _('FILE')),
4873 _('name of access log file to write to'), _('FILE')),
4872 ('d', 'daemon', None, _('run server in background')),
4874 ('d', 'daemon', None, _('run server in background')),
4873 ('', 'daemon-pipefds', '',
4875 ('', 'daemon-pipefds', '',
4874 _('used internally by daemon mode'), _('NUM')),
4876 _('used internally by daemon mode'), _('NUM')),
4875 ('E', 'errorlog', '',
4877 ('E', 'errorlog', '',
4876 _('name of error log file to write to'), _('FILE')),
4878 _('name of error log file to write to'), _('FILE')),
4877 # use string type, then we can check if something was passed
4879 # use string type, then we can check if something was passed
4878 ('p', 'port', '',
4880 ('p', 'port', '',
4879 _('port to listen on (default: 8000)'), _('PORT')),
4881 _('port to listen on (default: 8000)'), _('PORT')),
4880 ('a', 'address', '',
4882 ('a', 'address', '',
4881 _('address to listen on (default: all interfaces)'), _('ADDR')),
4883 _('address to listen on (default: all interfaces)'), _('ADDR')),
4882 ('', 'prefix', '',
4884 ('', 'prefix', '',
4883 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4885 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4884 ('n', 'name', '',
4886 ('n', 'name', '',
4885 _('name to show in web pages (default: working directory)'),
4887 _('name to show in web pages (default: working directory)'),
4886 _('NAME')),
4888 _('NAME')),
4887 ('', 'web-conf', '',
4889 ('', 'web-conf', '',
4888 _('name of the hgweb config file (see "hg help hgweb")'),
4890 _('name of the hgweb config file (see "hg help hgweb")'),
4889 _('FILE')),
4891 _('FILE')),
4890 ('', 'webdir-conf', '',
4892 ('', 'webdir-conf', '',
4891 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4893 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4892 ('', 'pid-file', '',
4894 ('', 'pid-file', '',
4893 _('name of file to write process ID to'), _('FILE')),
4895 _('name of file to write process ID to'), _('FILE')),
4894 ('', 'stdio', None, _('for remote clients')),
4896 ('', 'stdio', None, _('for remote clients')),
4895 ('t', 'templates', '',
4897 ('t', 'templates', '',
4896 _('web templates to use'), _('TEMPLATE')),
4898 _('web templates to use'), _('TEMPLATE')),
4897 ('', 'style', '',
4899 ('', 'style', '',
4898 _('template style to use'), _('STYLE')),
4900 _('template style to use'), _('STYLE')),
4899 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4901 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4900 ('', 'certificate', '',
4902 ('', 'certificate', '',
4901 _('SSL certificate file'), _('FILE'))],
4903 _('SSL certificate file'), _('FILE'))],
4902 _('[OPTION]...')),
4904 _('[OPTION]...')),
4903 "showconfig|debugconfig":
4905 "showconfig|debugconfig":
4904 (showconfig,
4906 (showconfig,
4905 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4907 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4906 _('[-u] [NAME]...')),
4908 _('[-u] [NAME]...')),
4907 "^summary|sum":
4909 "^summary|sum":
4908 (summary,
4910 (summary,
4909 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4911 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4910 "^status|st":
4912 "^status|st":
4911 (status,
4913 (status,
4912 [('A', 'all', None, _('show status of all files')),
4914 [('A', 'all', None, _('show status of all files')),
4913 ('m', 'modified', None, _('show only modified files')),
4915 ('m', 'modified', None, _('show only modified files')),
4914 ('a', 'added', None, _('show only added files')),
4916 ('a', 'added', None, _('show only added files')),
4915 ('r', 'removed', None, _('show only removed files')),
4917 ('r', 'removed', None, _('show only removed files')),
4916 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4918 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4917 ('c', 'clean', None, _('show only files without changes')),
4919 ('c', 'clean', None, _('show only files without changes')),
4918 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4920 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4919 ('i', 'ignored', None, _('show only ignored files')),
4921 ('i', 'ignored', None, _('show only ignored files')),
4920 ('n', 'no-status', None, _('hide status prefix')),
4922 ('n', 'no-status', None, _('hide status prefix')),
4921 ('C', 'copies', None, _('show source of copied files')),
4923 ('C', 'copies', None, _('show source of copied files')),
4922 ('0', 'print0', None,
4924 ('0', 'print0', None,
4923 _('end filenames with NUL, for use with xargs')),
4925 _('end filenames with NUL, for use with xargs')),
4924 ('', 'rev', [],
4926 ('', 'rev', [],
4925 _('show difference from revision'), _('REV')),
4927 _('show difference from revision'), _('REV')),
4926 ('', 'change', '',
4928 ('', 'change', '',
4927 _('list the changed files of a revision'), _('REV')),
4929 _('list the changed files of a revision'), _('REV')),
4928 ] + walkopts + subrepoopts,
4930 ] + walkopts + subrepoopts,
4929 _('[OPTION]... [FILE]...')),
4931 _('[OPTION]... [FILE]...')),
4930 "tag":
4932 "tag":
4931 (tag,
4933 (tag,
4932 [('f', 'force', None, _('force tag')),
4934 [('f', 'force', None, _('force tag')),
4933 ('l', 'local', None, _('make the tag local')),
4935 ('l', 'local', None, _('make the tag local')),
4934 ('r', 'rev', '',
4936 ('r', 'rev', '',
4935 _('revision to tag'), _('REV')),
4937 _('revision to tag'), _('REV')),
4936 ('', 'remove', None, _('remove a tag')),
4938 ('', 'remove', None, _('remove a tag')),
4937 # -l/--local is already there, commitopts cannot be used
4939 # -l/--local is already there, commitopts cannot be used
4938 ('e', 'edit', None, _('edit commit message')),
4940 ('e', 'edit', None, _('edit commit message')),
4939 ('m', 'message', '',
4941 ('m', 'message', '',
4940 _('use <text> as commit message'), _('TEXT')),
4942 _('use <text> as commit message'), _('TEXT')),
4941 ] + commitopts2,
4943 ] + commitopts2,
4942 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4944 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4943 "tags": (tags, [], ''),
4945 "tags": (tags, [], ''),
4944 "tip":
4946 "tip":
4945 (tip,
4947 (tip,
4946 [('p', 'patch', None, _('show patch')),
4948 [('p', 'patch', None, _('show patch')),
4947 ('g', 'git', None, _('use git extended diff format')),
4949 ('g', 'git', None, _('use git extended diff format')),
4948 ] + templateopts,
4950 ] + templateopts,
4949 _('[-p] [-g]')),
4951 _('[-p] [-g]')),
4950 "unbundle":
4952 "unbundle":
4951 (unbundle,
4953 (unbundle,
4952 [('u', 'update', None,
4954 [('u', 'update', None,
4953 _('update to new branch head if changesets were unbundled'))],
4955 _('update to new branch head if changesets were unbundled'))],
4954 _('[-u] FILE...')),
4956 _('[-u] FILE...')),
4955 "^update|up|checkout|co":
4957 "^update|up|checkout|co":
4956 (update,
4958 (update,
4957 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4959 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4958 ('c', 'check', None,
4960 ('c', 'check', None,
4959 _('update across branches if no uncommitted changes')),
4961 _('update across branches if no uncommitted changes')),
4960 ('d', 'date', '',
4962 ('d', 'date', '',
4961 _('tipmost revision matching date'), _('DATE')),
4963 _('tipmost revision matching date'), _('DATE')),
4962 ('r', 'rev', '',
4964 ('r', 'rev', '',
4963 _('revision'), _('REV'))],
4965 _('revision'), _('REV'))],
4964 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4966 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4965 "verify": (verify, []),
4967 "verify": (verify, []),
4966 "version": (version_, []),
4968 "version": (version_, []),
4967 }
4969 }
4968
4970
4969 norepo = ("clone init version help debugcommands debugcomplete"
4971 norepo = ("clone init version help debugcommands debugcomplete"
4970 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4972 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4971 " debugknown debuggetbundle debugbundle")
4973 " debugknown debuggetbundle debugbundle")
4972 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4974 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4973 " debugdata debugindex debugindexdot")
4975 " debugdata debugindex debugindexdot")
@@ -1,169 +1,190 b''
1 # discovery.py - protocol changeset discovery functions
1 # discovery.py - protocol changeset discovery functions
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 from node import nullid, short
8 from node import nullid, short
9 from i18n import _
9 from i18n import _
10 import util, setdiscovery, treediscovery
10 import util, setdiscovery, treediscovery
11
11
12 def findcommonincoming(repo, remote, heads=None, force=False):
12 def findcommonincoming(repo, remote, heads=None, force=False):
13 """Return a tuple (common, anyincoming, heads) used to identify the common
13 """Return a tuple (common, anyincoming, heads) used to identify the common
14 subset of nodes between repo and remote.
14 subset of nodes between repo and remote.
15
15
16 "common" is a list of (at least) the heads of the common subset.
16 "common" is a list of (at least) the heads of the common subset.
17 "anyincoming" is testable as a boolean indicating if any nodes are missing
17 "anyincoming" is testable as a boolean indicating if any nodes are missing
18 locally. If remote does not support getbundle, this actually is a list of
18 locally. If remote does not support getbundle, this actually is a list of
19 roots of the nodes that would be incoming, to be supplied to
19 roots of the nodes that would be incoming, to be supplied to
20 changegroupsubset. No code except for pull should be relying on this fact
20 changegroupsubset. No code except for pull should be relying on this fact
21 any longer.
21 any longer.
22 "heads" is either the supplied heads, or else the remote's heads.
22 "heads" is either the supplied heads, or else the remote's heads.
23
23
24 If you pass heads and they are all known locally, the reponse lists justs
24 If you pass heads and they are all known locally, the reponse lists justs
25 these heads in "common" and in "heads".
25 these heads in "common" and in "heads".
26
27 Please use findcommonoutgoing to compute the set of outgoing nodes to give
28 extensions a good hook into outgoing.
26 """
29 """
27
30
28 if not remote.capable('getbundle'):
31 if not remote.capable('getbundle'):
29 return treediscovery.findcommonincoming(repo, remote, heads, force)
32 return treediscovery.findcommonincoming(repo, remote, heads, force)
30
33
31 if heads:
34 if heads:
32 allknown = True
35 allknown = True
33 nm = repo.changelog.nodemap
36 nm = repo.changelog.nodemap
34 for h in heads:
37 for h in heads:
35 if nm.get(h) is None:
38 if nm.get(h) is None:
36 allknown = False
39 allknown = False
37 break
40 break
38 if allknown:
41 if allknown:
39 return (heads, False, heads)
42 return (heads, False, heads)
40
43
41 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
44 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
42 abortwhenunrelated=not force)
45 abortwhenunrelated=not force)
43 common, anyinc, srvheads = res
46 common, anyinc, srvheads = res
44 return (list(common), anyinc, heads or list(srvheads))
47 return (list(common), anyinc, heads or list(srvheads))
45
48
49 def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
50 '''Return a tuple (common, anyoutgoing, heads) used to identify the set
51 of nodes present in repo but not in other.
52
53 If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
54 are included. If you already know the local repo's heads, passing them in
55 onlyheads is faster than letting them be recomputed here.
56
57 If commoninc is given, it must the the result of a prior call to
58 findcommonincoming(repo, other, force) to avoid recomputing it here.
59
60 The returned tuple is meant to be passed to changelog.findmissing.'''
61 common, _any, _hds = commoninc or findcommonincoming(repo, other, force=force)
62 return (common, onlyheads or repo.heads())
63
46 def prepush(repo, remote, force, revs, newbranch):
64 def prepush(repo, remote, force, revs, newbranch):
47 '''Analyze the local and remote repositories and determine which
65 '''Analyze the local and remote repositories and determine which
48 changesets need to be pushed to the remote. Return value depends
66 changesets need to be pushed to the remote. Return value depends
49 on circumstances:
67 on circumstances:
50
68
51 If we are not going to push anything, return a tuple (None,
69 If we are not going to push anything, return a tuple (None,
52 outgoing) where outgoing is 0 if there are no outgoing
70 outgoing) where outgoing is 0 if there are no outgoing
53 changesets and 1 if there are, but we refuse to push them
71 changesets and 1 if there are, but we refuse to push them
54 (e.g. would create new remote heads).
72 (e.g. would create new remote heads).
55
73
56 Otherwise, return a tuple (changegroup, remoteheads), where
74 Otherwise, return a tuple (changegroup, remoteheads), where
57 changegroup is a readable file-like object whose read() returns
75 changegroup is a readable file-like object whose read() returns
58 successive changegroup chunks ready to be sent over the wire and
76 successive changegroup chunks ready to be sent over the wire and
59 remoteheads is the list of remote heads.'''
77 remoteheads is the list of remote heads.'''
60 common, inc, remoteheads = findcommonincoming(repo, remote, force=force)
78 commoninc = findcommonincoming(repo, remote, force=force)
79 common, revs = findcommonoutgoing(repo, remote, onlyheads=revs,
80 commoninc=commoninc, force=force)
81 _common, inc, remoteheads = commoninc
61
82
62 cl = repo.changelog
83 cl = repo.changelog
63 outg = cl.findmissing(common, revs)
84 outg = cl.findmissing(common, revs)
64
85
65 if not outg:
86 if not outg:
66 repo.ui.status(_("no changes found\n"))
87 repo.ui.status(_("no changes found\n"))
67 return None, 1
88 return None, 1
68
89
69 if not force and remoteheads != [nullid]:
90 if not force and remoteheads != [nullid]:
70 if remote.capable('branchmap'):
91 if remote.capable('branchmap'):
71 # Check for each named branch if we're creating new remote heads.
92 # Check for each named branch if we're creating new remote heads.
72 # To be a remote head after push, node must be either:
93 # To be a remote head after push, node must be either:
73 # - unknown locally
94 # - unknown locally
74 # - a local outgoing head descended from update
95 # - a local outgoing head descended from update
75 # - a remote head that's known locally and not
96 # - a remote head that's known locally and not
76 # ancestral to an outgoing head
97 # ancestral to an outgoing head
77
98
78 # 1. Create set of branches involved in the push.
99 # 1. Create set of branches involved in the push.
79 branches = set(repo[n].branch() for n in outg)
100 branches = set(repo[n].branch() for n in outg)
80
101
81 # 2. Check for new branches on the remote.
102 # 2. Check for new branches on the remote.
82 remotemap = remote.branchmap()
103 remotemap = remote.branchmap()
83 newbranches = branches - set(remotemap)
104 newbranches = branches - set(remotemap)
84 if newbranches and not newbranch: # new branch requires --new-branch
105 if newbranches and not newbranch: # new branch requires --new-branch
85 branchnames = ', '.join(sorted(newbranches))
106 branchnames = ', '.join(sorted(newbranches))
86 raise util.Abort(_("push creates new remote branches: %s!")
107 raise util.Abort(_("push creates new remote branches: %s!")
87 % branchnames,
108 % branchnames,
88 hint=_("use 'hg push --new-branch' to create"
109 hint=_("use 'hg push --new-branch' to create"
89 " new remote branches"))
110 " new remote branches"))
90 branches.difference_update(newbranches)
111 branches.difference_update(newbranches)
91
112
92 # 3. Construct the initial oldmap and newmap dicts.
113 # 3. Construct the initial oldmap and newmap dicts.
93 # They contain information about the remote heads before and
114 # They contain information about the remote heads before and
94 # after the push, respectively.
115 # after the push, respectively.
95 # Heads not found locally are not included in either dict,
116 # Heads not found locally are not included in either dict,
96 # since they won't be affected by the push.
117 # since they won't be affected by the push.
97 # unsynced contains all branches with incoming changesets.
118 # unsynced contains all branches with incoming changesets.
98 oldmap = {}
119 oldmap = {}
99 newmap = {}
120 newmap = {}
100 unsynced = set()
121 unsynced = set()
101 for branch in branches:
122 for branch in branches:
102 remotebrheads = remotemap[branch]
123 remotebrheads = remotemap[branch]
103 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
124 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
104 oldmap[branch] = prunedbrheads
125 oldmap[branch] = prunedbrheads
105 newmap[branch] = list(prunedbrheads)
126 newmap[branch] = list(prunedbrheads)
106 if len(remotebrheads) > len(prunedbrheads):
127 if len(remotebrheads) > len(prunedbrheads):
107 unsynced.add(branch)
128 unsynced.add(branch)
108
129
109 # 4. Update newmap with outgoing changes.
130 # 4. Update newmap with outgoing changes.
110 # This will possibly add new heads and remove existing ones.
131 # This will possibly add new heads and remove existing ones.
111 ctxgen = (repo[n] for n in outg)
132 ctxgen = (repo[n] for n in outg)
112 repo._updatebranchcache(newmap, ctxgen)
133 repo._updatebranchcache(newmap, ctxgen)
113
134
114 else:
135 else:
115 # 1-4b. old servers: Check for new topological heads.
136 # 1-4b. old servers: Check for new topological heads.
116 # Construct {old,new}map with branch = None (topological branch).
137 # Construct {old,new}map with branch = None (topological branch).
117 # (code based on _updatebranchcache)
138 # (code based on _updatebranchcache)
118 oldheads = set(h for h in remoteheads if h in cl.nodemap)
139 oldheads = set(h for h in remoteheads if h in cl.nodemap)
119 newheads = oldheads.union(outg)
140 newheads = oldheads.union(outg)
120 if len(newheads) > 1:
141 if len(newheads) > 1:
121 for latest in reversed(outg):
142 for latest in reversed(outg):
122 if latest not in newheads:
143 if latest not in newheads:
123 continue
144 continue
124 minhrev = min(cl.rev(h) for h in newheads)
145 minhrev = min(cl.rev(h) for h in newheads)
125 reachable = cl.reachable(latest, cl.node(minhrev))
146 reachable = cl.reachable(latest, cl.node(minhrev))
126 reachable.remove(latest)
147 reachable.remove(latest)
127 newheads.difference_update(reachable)
148 newheads.difference_update(reachable)
128 branches = set([None])
149 branches = set([None])
129 newmap = {None: newheads}
150 newmap = {None: newheads}
130 oldmap = {None: oldheads}
151 oldmap = {None: oldheads}
131 unsynced = inc and branches or set()
152 unsynced = inc and branches or set()
132
153
133 # 5. Check for new heads.
154 # 5. Check for new heads.
134 # If there are more heads after the push than before, a suitable
155 # If there are more heads after the push than before, a suitable
135 # error message, depending on unsynced status, is displayed.
156 # error message, depending on unsynced status, is displayed.
136 error = None
157 error = None
137 for branch in branches:
158 for branch in branches:
138 newhs = set(newmap[branch])
159 newhs = set(newmap[branch])
139 oldhs = set(oldmap[branch])
160 oldhs = set(oldmap[branch])
140 if len(newhs) > len(oldhs):
161 if len(newhs) > len(oldhs):
141 if error is None:
162 if error is None:
142 if branch:
163 if branch:
143 error = _("push creates new remote heads "
164 error = _("push creates new remote heads "
144 "on branch '%s'!") % branch
165 "on branch '%s'!") % branch
145 else:
166 else:
146 error = _("push creates new remote heads!")
167 error = _("push creates new remote heads!")
147 if branch in unsynced:
168 if branch in unsynced:
148 hint = _("you should pull and merge or "
169 hint = _("you should pull and merge or "
149 "use push -f to force")
170 "use push -f to force")
150 else:
171 else:
151 hint = _("did you forget to merge? "
172 hint = _("did you forget to merge? "
152 "use push -f to force")
173 "use push -f to force")
153 if branch:
174 if branch:
154 repo.ui.debug("new remote heads on branch '%s'\n" % branch)
175 repo.ui.debug("new remote heads on branch '%s'\n" % branch)
155 for h in (newhs - oldhs):
176 for h in (newhs - oldhs):
156 repo.ui.debug("new remote head %s\n" % short(h))
177 repo.ui.debug("new remote head %s\n" % short(h))
157 if error:
178 if error:
158 raise util.Abort(error, hint=hint)
179 raise util.Abort(error, hint=hint)
159
180
160 # 6. Check for unsynced changes on involved branches.
181 # 6. Check for unsynced changes on involved branches.
161 if unsynced:
182 if unsynced:
162 repo.ui.warn(_("note: unsynced remote changes!\n"))
183 repo.ui.warn(_("note: unsynced remote changes!\n"))
163
184
164 if revs is None:
185 if revs is None:
165 # use the fast path, no race possible on push
186 # use the fast path, no race possible on push
166 cg = repo._changegroup(outg, 'push')
187 cg = repo._changegroup(outg, 'push')
167 else:
188 else:
168 cg = repo.getbundle('push', heads=revs, common=common)
189 cg = repo.getbundle('push', heads=revs, common=common)
169 return cg, remoteheads
190 return cg, remoteheads
@@ -1,557 +1,557 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid
11 from node import hex, nullid
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, bookmarks
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, bookmarks
13 import lock, util, extensions, error, node
13 import lock, util, extensions, error, node
14 import cmdutil, discovery
14 import cmdutil, discovery
15 import merge as mergemod
15 import merge as mergemod
16 import verify as verifymod
16 import verify as verifymod
17 import errno, os, shutil
17 import errno, os, shutil
18
18
19 def _local(path):
19 def _local(path):
20 path = util.expandpath(util.localpath(path))
20 path = util.expandpath(util.localpath(path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
21 return (os.path.isfile(path) and bundlerepo or localrepo)
22
22
23 def addbranchrevs(lrepo, repo, branches, revs):
23 def addbranchrevs(lrepo, repo, branches, revs):
24 hashbranch, branches = branches
24 hashbranch, branches = branches
25 if not hashbranch and not branches:
25 if not hashbranch and not branches:
26 return revs or None, revs and revs[0] or None
26 return revs or None, revs and revs[0] or None
27 revs = revs and list(revs) or []
27 revs = revs and list(revs) or []
28 if not repo.capable('branchmap'):
28 if not repo.capable('branchmap'):
29 if branches:
29 if branches:
30 raise util.Abort(_("remote branch lookup not supported"))
30 raise util.Abort(_("remote branch lookup not supported"))
31 revs.append(hashbranch)
31 revs.append(hashbranch)
32 return revs, revs[0]
32 return revs, revs[0]
33 branchmap = repo.branchmap()
33 branchmap = repo.branchmap()
34
34
35 def primary(branch):
35 def primary(branch):
36 if branch == '.':
36 if branch == '.':
37 if not lrepo or not lrepo.local():
37 if not lrepo or not lrepo.local():
38 raise util.Abort(_("dirstate branch not accessible"))
38 raise util.Abort(_("dirstate branch not accessible"))
39 branch = lrepo.dirstate.branch()
39 branch = lrepo.dirstate.branch()
40 if branch in branchmap:
40 if branch in branchmap:
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 return True
42 return True
43 else:
43 else:
44 return False
44 return False
45
45
46 for branch in branches:
46 for branch in branches:
47 if not primary(branch):
47 if not primary(branch):
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 if hashbranch:
49 if hashbranch:
50 if not primary(hashbranch):
50 if not primary(hashbranch):
51 revs.append(hashbranch)
51 revs.append(hashbranch)
52 return revs, revs[0]
52 return revs, revs[0]
53
53
54 def parseurl(path, branches=None):
54 def parseurl(path, branches=None):
55 '''parse url#branch, returning (url, (branch, branches))'''
55 '''parse url#branch, returning (url, (branch, branches))'''
56
56
57 u = util.url(path)
57 u = util.url(path)
58 branch = None
58 branch = None
59 if u.fragment:
59 if u.fragment:
60 branch = u.fragment
60 branch = u.fragment
61 u.fragment = None
61 u.fragment = None
62 return str(u), (branch, branches or [])
62 return str(u), (branch, branches or [])
63
63
64 schemes = {
64 schemes = {
65 'bundle': bundlerepo,
65 'bundle': bundlerepo,
66 'file': _local,
66 'file': _local,
67 'http': httprepo,
67 'http': httprepo,
68 'https': httprepo,
68 'https': httprepo,
69 'ssh': sshrepo,
69 'ssh': sshrepo,
70 'static-http': statichttprepo,
70 'static-http': statichttprepo,
71 }
71 }
72
72
73 def _lookup(path):
73 def _lookup(path):
74 u = util.url(path)
74 u = util.url(path)
75 scheme = u.scheme or 'file'
75 scheme = u.scheme or 'file'
76 thing = schemes.get(scheme) or schemes['file']
76 thing = schemes.get(scheme) or schemes['file']
77 try:
77 try:
78 return thing(path)
78 return thing(path)
79 except TypeError:
79 except TypeError:
80 return thing
80 return thing
81
81
82 def islocal(repo):
82 def islocal(repo):
83 '''return true if repo or path is local'''
83 '''return true if repo or path is local'''
84 if isinstance(repo, str):
84 if isinstance(repo, str):
85 try:
85 try:
86 return _lookup(repo).islocal(repo)
86 return _lookup(repo).islocal(repo)
87 except AttributeError:
87 except AttributeError:
88 return False
88 return False
89 return repo.local()
89 return repo.local()
90
90
91 def repository(ui, path='', create=False):
91 def repository(ui, path='', create=False):
92 """return a repository object for the specified path"""
92 """return a repository object for the specified path"""
93 repo = _lookup(path).instance(ui, path, create)
93 repo = _lookup(path).instance(ui, path, create)
94 ui = getattr(repo, "ui", ui)
94 ui = getattr(repo, "ui", ui)
95 for name, module in extensions.extensions():
95 for name, module in extensions.extensions():
96 hook = getattr(module, 'reposetup', None)
96 hook = getattr(module, 'reposetup', None)
97 if hook:
97 if hook:
98 hook(ui, repo)
98 hook(ui, repo)
99 return repo
99 return repo
100
100
101 def defaultdest(source):
101 def defaultdest(source):
102 '''return default destination of clone if none is given'''
102 '''return default destination of clone if none is given'''
103 return os.path.basename(os.path.normpath(source))
103 return os.path.basename(os.path.normpath(source))
104
104
105 def share(ui, source, dest=None, update=True):
105 def share(ui, source, dest=None, update=True):
106 '''create a shared repository'''
106 '''create a shared repository'''
107
107
108 if not islocal(source):
108 if not islocal(source):
109 raise util.Abort(_('can only share local repositories'))
109 raise util.Abort(_('can only share local repositories'))
110
110
111 if not dest:
111 if not dest:
112 dest = defaultdest(source)
112 dest = defaultdest(source)
113 else:
113 else:
114 dest = ui.expandpath(dest)
114 dest = ui.expandpath(dest)
115
115
116 if isinstance(source, str):
116 if isinstance(source, str):
117 origsource = ui.expandpath(source)
117 origsource = ui.expandpath(source)
118 source, branches = parseurl(origsource)
118 source, branches = parseurl(origsource)
119 srcrepo = repository(ui, source)
119 srcrepo = repository(ui, source)
120 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
120 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
121 else:
121 else:
122 srcrepo = source
122 srcrepo = source
123 origsource = source = srcrepo.url()
123 origsource = source = srcrepo.url()
124 checkout = None
124 checkout = None
125
125
126 sharedpath = srcrepo.sharedpath # if our source is already sharing
126 sharedpath = srcrepo.sharedpath # if our source is already sharing
127
127
128 root = os.path.realpath(dest)
128 root = os.path.realpath(dest)
129 roothg = os.path.join(root, '.hg')
129 roothg = os.path.join(root, '.hg')
130
130
131 if os.path.exists(roothg):
131 if os.path.exists(roothg):
132 raise util.Abort(_('destination already exists'))
132 raise util.Abort(_('destination already exists'))
133
133
134 if not os.path.isdir(root):
134 if not os.path.isdir(root):
135 os.mkdir(root)
135 os.mkdir(root)
136 util.makedir(roothg, notindexed=True)
136 util.makedir(roothg, notindexed=True)
137
137
138 requirements = ''
138 requirements = ''
139 try:
139 try:
140 requirements = srcrepo.opener.read('requires')
140 requirements = srcrepo.opener.read('requires')
141 except IOError, inst:
141 except IOError, inst:
142 if inst.errno != errno.ENOENT:
142 if inst.errno != errno.ENOENT:
143 raise
143 raise
144
144
145 requirements += 'shared\n'
145 requirements += 'shared\n'
146 util.writefile(os.path.join(roothg, 'requires'), requirements)
146 util.writefile(os.path.join(roothg, 'requires'), requirements)
147 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
147 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
148
148
149 r = repository(ui, root)
149 r = repository(ui, root)
150
150
151 default = srcrepo.ui.config('paths', 'default')
151 default = srcrepo.ui.config('paths', 'default')
152 if default:
152 if default:
153 fp = r.opener("hgrc", "w", text=True)
153 fp = r.opener("hgrc", "w", text=True)
154 fp.write("[paths]\n")
154 fp.write("[paths]\n")
155 fp.write("default = %s\n" % default)
155 fp.write("default = %s\n" % default)
156 fp.close()
156 fp.close()
157
157
158 if update:
158 if update:
159 r.ui.status(_("updating working directory\n"))
159 r.ui.status(_("updating working directory\n"))
160 if update is not True:
160 if update is not True:
161 checkout = update
161 checkout = update
162 for test in (checkout, 'default', 'tip'):
162 for test in (checkout, 'default', 'tip'):
163 if test is None:
163 if test is None:
164 continue
164 continue
165 try:
165 try:
166 uprev = r.lookup(test)
166 uprev = r.lookup(test)
167 break
167 break
168 except error.RepoLookupError:
168 except error.RepoLookupError:
169 continue
169 continue
170 _update(r, uprev)
170 _update(r, uprev)
171
171
172 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
172 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
173 stream=False, branch=None):
173 stream=False, branch=None):
174 """Make a copy of an existing repository.
174 """Make a copy of an existing repository.
175
175
176 Create a copy of an existing repository in a new directory. The
176 Create a copy of an existing repository in a new directory. The
177 source and destination are URLs, as passed to the repository
177 source and destination are URLs, as passed to the repository
178 function. Returns a pair of repository objects, the source and
178 function. Returns a pair of repository objects, the source and
179 newly created destination.
179 newly created destination.
180
180
181 The location of the source is added to the new repository's
181 The location of the source is added to the new repository's
182 .hg/hgrc file, as the default to be used for future pulls and
182 .hg/hgrc file, as the default to be used for future pulls and
183 pushes.
183 pushes.
184
184
185 If an exception is raised, the partly cloned/updated destination
185 If an exception is raised, the partly cloned/updated destination
186 repository will be deleted.
186 repository will be deleted.
187
187
188 Arguments:
188 Arguments:
189
189
190 source: repository object or URL
190 source: repository object or URL
191
191
192 dest: URL of destination repository to create (defaults to base
192 dest: URL of destination repository to create (defaults to base
193 name of source repository)
193 name of source repository)
194
194
195 pull: always pull from source repository, even in local case
195 pull: always pull from source repository, even in local case
196
196
197 stream: stream raw data uncompressed from repository (fast over
197 stream: stream raw data uncompressed from repository (fast over
198 LAN, slow over WAN)
198 LAN, slow over WAN)
199
199
200 rev: revision to clone up to (implies pull=True)
200 rev: revision to clone up to (implies pull=True)
201
201
202 update: update working directory after clone completes, if
202 update: update working directory after clone completes, if
203 destination is local repository (True means update to default rev,
203 destination is local repository (True means update to default rev,
204 anything else is treated as a revision)
204 anything else is treated as a revision)
205
205
206 branch: branches to clone
206 branch: branches to clone
207 """
207 """
208
208
209 if isinstance(source, str):
209 if isinstance(source, str):
210 origsource = ui.expandpath(source)
210 origsource = ui.expandpath(source)
211 source, branch = parseurl(origsource, branch)
211 source, branch = parseurl(origsource, branch)
212 src_repo = repository(ui, source)
212 src_repo = repository(ui, source)
213 else:
213 else:
214 src_repo = source
214 src_repo = source
215 branch = (None, branch or [])
215 branch = (None, branch or [])
216 origsource = source = src_repo.url()
216 origsource = source = src_repo.url()
217 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
217 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
218
218
219 if dest is None:
219 if dest is None:
220 dest = defaultdest(source)
220 dest = defaultdest(source)
221 ui.status(_("destination directory: %s\n") % dest)
221 ui.status(_("destination directory: %s\n") % dest)
222 else:
222 else:
223 dest = ui.expandpath(dest)
223 dest = ui.expandpath(dest)
224
224
225 dest = util.localpath(dest)
225 dest = util.localpath(dest)
226 source = util.localpath(source)
226 source = util.localpath(source)
227
227
228 if os.path.exists(dest):
228 if os.path.exists(dest):
229 if not os.path.isdir(dest):
229 if not os.path.isdir(dest):
230 raise util.Abort(_("destination '%s' already exists") % dest)
230 raise util.Abort(_("destination '%s' already exists") % dest)
231 elif os.listdir(dest):
231 elif os.listdir(dest):
232 raise util.Abort(_("destination '%s' is not empty") % dest)
232 raise util.Abort(_("destination '%s' is not empty") % dest)
233
233
234 class DirCleanup(object):
234 class DirCleanup(object):
235 def __init__(self, dir_):
235 def __init__(self, dir_):
236 self.rmtree = shutil.rmtree
236 self.rmtree = shutil.rmtree
237 self.dir_ = dir_
237 self.dir_ = dir_
238 def close(self):
238 def close(self):
239 self.dir_ = None
239 self.dir_ = None
240 def cleanup(self):
240 def cleanup(self):
241 if self.dir_:
241 if self.dir_:
242 self.rmtree(self.dir_, True)
242 self.rmtree(self.dir_, True)
243
243
244 src_lock = dest_lock = dir_cleanup = None
244 src_lock = dest_lock = dir_cleanup = None
245 try:
245 try:
246 if islocal(dest):
246 if islocal(dest):
247 dir_cleanup = DirCleanup(dest)
247 dir_cleanup = DirCleanup(dest)
248
248
249 abspath = origsource
249 abspath = origsource
250 copy = False
250 copy = False
251 if src_repo.cancopy() and islocal(dest):
251 if src_repo.cancopy() and islocal(dest):
252 abspath = os.path.abspath(util.localpath(origsource))
252 abspath = os.path.abspath(util.localpath(origsource))
253 copy = not pull and not rev
253 copy = not pull and not rev
254
254
255 if copy:
255 if copy:
256 try:
256 try:
257 # we use a lock here because if we race with commit, we
257 # we use a lock here because if we race with commit, we
258 # can end up with extra data in the cloned revlogs that's
258 # can end up with extra data in the cloned revlogs that's
259 # not pointed to by changesets, thus causing verify to
259 # not pointed to by changesets, thus causing verify to
260 # fail
260 # fail
261 src_lock = src_repo.lock(wait=False)
261 src_lock = src_repo.lock(wait=False)
262 except error.LockError:
262 except error.LockError:
263 copy = False
263 copy = False
264
264
265 if copy:
265 if copy:
266 src_repo.hook('preoutgoing', throw=True, source='clone')
266 src_repo.hook('preoutgoing', throw=True, source='clone')
267 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
267 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
268 if not os.path.exists(dest):
268 if not os.path.exists(dest):
269 os.mkdir(dest)
269 os.mkdir(dest)
270 else:
270 else:
271 # only clean up directories we create ourselves
271 # only clean up directories we create ourselves
272 dir_cleanup.dir_ = hgdir
272 dir_cleanup.dir_ = hgdir
273 try:
273 try:
274 dest_path = hgdir
274 dest_path = hgdir
275 util.makedir(dest_path, notindexed=True)
275 util.makedir(dest_path, notindexed=True)
276 except OSError, inst:
276 except OSError, inst:
277 if inst.errno == errno.EEXIST:
277 if inst.errno == errno.EEXIST:
278 dir_cleanup.close()
278 dir_cleanup.close()
279 raise util.Abort(_("destination '%s' already exists")
279 raise util.Abort(_("destination '%s' already exists")
280 % dest)
280 % dest)
281 raise
281 raise
282
282
283 hardlink = None
283 hardlink = None
284 num = 0
284 num = 0
285 for f in src_repo.store.copylist():
285 for f in src_repo.store.copylist():
286 src = os.path.join(src_repo.sharedpath, f)
286 src = os.path.join(src_repo.sharedpath, f)
287 dst = os.path.join(dest_path, f)
287 dst = os.path.join(dest_path, f)
288 dstbase = os.path.dirname(dst)
288 dstbase = os.path.dirname(dst)
289 if dstbase and not os.path.exists(dstbase):
289 if dstbase and not os.path.exists(dstbase):
290 os.mkdir(dstbase)
290 os.mkdir(dstbase)
291 if os.path.exists(src):
291 if os.path.exists(src):
292 if dst.endswith('data'):
292 if dst.endswith('data'):
293 # lock to avoid premature writing to the target
293 # lock to avoid premature writing to the target
294 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
294 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
295 hardlink, n = util.copyfiles(src, dst, hardlink)
295 hardlink, n = util.copyfiles(src, dst, hardlink)
296 num += n
296 num += n
297 if hardlink:
297 if hardlink:
298 ui.debug("linked %d files\n" % num)
298 ui.debug("linked %d files\n" % num)
299 else:
299 else:
300 ui.debug("copied %d files\n" % num)
300 ui.debug("copied %d files\n" % num)
301
301
302 # we need to re-init the repo after manually copying the data
302 # we need to re-init the repo after manually copying the data
303 # into it
303 # into it
304 dest_repo = repository(ui, dest)
304 dest_repo = repository(ui, dest)
305 src_repo.hook('outgoing', source='clone',
305 src_repo.hook('outgoing', source='clone',
306 node=node.hex(node.nullid))
306 node=node.hex(node.nullid))
307 else:
307 else:
308 try:
308 try:
309 dest_repo = repository(ui, dest, create=True)
309 dest_repo = repository(ui, dest, create=True)
310 except OSError, inst:
310 except OSError, inst:
311 if inst.errno == errno.EEXIST:
311 if inst.errno == errno.EEXIST:
312 dir_cleanup.close()
312 dir_cleanup.close()
313 raise util.Abort(_("destination '%s' already exists")
313 raise util.Abort(_("destination '%s' already exists")
314 % dest)
314 % dest)
315 raise
315 raise
316
316
317 revs = None
317 revs = None
318 if rev:
318 if rev:
319 if 'lookup' not in src_repo.capabilities:
319 if 'lookup' not in src_repo.capabilities:
320 raise util.Abort(_("src repository does not support "
320 raise util.Abort(_("src repository does not support "
321 "revision lookup and so doesn't "
321 "revision lookup and so doesn't "
322 "support clone by revision"))
322 "support clone by revision"))
323 revs = [src_repo.lookup(r) for r in rev]
323 revs = [src_repo.lookup(r) for r in rev]
324 checkout = revs[0]
324 checkout = revs[0]
325 if dest_repo.local():
325 if dest_repo.local():
326 dest_repo.clone(src_repo, heads=revs, stream=stream)
326 dest_repo.clone(src_repo, heads=revs, stream=stream)
327 elif src_repo.local():
327 elif src_repo.local():
328 src_repo.push(dest_repo, revs=revs)
328 src_repo.push(dest_repo, revs=revs)
329 else:
329 else:
330 raise util.Abort(_("clone from remote to remote not supported"))
330 raise util.Abort(_("clone from remote to remote not supported"))
331
331
332 if dir_cleanup:
332 if dir_cleanup:
333 dir_cleanup.close()
333 dir_cleanup.close()
334
334
335 if dest_repo.local():
335 if dest_repo.local():
336 fp = dest_repo.opener("hgrc", "w", text=True)
336 fp = dest_repo.opener("hgrc", "w", text=True)
337 fp.write("[paths]\n")
337 fp.write("[paths]\n")
338 fp.write("default = %s\n" % abspath)
338 fp.write("default = %s\n" % abspath)
339 fp.close()
339 fp.close()
340
340
341 dest_repo.ui.setconfig('paths', 'default', abspath)
341 dest_repo.ui.setconfig('paths', 'default', abspath)
342
342
343 if update:
343 if update:
344 if update is not True:
344 if update is not True:
345 checkout = update
345 checkout = update
346 if src_repo.local():
346 if src_repo.local():
347 checkout = src_repo.lookup(update)
347 checkout = src_repo.lookup(update)
348 for test in (checkout, 'default', 'tip'):
348 for test in (checkout, 'default', 'tip'):
349 if test is None:
349 if test is None:
350 continue
350 continue
351 try:
351 try:
352 uprev = dest_repo.lookup(test)
352 uprev = dest_repo.lookup(test)
353 break
353 break
354 except error.RepoLookupError:
354 except error.RepoLookupError:
355 continue
355 continue
356 bn = dest_repo[uprev].branch()
356 bn = dest_repo[uprev].branch()
357 dest_repo.ui.status(_("updating to branch %s\n") % bn)
357 dest_repo.ui.status(_("updating to branch %s\n") % bn)
358 _update(dest_repo, uprev)
358 _update(dest_repo, uprev)
359
359
360 # clone all bookmarks
360 # clone all bookmarks
361 if dest_repo.local() and src_repo.capable("pushkey"):
361 if dest_repo.local() and src_repo.capable("pushkey"):
362 rb = src_repo.listkeys('bookmarks')
362 rb = src_repo.listkeys('bookmarks')
363 for k, n in rb.iteritems():
363 for k, n in rb.iteritems():
364 try:
364 try:
365 m = dest_repo.lookup(n)
365 m = dest_repo.lookup(n)
366 dest_repo._bookmarks[k] = m
366 dest_repo._bookmarks[k] = m
367 except error.RepoLookupError:
367 except error.RepoLookupError:
368 pass
368 pass
369 if rb:
369 if rb:
370 bookmarks.write(dest_repo)
370 bookmarks.write(dest_repo)
371 elif src_repo.local() and dest_repo.capable("pushkey"):
371 elif src_repo.local() and dest_repo.capable("pushkey"):
372 for k, n in src_repo._bookmarks.iteritems():
372 for k, n in src_repo._bookmarks.iteritems():
373 dest_repo.pushkey('bookmarks', k, '', hex(n))
373 dest_repo.pushkey('bookmarks', k, '', hex(n))
374
374
375 return src_repo, dest_repo
375 return src_repo, dest_repo
376 finally:
376 finally:
377 release(src_lock, dest_lock)
377 release(src_lock, dest_lock)
378 if dir_cleanup is not None:
378 if dir_cleanup is not None:
379 dir_cleanup.cleanup()
379 dir_cleanup.cleanup()
380
380
381 def _showstats(repo, stats):
381 def _showstats(repo, stats):
382 repo.ui.status(_("%d files updated, %d files merged, "
382 repo.ui.status(_("%d files updated, %d files merged, "
383 "%d files removed, %d files unresolved\n") % stats)
383 "%d files removed, %d files unresolved\n") % stats)
384
384
385 def update(repo, node):
385 def update(repo, node):
386 """update the working directory to node, merging linear changes"""
386 """update the working directory to node, merging linear changes"""
387 stats = mergemod.update(repo, node, False, False, None)
387 stats = mergemod.update(repo, node, False, False, None)
388 _showstats(repo, stats)
388 _showstats(repo, stats)
389 if stats[3]:
389 if stats[3]:
390 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
390 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
391 return stats[3] > 0
391 return stats[3] > 0
392
392
393 # naming conflict in clone()
393 # naming conflict in clone()
394 _update = update
394 _update = update
395
395
396 def clean(repo, node, show_stats=True):
396 def clean(repo, node, show_stats=True):
397 """forcibly switch the working directory to node, clobbering changes"""
397 """forcibly switch the working directory to node, clobbering changes"""
398 stats = mergemod.update(repo, node, False, True, None)
398 stats = mergemod.update(repo, node, False, True, None)
399 if show_stats:
399 if show_stats:
400 _showstats(repo, stats)
400 _showstats(repo, stats)
401 return stats[3] > 0
401 return stats[3] > 0
402
402
403 def merge(repo, node, force=None, remind=True):
403 def merge(repo, node, force=None, remind=True):
404 """Branch merge with node, resolving changes. Return true if any
404 """Branch merge with node, resolving changes. Return true if any
405 unresolved conflicts."""
405 unresolved conflicts."""
406 stats = mergemod.update(repo, node, True, force, False)
406 stats = mergemod.update(repo, node, True, force, False)
407 _showstats(repo, stats)
407 _showstats(repo, stats)
408 if stats[3]:
408 if stats[3]:
409 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
409 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
410 "or 'hg update -C .' to abandon\n"))
410 "or 'hg update -C .' to abandon\n"))
411 elif remind:
411 elif remind:
412 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
412 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
413 return stats[3] > 0
413 return stats[3] > 0
414
414
415 def _incoming(displaychlist, subreporecurse, ui, repo, source,
415 def _incoming(displaychlist, subreporecurse, ui, repo, source,
416 opts, buffered=False):
416 opts, buffered=False):
417 """
417 """
418 Helper for incoming / gincoming.
418 Helper for incoming / gincoming.
419 displaychlist gets called with
419 displaychlist gets called with
420 (remoterepo, incomingchangesetlist, displayer) parameters,
420 (remoterepo, incomingchangesetlist, displayer) parameters,
421 and is supposed to contain only code that can't be unified.
421 and is supposed to contain only code that can't be unified.
422 """
422 """
423 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
423 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
424 other = repository(remoteui(repo, opts), source)
424 other = repository(remoteui(repo, opts), source)
425 ui.status(_('comparing with %s\n') % util.hidepassword(source))
425 ui.status(_('comparing with %s\n') % util.hidepassword(source))
426 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
426 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
427
427
428 if revs:
428 if revs:
429 revs = [other.lookup(rev) for rev in revs]
429 revs = [other.lookup(rev) for rev in revs]
430 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
430 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
431 revs, opts["bundle"], opts["force"])
431 revs, opts["bundle"], opts["force"])
432 try:
432 try:
433 if not chlist:
433 if not chlist:
434 ui.status(_("no changes found\n"))
434 ui.status(_("no changes found\n"))
435 return subreporecurse()
435 return subreporecurse()
436
436
437 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
437 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
438
438
439 # XXX once graphlog extension makes it into core,
439 # XXX once graphlog extension makes it into core,
440 # should be replaced by a if graph/else
440 # should be replaced by a if graph/else
441 displaychlist(other, chlist, displayer)
441 displaychlist(other, chlist, displayer)
442
442
443 displayer.close()
443 displayer.close()
444 finally:
444 finally:
445 cleanupfn()
445 cleanupfn()
446 subreporecurse()
446 subreporecurse()
447 return 0 # exit code is zero since we found incoming changes
447 return 0 # exit code is zero since we found incoming changes
448
448
449 def incoming(ui, repo, source, opts):
449 def incoming(ui, repo, source, opts):
450 def subreporecurse():
450 def subreporecurse():
451 ret = 1
451 ret = 1
452 if opts.get('subrepos'):
452 if opts.get('subrepos'):
453 ctx = repo[None]
453 ctx = repo[None]
454 for subpath in sorted(ctx.substate):
454 for subpath in sorted(ctx.substate):
455 sub = ctx.sub(subpath)
455 sub = ctx.sub(subpath)
456 ret = min(ret, sub.incoming(ui, source, opts))
456 ret = min(ret, sub.incoming(ui, source, opts))
457 return ret
457 return ret
458
458
459 def display(other, chlist, displayer):
459 def display(other, chlist, displayer):
460 limit = cmdutil.loglimit(opts)
460 limit = cmdutil.loglimit(opts)
461 if opts.get('newest_first'):
461 if opts.get('newest_first'):
462 chlist.reverse()
462 chlist.reverse()
463 count = 0
463 count = 0
464 for n in chlist:
464 for n in chlist:
465 if limit is not None and count >= limit:
465 if limit is not None and count >= limit:
466 break
466 break
467 parents = [p for p in other.changelog.parents(n) if p != nullid]
467 parents = [p for p in other.changelog.parents(n) if p != nullid]
468 if opts.get('no_merges') and len(parents) == 2:
468 if opts.get('no_merges') and len(parents) == 2:
469 continue
469 continue
470 count += 1
470 count += 1
471 displayer.show(other[n])
471 displayer.show(other[n])
472 return _incoming(display, subreporecurse, ui, repo, source, opts)
472 return _incoming(display, subreporecurse, ui, repo, source, opts)
473
473
474 def _outgoing(ui, repo, dest, opts):
474 def _outgoing(ui, repo, dest, opts):
475 dest = ui.expandpath(dest or 'default-push', dest or 'default')
475 dest = ui.expandpath(dest or 'default-push', dest or 'default')
476 dest, branches = parseurl(dest, opts.get('branch'))
476 dest, branches = parseurl(dest, opts.get('branch'))
477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
478 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
478 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
479 if revs:
479 if revs:
480 revs = [repo.lookup(rev) for rev in revs]
480 revs = [repo.lookup(rev) for rev in revs]
481
481
482 other = repository(remoteui(repo, opts), dest)
482 other = repository(remoteui(repo, opts), dest)
483 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
483 common, outheads = discovery.findcommonoutgoing(repo, other, revs,
484 common, _anyinc, _heads = inc
484 force=opts.get('force'))
485 o = repo.changelog.findmissing(common, revs)
485 o = repo.changelog.findmissing(common, outheads)
486 if not o:
486 if not o:
487 ui.status(_("no changes found\n"))
487 ui.status(_("no changes found\n"))
488 return None
488 return None
489 return o
489 return o
490
490
491 def outgoing(ui, repo, dest, opts):
491 def outgoing(ui, repo, dest, opts):
492 def recurse():
492 def recurse():
493 ret = 1
493 ret = 1
494 if opts.get('subrepos'):
494 if opts.get('subrepos'):
495 ctx = repo[None]
495 ctx = repo[None]
496 for subpath in sorted(ctx.substate):
496 for subpath in sorted(ctx.substate):
497 sub = ctx.sub(subpath)
497 sub = ctx.sub(subpath)
498 ret = min(ret, sub.outgoing(ui, dest, opts))
498 ret = min(ret, sub.outgoing(ui, dest, opts))
499 return ret
499 return ret
500
500
501 limit = cmdutil.loglimit(opts)
501 limit = cmdutil.loglimit(opts)
502 o = _outgoing(ui, repo, dest, opts)
502 o = _outgoing(ui, repo, dest, opts)
503 if o is None:
503 if o is None:
504 return recurse()
504 return recurse()
505
505
506 if opts.get('newest_first'):
506 if opts.get('newest_first'):
507 o.reverse()
507 o.reverse()
508 displayer = cmdutil.show_changeset(ui, repo, opts)
508 displayer = cmdutil.show_changeset(ui, repo, opts)
509 count = 0
509 count = 0
510 for n in o:
510 for n in o:
511 if limit is not None and count >= limit:
511 if limit is not None and count >= limit:
512 break
512 break
513 parents = [p for p in repo.changelog.parents(n) if p != nullid]
513 parents = [p for p in repo.changelog.parents(n) if p != nullid]
514 if opts.get('no_merges') and len(parents) == 2:
514 if opts.get('no_merges') and len(parents) == 2:
515 continue
515 continue
516 count += 1
516 count += 1
517 displayer.show(repo[n])
517 displayer.show(repo[n])
518 displayer.close()
518 displayer.close()
519 recurse()
519 recurse()
520 return 0 # exit code is zero since we found outgoing changes
520 return 0 # exit code is zero since we found outgoing changes
521
521
522 def revert(repo, node, choose):
522 def revert(repo, node, choose):
523 """revert changes to revision in node without updating dirstate"""
523 """revert changes to revision in node without updating dirstate"""
524 return mergemod.update(repo, node, False, True, choose)[3] > 0
524 return mergemod.update(repo, node, False, True, choose)[3] > 0
525
525
526 def verify(repo):
526 def verify(repo):
527 """verify the consistency of a repository"""
527 """verify the consistency of a repository"""
528 return verifymod.verify(repo)
528 return verifymod.verify(repo)
529
529
530 def remoteui(src, opts):
530 def remoteui(src, opts):
531 'build a remote ui from ui or repo and opts'
531 'build a remote ui from ui or repo and opts'
532 if hasattr(src, 'baseui'): # looks like a repository
532 if hasattr(src, 'baseui'): # looks like a repository
533 dst = src.baseui.copy() # drop repo-specific config
533 dst = src.baseui.copy() # drop repo-specific config
534 src = src.ui # copy target options from repo
534 src = src.ui # copy target options from repo
535 else: # assume it's a global ui object
535 else: # assume it's a global ui object
536 dst = src.copy() # keep all global options
536 dst = src.copy() # keep all global options
537
537
538 # copy ssh-specific options
538 # copy ssh-specific options
539 for o in 'ssh', 'remotecmd':
539 for o in 'ssh', 'remotecmd':
540 v = opts.get(o) or src.config('ui', o)
540 v = opts.get(o) or src.config('ui', o)
541 if v:
541 if v:
542 dst.setconfig("ui", o, v)
542 dst.setconfig("ui", o, v)
543
543
544 # copy bundle-specific options
544 # copy bundle-specific options
545 r = src.config('bundle', 'mainreporoot')
545 r = src.config('bundle', 'mainreporoot')
546 if r:
546 if r:
547 dst.setconfig('bundle', 'mainreporoot', r)
547 dst.setconfig('bundle', 'mainreporoot', r)
548
548
549 # copy selected local settings to the remote ui
549 # copy selected local settings to the remote ui
550 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
550 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
551 for key, val in src.configitems(sect):
551 for key, val in src.configitems(sect):
552 dst.setconfig(sect, key, val)
552 dst.setconfig(sect, key, val)
553 v = src.config('web', 'cacerts')
553 v = src.config('web', 'cacerts')
554 if v:
554 if v:
555 dst.setconfig('web', 'cacerts', util.expandpath(v))
555 dst.setconfig('web', 'cacerts', util.expandpath(v))
556
556
557 return dst
557 return dst
@@ -1,988 +1,988 b''
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, help, hbisect
9 import parser, util, error, discovery, help, hbisect
10 import bookmarks as bookmarksmod
10 import bookmarks as bookmarksmod
11 import match as matchmod
11 import match as matchmod
12 from i18n import _
12 from i18n import _
13
13
14 elements = {
14 elements = {
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
16 "~": (18, None, ("ancestor", 18)),
16 "~": (18, None, ("ancestor", 18)),
17 "^": (18, None, ("parent", 18), ("parentpost", 18)),
17 "^": (18, None, ("parent", 18), ("parentpost", 18)),
18 "-": (5, ("negate", 19), ("minus", 5)),
18 "-": (5, ("negate", 19), ("minus", 5)),
19 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
19 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
20 ("dagrangepost", 17)),
20 ("dagrangepost", 17)),
21 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
21 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
22 ("dagrangepost", 17)),
22 ("dagrangepost", 17)),
23 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
23 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
24 "not": (10, ("not", 10)),
24 "not": (10, ("not", 10)),
25 "!": (10, ("not", 10)),
25 "!": (10, ("not", 10)),
26 "and": (5, None, ("and", 5)),
26 "and": (5, None, ("and", 5)),
27 "&": (5, None, ("and", 5)),
27 "&": (5, None, ("and", 5)),
28 "or": (4, None, ("or", 4)),
28 "or": (4, None, ("or", 4)),
29 "|": (4, None, ("or", 4)),
29 "|": (4, None, ("or", 4)),
30 "+": (4, None, ("or", 4)),
30 "+": (4, None, ("or", 4)),
31 ",": (2, None, ("list", 2)),
31 ",": (2, None, ("list", 2)),
32 ")": (0, None, None),
32 ")": (0, None, None),
33 "symbol": (0, ("symbol",), None),
33 "symbol": (0, ("symbol",), None),
34 "string": (0, ("string",), None),
34 "string": (0, ("string",), None),
35 "end": (0, None, None),
35 "end": (0, None, None),
36 }
36 }
37
37
38 keywords = set(['and', 'or', 'not'])
38 keywords = set(['and', 'or', 'not'])
39
39
40 def tokenize(program):
40 def tokenize(program):
41 pos, l = 0, len(program)
41 pos, l = 0, len(program)
42 while pos < l:
42 while pos < l:
43 c = program[pos]
43 c = program[pos]
44 if c.isspace(): # skip inter-token whitespace
44 if c.isspace(): # skip inter-token whitespace
45 pass
45 pass
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 == '.' and program[pos:pos + 2] == '..': # look ahead carefully
49 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
50 yield ('..', None, pos)
50 yield ('..', None, pos)
51 pos += 1 # skip ahead
51 pos += 1 # skip ahead
52 elif c in "():,-|&+!~^": # handle simple operators
52 elif c in "():,-|&+!~^": # handle simple operators
53 yield (c, None, pos)
53 yield (c, None, pos)
54 elif (c in '"\'' or c == 'r' and
54 elif (c in '"\'' or c == 'r' and
55 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
55 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
56 if c == 'r':
56 if c == 'r':
57 pos += 1
57 pos += 1
58 c = program[pos]
58 c = program[pos]
59 decode = lambda x: x
59 decode = lambda x: x
60 else:
60 else:
61 decode = lambda x: x.decode('string-escape')
61 decode = lambda x: x.decode('string-escape')
62 pos += 1
62 pos += 1
63 s = pos
63 s = pos
64 while pos < l: # find closing quote
64 while pos < l: # find closing quote
65 d = program[pos]
65 d = program[pos]
66 if d == '\\': # skip over escaped characters
66 if d == '\\': # skip over escaped characters
67 pos += 2
67 pos += 2
68 continue
68 continue
69 if d == c:
69 if d == c:
70 yield ('string', decode(program[s:pos]), s)
70 yield ('string', decode(program[s:pos]), s)
71 break
71 break
72 pos += 1
72 pos += 1
73 else:
73 else:
74 raise error.ParseError(_("unterminated string"), s)
74 raise error.ParseError(_("unterminated string"), s)
75 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
75 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
76 s = pos
76 s = pos
77 pos += 1
77 pos += 1
78 while pos < l: # find end of symbol
78 while pos < l: # find end of symbol
79 d = program[pos]
79 d = program[pos]
80 if not (d.isalnum() or d in "._" or ord(d) > 127):
80 if not (d.isalnum() or d in "._" or ord(d) > 127):
81 break
81 break
82 if d == '.' and program[pos - 1] == '.': # special case for ..
82 if d == '.' and program[pos - 1] == '.': # special case for ..
83 pos -= 1
83 pos -= 1
84 break
84 break
85 pos += 1
85 pos += 1
86 sym = program[s:pos]
86 sym = program[s:pos]
87 if sym in keywords: # operator keywords
87 if sym in keywords: # operator keywords
88 yield (sym, None, s)
88 yield (sym, None, s)
89 else:
89 else:
90 yield ('symbol', sym, s)
90 yield ('symbol', sym, s)
91 pos -= 1
91 pos -= 1
92 else:
92 else:
93 raise error.ParseError(_("syntax error"), pos)
93 raise error.ParseError(_("syntax error"), pos)
94 pos += 1
94 pos += 1
95 yield ('end', None, pos)
95 yield ('end', None, pos)
96
96
97 # helpers
97 # helpers
98
98
99 def getstring(x, err):
99 def getstring(x, err):
100 if x and (x[0] == 'string' or x[0] == 'symbol'):
100 if x and (x[0] == 'string' or x[0] == 'symbol'):
101 return x[1]
101 return x[1]
102 raise error.ParseError(err)
102 raise error.ParseError(err)
103
103
104 def getlist(x):
104 def getlist(x):
105 if not x:
105 if not x:
106 return []
106 return []
107 if x[0] == 'list':
107 if x[0] == 'list':
108 return getlist(x[1]) + [x[2]]
108 return getlist(x[1]) + [x[2]]
109 return [x]
109 return [x]
110
110
111 def getargs(x, min, max, err):
111 def getargs(x, min, max, err):
112 l = getlist(x)
112 l = getlist(x)
113 if len(l) < min or len(l) > max:
113 if len(l) < min or len(l) > max:
114 raise error.ParseError(err)
114 raise error.ParseError(err)
115 return l
115 return l
116
116
117 def getset(repo, subset, x):
117 def getset(repo, subset, x):
118 if not x:
118 if not x:
119 raise error.ParseError(_("missing argument"))
119 raise error.ParseError(_("missing argument"))
120 return methods[x[0]](repo, subset, *x[1:])
120 return methods[x[0]](repo, subset, *x[1:])
121
121
122 # operator methods
122 # operator methods
123
123
124 def stringset(repo, subset, x):
124 def stringset(repo, subset, x):
125 x = repo[x].rev()
125 x = repo[x].rev()
126 if x == -1 and len(subset) == len(repo):
126 if x == -1 and len(subset) == len(repo):
127 return [-1]
127 return [-1]
128 if len(subset) == len(repo) or x in subset:
128 if len(subset) == len(repo) or x in subset:
129 return [x]
129 return [x]
130 return []
130 return []
131
131
132 def symbolset(repo, subset, x):
132 def symbolset(repo, subset, x):
133 if x in symbols:
133 if x in symbols:
134 raise error.ParseError(_("can't use %s here") % x)
134 raise error.ParseError(_("can't use %s here") % x)
135 return stringset(repo, subset, x)
135 return stringset(repo, subset, x)
136
136
137 def rangeset(repo, subset, x, y):
137 def rangeset(repo, subset, x, y):
138 m = getset(repo, subset, x)
138 m = getset(repo, subset, x)
139 if not m:
139 if not m:
140 m = getset(repo, range(len(repo)), x)
140 m = getset(repo, range(len(repo)), x)
141
141
142 n = getset(repo, subset, y)
142 n = getset(repo, subset, y)
143 if not n:
143 if not n:
144 n = getset(repo, range(len(repo)), y)
144 n = getset(repo, range(len(repo)), y)
145
145
146 if not m or not n:
146 if not m or not n:
147 return []
147 return []
148 m, n = m[0], n[-1]
148 m, n = m[0], n[-1]
149
149
150 if m < n:
150 if m < n:
151 r = range(m, n + 1)
151 r = range(m, n + 1)
152 else:
152 else:
153 r = range(m, n - 1, -1)
153 r = range(m, n - 1, -1)
154 s = set(subset)
154 s = set(subset)
155 return [x for x in r if x in s]
155 return [x for x in r if x in s]
156
156
157 def andset(repo, subset, x, y):
157 def andset(repo, subset, x, y):
158 return getset(repo, getset(repo, subset, x), y)
158 return getset(repo, getset(repo, subset, x), y)
159
159
160 def orset(repo, subset, x, y):
160 def orset(repo, subset, x, y):
161 xl = getset(repo, subset, x)
161 xl = getset(repo, subset, x)
162 s = set(xl)
162 s = set(xl)
163 yl = getset(repo, [r for r in subset if r not in s], y)
163 yl = getset(repo, [r for r in subset if r not in s], y)
164 return xl + yl
164 return xl + yl
165
165
166 def notset(repo, subset, x):
166 def notset(repo, subset, x):
167 s = set(getset(repo, subset, x))
167 s = set(getset(repo, subset, x))
168 return [r for r in subset if r not in s]
168 return [r for r in subset if r not in s]
169
169
170 def listset(repo, subset, a, b):
170 def listset(repo, subset, a, b):
171 raise error.ParseError(_("can't use a list in this context"))
171 raise error.ParseError(_("can't use a list in this context"))
172
172
173 def func(repo, subset, a, b):
173 def func(repo, subset, a, b):
174 if a[0] == 'symbol' and a[1] in symbols:
174 if a[0] == 'symbol' and a[1] in symbols:
175 return symbols[a[1]](repo, subset, b)
175 return symbols[a[1]](repo, subset, b)
176 raise error.ParseError(_("not a function: %s") % a[1])
176 raise error.ParseError(_("not a function: %s") % a[1])
177
177
178 # functions
178 # functions
179
179
180 def adds(repo, subset, x):
180 def adds(repo, subset, x):
181 """``adds(pattern)``
181 """``adds(pattern)``
182 Changesets that add a file matching pattern.
182 Changesets that add a file matching pattern.
183 """
183 """
184 # i18n: "adds" is a keyword
184 # i18n: "adds" is a keyword
185 pat = getstring(x, _("adds requires a pattern"))
185 pat = getstring(x, _("adds requires a pattern"))
186 return checkstatus(repo, subset, pat, 1)
186 return checkstatus(repo, subset, pat, 1)
187
187
188 def ancestor(repo, subset, x):
188 def ancestor(repo, subset, x):
189 """``ancestor(single, single)``
189 """``ancestor(single, single)``
190 Greatest common ancestor of the two changesets.
190 Greatest common ancestor of the two changesets.
191 """
191 """
192 # i18n: "ancestor" is a keyword
192 # i18n: "ancestor" is a keyword
193 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
193 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
194 r = range(len(repo))
194 r = range(len(repo))
195 a = getset(repo, r, l[0])
195 a = getset(repo, r, l[0])
196 b = getset(repo, r, l[1])
196 b = getset(repo, r, l[1])
197 if len(a) != 1 or len(b) != 1:
197 if len(a) != 1 or len(b) != 1:
198 # i18n: "ancestor" is a keyword
198 # i18n: "ancestor" is a keyword
199 raise error.ParseError(_("ancestor arguments must be single revisions"))
199 raise error.ParseError(_("ancestor arguments must be single revisions"))
200 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
200 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
201
201
202 return [r for r in an if r in subset]
202 return [r for r in an if r in subset]
203
203
204 def ancestors(repo, subset, x):
204 def ancestors(repo, subset, x):
205 """``ancestors(set)``
205 """``ancestors(set)``
206 Changesets that are ancestors of a changeset in set.
206 Changesets that are ancestors of a changeset in set.
207 """
207 """
208 args = getset(repo, range(len(repo)), x)
208 args = getset(repo, range(len(repo)), x)
209 if not args:
209 if not args:
210 return []
210 return []
211 s = set(repo.changelog.ancestors(*args)) | set(args)
211 s = set(repo.changelog.ancestors(*args)) | set(args)
212 return [r for r in subset if r in s]
212 return [r for r in subset if r in s]
213
213
214 def ancestorspec(repo, subset, x, n):
214 def ancestorspec(repo, subset, x, n):
215 """``set~n``
215 """``set~n``
216 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
216 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
217 """
217 """
218 try:
218 try:
219 n = int(n[1])
219 n = int(n[1])
220 except ValueError:
220 except ValueError:
221 raise error.ParseError(_("~ expects a number"))
221 raise error.ParseError(_("~ expects a number"))
222 ps = set()
222 ps = set()
223 cl = repo.changelog
223 cl = repo.changelog
224 for r in getset(repo, subset, x):
224 for r in getset(repo, subset, x):
225 for i in range(n):
225 for i in range(n):
226 r = cl.parentrevs(r)[0]
226 r = cl.parentrevs(r)[0]
227 ps.add(r)
227 ps.add(r)
228 return [r for r in subset if r in ps]
228 return [r for r in subset if r in ps]
229
229
230 def author(repo, subset, x):
230 def author(repo, subset, x):
231 """``author(string)``
231 """``author(string)``
232 Alias for ``user(string)``.
232 Alias for ``user(string)``.
233 """
233 """
234 # i18n: "author" is a keyword
234 # i18n: "author" is a keyword
235 n = getstring(x, _("author requires a string")).lower()
235 n = getstring(x, _("author requires a string")).lower()
236 return [r for r in subset if n in repo[r].user().lower()]
236 return [r for r in subset if n in repo[r].user().lower()]
237
237
238 def bisected(repo, subset, x):
238 def bisected(repo, subset, x):
239 """``bisected(string)``
239 """``bisected(string)``
240 Changesets marked in the specified bisect state (good, bad, skip).
240 Changesets marked in the specified bisect state (good, bad, skip).
241 """
241 """
242 state = getstring(x, _("bisect requires a string")).lower()
242 state = getstring(x, _("bisect requires a string")).lower()
243 if state not in ('good', 'bad', 'skip', 'unknown'):
243 if state not in ('good', 'bad', 'skip', 'unknown'):
244 raise error.ParseError(_('invalid bisect state'))
244 raise error.ParseError(_('invalid bisect state'))
245 marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
245 marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
246 return [r for r in subset if r in marked]
246 return [r for r in subset if r in marked]
247
247
248 def bookmark(repo, subset, x):
248 def bookmark(repo, subset, x):
249 """``bookmark([name])``
249 """``bookmark([name])``
250 The named bookmark or all bookmarks.
250 The named bookmark or all bookmarks.
251 """
251 """
252 # i18n: "bookmark" is a keyword
252 # i18n: "bookmark" is a keyword
253 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
253 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
254 if args:
254 if args:
255 bm = getstring(args[0],
255 bm = getstring(args[0],
256 # i18n: "bookmark" is a keyword
256 # i18n: "bookmark" is a keyword
257 _('the argument to bookmark must be a string'))
257 _('the argument to bookmark must be a string'))
258 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
258 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
259 if not bmrev:
259 if not bmrev:
260 raise util.Abort(_("bookmark '%s' does not exist") % bm)
260 raise util.Abort(_("bookmark '%s' does not exist") % bm)
261 bmrev = repo[bmrev].rev()
261 bmrev = repo[bmrev].rev()
262 return [r for r in subset if r == bmrev]
262 return [r for r in subset if r == bmrev]
263 bms = set([repo[r].rev()
263 bms = set([repo[r].rev()
264 for r in bookmarksmod.listbookmarks(repo).values()])
264 for r in bookmarksmod.listbookmarks(repo).values()])
265 return [r for r in subset if r in bms]
265 return [r for r in subset if r in bms]
266
266
267 def branch(repo, subset, x):
267 def branch(repo, subset, x):
268 """``branch(string or set)``
268 """``branch(string or set)``
269 All changesets belonging to the given branch or the branches of the given
269 All changesets belonging to the given branch or the branches of the given
270 changesets.
270 changesets.
271 """
271 """
272 try:
272 try:
273 b = getstring(x, '')
273 b = getstring(x, '')
274 if b in repo.branchmap():
274 if b in repo.branchmap():
275 return [r for r in subset if repo[r].branch() == b]
275 return [r for r in subset if repo[r].branch() == b]
276 except error.ParseError:
276 except error.ParseError:
277 # not a string, but another revspec, e.g. tip()
277 # not a string, but another revspec, e.g. tip()
278 pass
278 pass
279
279
280 s = getset(repo, range(len(repo)), x)
280 s = getset(repo, range(len(repo)), x)
281 b = set()
281 b = set()
282 for r in s:
282 for r in s:
283 b.add(repo[r].branch())
283 b.add(repo[r].branch())
284 s = set(s)
284 s = set(s)
285 return [r for r in subset if r in s or repo[r].branch() in b]
285 return [r for r in subset if r in s or repo[r].branch() in b]
286
286
287 def checkstatus(repo, subset, pat, field):
287 def checkstatus(repo, subset, pat, field):
288 m = matchmod.match(repo.root, repo.getcwd(), [pat])
288 m = matchmod.match(repo.root, repo.getcwd(), [pat])
289 s = []
289 s = []
290 fast = (m.files() == [pat])
290 fast = (m.files() == [pat])
291 for r in subset:
291 for r in subset:
292 c = repo[r]
292 c = repo[r]
293 if fast:
293 if fast:
294 if pat not in c.files():
294 if pat not in c.files():
295 continue
295 continue
296 else:
296 else:
297 for f in c.files():
297 for f in c.files():
298 if m(f):
298 if m(f):
299 break
299 break
300 else:
300 else:
301 continue
301 continue
302 files = repo.status(c.p1().node(), c.node())[field]
302 files = repo.status(c.p1().node(), c.node())[field]
303 if fast:
303 if fast:
304 if pat in files:
304 if pat in files:
305 s.append(r)
305 s.append(r)
306 else:
306 else:
307 for f in files:
307 for f in files:
308 if m(f):
308 if m(f):
309 s.append(r)
309 s.append(r)
310 break
310 break
311 return s
311 return s
312
312
313 def children(repo, subset, x):
313 def children(repo, subset, x):
314 """``children(set)``
314 """``children(set)``
315 Child changesets of changesets in set.
315 Child changesets of changesets in set.
316 """
316 """
317 cs = set()
317 cs = set()
318 cl = repo.changelog
318 cl = repo.changelog
319 s = set(getset(repo, range(len(repo)), x))
319 s = set(getset(repo, range(len(repo)), x))
320 for r in xrange(0, len(repo)):
320 for r in xrange(0, len(repo)):
321 for p in cl.parentrevs(r):
321 for p in cl.parentrevs(r):
322 if p in s:
322 if p in s:
323 cs.add(r)
323 cs.add(r)
324 return [r for r in subset if r in cs]
324 return [r for r in subset if r in cs]
325
325
326 def closed(repo, subset, x):
326 def closed(repo, subset, x):
327 """``closed()``
327 """``closed()``
328 Changeset is closed.
328 Changeset is closed.
329 """
329 """
330 # i18n: "closed" is a keyword
330 # i18n: "closed" is a keyword
331 getargs(x, 0, 0, _("closed takes no arguments"))
331 getargs(x, 0, 0, _("closed takes no arguments"))
332 return [r for r in subset if repo[r].extra().get('close')]
332 return [r for r in subset if repo[r].extra().get('close')]
333
333
334 def contains(repo, subset, x):
334 def contains(repo, subset, x):
335 """``contains(pattern)``
335 """``contains(pattern)``
336 Revision contains pattern.
336 Revision contains pattern.
337 """
337 """
338 # i18n: "contains" is a keyword
338 # i18n: "contains" is a keyword
339 pat = getstring(x, _("contains requires a pattern"))
339 pat = getstring(x, _("contains requires a pattern"))
340 m = matchmod.match(repo.root, repo.getcwd(), [pat])
340 m = matchmod.match(repo.root, repo.getcwd(), [pat])
341 s = []
341 s = []
342 if m.files() == [pat]:
342 if m.files() == [pat]:
343 for r in subset:
343 for r in subset:
344 if pat in repo[r]:
344 if pat in repo[r]:
345 s.append(r)
345 s.append(r)
346 else:
346 else:
347 for r in subset:
347 for r in subset:
348 for f in repo[r].manifest():
348 for f in repo[r].manifest():
349 if m(f):
349 if m(f):
350 s.append(r)
350 s.append(r)
351 break
351 break
352 return s
352 return s
353
353
354 def date(repo, subset, x):
354 def date(repo, subset, x):
355 """``date(interval)``
355 """``date(interval)``
356 Changesets within the interval, see :hg:`help dates`.
356 Changesets within the interval, see :hg:`help dates`.
357 """
357 """
358 # i18n: "date" is a keyword
358 # i18n: "date" is a keyword
359 ds = getstring(x, _("date requires a string"))
359 ds = getstring(x, _("date requires a string"))
360 dm = util.matchdate(ds)
360 dm = util.matchdate(ds)
361 return [r for r in subset if dm(repo[r].date()[0])]
361 return [r for r in subset if dm(repo[r].date()[0])]
362
362
363 def descendants(repo, subset, x):
363 def descendants(repo, subset, x):
364 """``descendants(set)``
364 """``descendants(set)``
365 Changesets which are descendants of changesets in set.
365 Changesets which are descendants of changesets in set.
366 """
366 """
367 args = getset(repo, range(len(repo)), x)
367 args = getset(repo, range(len(repo)), x)
368 if not args:
368 if not args:
369 return []
369 return []
370 s = set(repo.changelog.descendants(*args)) | set(args)
370 s = set(repo.changelog.descendants(*args)) | set(args)
371 return [r for r in subset if r in s]
371 return [r for r in subset if r in s]
372
372
373 def follow(repo, subset, x):
373 def follow(repo, subset, x):
374 """``follow()``
374 """``follow()``
375 An alias for ``::.`` (ancestors of the working copy's first parent).
375 An alias for ``::.`` (ancestors of the working copy's first parent).
376 """
376 """
377 # i18n: "follow" is a keyword
377 # i18n: "follow" is a keyword
378 getargs(x, 0, 0, _("follow takes no arguments"))
378 getargs(x, 0, 0, _("follow takes no arguments"))
379 p = repo['.'].rev()
379 p = repo['.'].rev()
380 s = set(repo.changelog.ancestors(p)) | set([p])
380 s = set(repo.changelog.ancestors(p)) | set([p])
381 return [r for r in subset if r in s]
381 return [r for r in subset if r in s]
382
382
383 def getall(repo, subset, x):
383 def getall(repo, subset, x):
384 """``all()``
384 """``all()``
385 All changesets, the same as ``0:tip``.
385 All changesets, the same as ``0:tip``.
386 """
386 """
387 # i18n: "all" is a keyword
387 # i18n: "all" is a keyword
388 getargs(x, 0, 0, _("all takes no arguments"))
388 getargs(x, 0, 0, _("all takes no arguments"))
389 return subset
389 return subset
390
390
391 def grep(repo, subset, x):
391 def grep(repo, subset, x):
392 """``grep(regex)``
392 """``grep(regex)``
393 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
393 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
394 to ensure special escape characters are handled correctly.
394 to ensure special escape characters are handled correctly.
395 """
395 """
396 try:
396 try:
397 # i18n: "grep" is a keyword
397 # i18n: "grep" is a keyword
398 gr = re.compile(getstring(x, _("grep requires a string")))
398 gr = re.compile(getstring(x, _("grep requires a string")))
399 except re.error, e:
399 except re.error, e:
400 raise error.ParseError(_('invalid match pattern: %s') % e)
400 raise error.ParseError(_('invalid match pattern: %s') % e)
401 l = []
401 l = []
402 for r in subset:
402 for r in subset:
403 c = repo[r]
403 c = repo[r]
404 for e in c.files() + [c.user(), c.description()]:
404 for e in c.files() + [c.user(), c.description()]:
405 if gr.search(e):
405 if gr.search(e):
406 l.append(r)
406 l.append(r)
407 break
407 break
408 return l
408 return l
409
409
410 def hasfile(repo, subset, x):
410 def hasfile(repo, subset, x):
411 """``file(pattern)``
411 """``file(pattern)``
412 Changesets affecting files matched by pattern.
412 Changesets affecting files matched by pattern.
413 """
413 """
414 # i18n: "file" is a keyword
414 # i18n: "file" is a keyword
415 pat = getstring(x, _("file requires a pattern"))
415 pat = getstring(x, _("file requires a pattern"))
416 m = matchmod.match(repo.root, repo.getcwd(), [pat])
416 m = matchmod.match(repo.root, repo.getcwd(), [pat])
417 s = []
417 s = []
418 for r in subset:
418 for r in subset:
419 for f in repo[r].files():
419 for f in repo[r].files():
420 if m(f):
420 if m(f):
421 s.append(r)
421 s.append(r)
422 break
422 break
423 return s
423 return s
424
424
425 def head(repo, subset, x):
425 def head(repo, subset, x):
426 """``head()``
426 """``head()``
427 Changeset is a named branch head.
427 Changeset is a named branch head.
428 """
428 """
429 # i18n: "head" is a keyword
429 # i18n: "head" is a keyword
430 getargs(x, 0, 0, _("head takes no arguments"))
430 getargs(x, 0, 0, _("head takes no arguments"))
431 hs = set()
431 hs = set()
432 for b, ls in repo.branchmap().iteritems():
432 for b, ls in repo.branchmap().iteritems():
433 hs.update(repo[h].rev() for h in ls)
433 hs.update(repo[h].rev() for h in ls)
434 return [r for r in subset if r in hs]
434 return [r for r in subset if r in hs]
435
435
436 def heads(repo, subset, x):
436 def heads(repo, subset, x):
437 """``heads(set)``
437 """``heads(set)``
438 Members of set with no children in set.
438 Members of set with no children in set.
439 """
439 """
440 s = getset(repo, subset, x)
440 s = getset(repo, subset, x)
441 ps = set(parents(repo, subset, x))
441 ps = set(parents(repo, subset, x))
442 return [r for r in s if r not in ps]
442 return [r for r in s if r not in ps]
443
443
444 def keyword(repo, subset, x):
444 def keyword(repo, subset, x):
445 """``keyword(string)``
445 """``keyword(string)``
446 Search commit message, user name, and names of changed files for
446 Search commit message, user name, and names of changed files for
447 string.
447 string.
448 """
448 """
449 # i18n: "keyword" is a keyword
449 # i18n: "keyword" is a keyword
450 kw = getstring(x, _("keyword requires a string")).lower()
450 kw = getstring(x, _("keyword requires a string")).lower()
451 l = []
451 l = []
452 for r in subset:
452 for r in subset:
453 c = repo[r]
453 c = repo[r]
454 t = " ".join(c.files() + [c.user(), c.description()])
454 t = " ".join(c.files() + [c.user(), c.description()])
455 if kw in t.lower():
455 if kw in t.lower():
456 l.append(r)
456 l.append(r)
457 return l
457 return l
458
458
459 def limit(repo, subset, x):
459 def limit(repo, subset, x):
460 """``limit(set, n)``
460 """``limit(set, n)``
461 First n members of set.
461 First n members of set.
462 """
462 """
463 # i18n: "limit" is a keyword
463 # i18n: "limit" is a keyword
464 l = getargs(x, 2, 2, _("limit requires two arguments"))
464 l = getargs(x, 2, 2, _("limit requires two arguments"))
465 try:
465 try:
466 # i18n: "limit" is a keyword
466 # i18n: "limit" is a keyword
467 lim = int(getstring(l[1], _("limit requires a number")))
467 lim = int(getstring(l[1], _("limit requires a number")))
468 except ValueError:
468 except ValueError:
469 # i18n: "limit" is a keyword
469 # i18n: "limit" is a keyword
470 raise error.ParseError(_("limit expects a number"))
470 raise error.ParseError(_("limit expects a number"))
471 ss = set(subset)
471 ss = set(subset)
472 os = getset(repo, range(len(repo)), l[0])[:lim]
472 os = getset(repo, range(len(repo)), l[0])[:lim]
473 return [r for r in os if r in ss]
473 return [r for r in os if r in ss]
474
474
475 def last(repo, subset, x):
475 def last(repo, subset, x):
476 """``last(set, n)``
476 """``last(set, n)``
477 Last n members of set.
477 Last n members of set.
478 """
478 """
479 # i18n: "last" is a keyword
479 # i18n: "last" is a keyword
480 l = getargs(x, 2, 2, _("last requires two arguments"))
480 l = getargs(x, 2, 2, _("last requires two arguments"))
481 try:
481 try:
482 # i18n: "last" is a keyword
482 # i18n: "last" is a keyword
483 lim = int(getstring(l[1], _("last requires a number")))
483 lim = int(getstring(l[1], _("last requires a number")))
484 except ValueError:
484 except ValueError:
485 # i18n: "last" is a keyword
485 # i18n: "last" is a keyword
486 raise error.ParseError(_("last expects a number"))
486 raise error.ParseError(_("last expects a number"))
487 ss = set(subset)
487 ss = set(subset)
488 os = getset(repo, range(len(repo)), l[0])[-lim:]
488 os = getset(repo, range(len(repo)), l[0])[-lim:]
489 return [r for r in os if r in ss]
489 return [r for r in os if r in ss]
490
490
491 def maxrev(repo, subset, x):
491 def maxrev(repo, subset, x):
492 """``max(set)``
492 """``max(set)``
493 Changeset with highest revision number in set.
493 Changeset with highest revision number in set.
494 """
494 """
495 os = getset(repo, range(len(repo)), x)
495 os = getset(repo, range(len(repo)), x)
496 if os:
496 if os:
497 m = max(os)
497 m = max(os)
498 if m in subset:
498 if m in subset:
499 return [m]
499 return [m]
500 return []
500 return []
501
501
502 def merge(repo, subset, x):
502 def merge(repo, subset, x):
503 """``merge()``
503 """``merge()``
504 Changeset is a merge changeset.
504 Changeset is a merge changeset.
505 """
505 """
506 # i18n: "merge" is a keyword
506 # i18n: "merge" is a keyword
507 getargs(x, 0, 0, _("merge takes no arguments"))
507 getargs(x, 0, 0, _("merge takes no arguments"))
508 cl = repo.changelog
508 cl = repo.changelog
509 return [r for r in subset if cl.parentrevs(r)[1] != -1]
509 return [r for r in subset if cl.parentrevs(r)[1] != -1]
510
510
511 def minrev(repo, subset, x):
511 def minrev(repo, subset, x):
512 """``min(set)``
512 """``min(set)``
513 Changeset with lowest revision number in set.
513 Changeset with lowest revision number in set.
514 """
514 """
515 os = getset(repo, range(len(repo)), x)
515 os = getset(repo, range(len(repo)), x)
516 if os:
516 if os:
517 m = min(os)
517 m = min(os)
518 if m in subset:
518 if m in subset:
519 return [m]
519 return [m]
520 return []
520 return []
521
521
522 def modifies(repo, subset, x):
522 def modifies(repo, subset, x):
523 """``modifies(pattern)``
523 """``modifies(pattern)``
524 Changesets modifying files matched by pattern.
524 Changesets modifying files matched by pattern.
525 """
525 """
526 # i18n: "modifies" is a keyword
526 # i18n: "modifies" is a keyword
527 pat = getstring(x, _("modifies requires a pattern"))
527 pat = getstring(x, _("modifies requires a pattern"))
528 return checkstatus(repo, subset, pat, 0)
528 return checkstatus(repo, subset, pat, 0)
529
529
530 def node(repo, subset, x):
530 def node(repo, subset, x):
531 """``id(string)``
531 """``id(string)``
532 Revision non-ambiguously specified by the given hex string prefix.
532 Revision non-ambiguously specified by the given hex string prefix.
533 """
533 """
534 # i18n: "id" is a keyword
534 # i18n: "id" is a keyword
535 l = getargs(x, 1, 1, _("id requires one argument"))
535 l = getargs(x, 1, 1, _("id requires one argument"))
536 # i18n: "id" is a keyword
536 # i18n: "id" is a keyword
537 n = getstring(l[0], _("id requires a string"))
537 n = getstring(l[0], _("id requires a string"))
538 if len(n) == 40:
538 if len(n) == 40:
539 rn = repo[n].rev()
539 rn = repo[n].rev()
540 else:
540 else:
541 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
541 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
542 return [r for r in subset if r == rn]
542 return [r for r in subset if r == rn]
543
543
544 def outgoing(repo, subset, x):
544 def outgoing(repo, subset, x):
545 """``outgoing([path])``
545 """``outgoing([path])``
546 Changesets not found in the specified destination repository, or the
546 Changesets not found in the specified destination repository, or the
547 default push location.
547 default push location.
548 """
548 """
549 import hg # avoid start-up nasties
549 import hg # avoid start-up nasties
550 # i18n: "outgoing" is a keyword
550 # i18n: "outgoing" is a keyword
551 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
551 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
552 # i18n: "outgoing" is a keyword
552 # i18n: "outgoing" is a keyword
553 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
553 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
554 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
554 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
555 dest, branches = hg.parseurl(dest)
555 dest, branches = hg.parseurl(dest)
556 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
556 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
557 if revs:
557 if revs:
558 revs = [repo.lookup(rev) for rev in revs]
558 revs = [repo.lookup(rev) for rev in revs]
559 other = hg.repository(hg.remoteui(repo, {}), dest)
559 other = hg.repository(hg.remoteui(repo, {}), dest)
560 repo.ui.pushbuffer()
560 repo.ui.pushbuffer()
561 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
561 common, outheads = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
562 repo.ui.popbuffer()
562 repo.ui.popbuffer()
563 cl = repo.changelog
563 cl = repo.changelog
564 o = set([cl.rev(r) for r in repo.changelog.findmissing(common, revs)])
564 o = set([cl.rev(r) for r in repo.changelog.findmissing(common, outheads)])
565 return [r for r in subset if r in o]
565 return [r for r in subset if r in o]
566
566
567 def p1(repo, subset, x):
567 def p1(repo, subset, x):
568 """``p1([set])``
568 """``p1([set])``
569 First parent of changesets in set, or the working directory.
569 First parent of changesets in set, or the working directory.
570 """
570 """
571 if x is None:
571 if x is None:
572 p = repo[x].p1().rev()
572 p = repo[x].p1().rev()
573 return [r for r in subset if r == p]
573 return [r for r in subset if r == p]
574
574
575 ps = set()
575 ps = set()
576 cl = repo.changelog
576 cl = repo.changelog
577 for r in getset(repo, range(len(repo)), x):
577 for r in getset(repo, range(len(repo)), x):
578 ps.add(cl.parentrevs(r)[0])
578 ps.add(cl.parentrevs(r)[0])
579 return [r for r in subset if r in ps]
579 return [r for r in subset if r in ps]
580
580
581 def p2(repo, subset, x):
581 def p2(repo, subset, x):
582 """``p2([set])``
582 """``p2([set])``
583 Second parent of changesets in set, or the working directory.
583 Second parent of changesets in set, or the working directory.
584 """
584 """
585 if x is None:
585 if x is None:
586 ps = repo[x].parents()
586 ps = repo[x].parents()
587 try:
587 try:
588 p = ps[1].rev()
588 p = ps[1].rev()
589 return [r for r in subset if r == p]
589 return [r for r in subset if r == p]
590 except IndexError:
590 except IndexError:
591 return []
591 return []
592
592
593 ps = set()
593 ps = set()
594 cl = repo.changelog
594 cl = repo.changelog
595 for r in getset(repo, range(len(repo)), x):
595 for r in getset(repo, range(len(repo)), x):
596 ps.add(cl.parentrevs(r)[1])
596 ps.add(cl.parentrevs(r)[1])
597 return [r for r in subset if r in ps]
597 return [r for r in subset if r in ps]
598
598
599 def parents(repo, subset, x):
599 def parents(repo, subset, x):
600 """``parents([set])``
600 """``parents([set])``
601 The set of all parents for all changesets in set, or the working directory.
601 The set of all parents for all changesets in set, or the working directory.
602 """
602 """
603 if x is None:
603 if x is None:
604 ps = tuple(p.rev() for p in repo[x].parents())
604 ps = tuple(p.rev() for p in repo[x].parents())
605 return [r for r in subset if r in ps]
605 return [r for r in subset if r in ps]
606
606
607 ps = set()
607 ps = set()
608 cl = repo.changelog
608 cl = repo.changelog
609 for r in getset(repo, range(len(repo)), x):
609 for r in getset(repo, range(len(repo)), x):
610 ps.update(cl.parentrevs(r))
610 ps.update(cl.parentrevs(r))
611 return [r for r in subset if r in ps]
611 return [r for r in subset if r in ps]
612
612
613 def parentspec(repo, subset, x, n):
613 def parentspec(repo, subset, x, n):
614 """``set^0``
614 """``set^0``
615 The set.
615 The set.
616 ``set^1`` (or ``set^``), ``set^2``
616 ``set^1`` (or ``set^``), ``set^2``
617 First or second parent, respectively, of all changesets in set.
617 First or second parent, respectively, of all changesets in set.
618 """
618 """
619 try:
619 try:
620 n = int(n[1])
620 n = int(n[1])
621 if n not in (0, 1, 2):
621 if n not in (0, 1, 2):
622 raise ValueError
622 raise ValueError
623 except ValueError:
623 except ValueError:
624 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
624 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
625 ps = set()
625 ps = set()
626 cl = repo.changelog
626 cl = repo.changelog
627 for r in getset(repo, subset, x):
627 for r in getset(repo, subset, x):
628 if n == 0:
628 if n == 0:
629 ps.add(r)
629 ps.add(r)
630 elif n == 1:
630 elif n == 1:
631 ps.add(cl.parentrevs(r)[0])
631 ps.add(cl.parentrevs(r)[0])
632 elif n == 2:
632 elif n == 2:
633 parents = cl.parentrevs(r)
633 parents = cl.parentrevs(r)
634 if len(parents) > 1:
634 if len(parents) > 1:
635 ps.add(parents[1])
635 ps.add(parents[1])
636 return [r for r in subset if r in ps]
636 return [r for r in subset if r in ps]
637
637
638 def present(repo, subset, x):
638 def present(repo, subset, x):
639 """``present(set)``
639 """``present(set)``
640 An empty set, if any revision in set isn't found; otherwise,
640 An empty set, if any revision in set isn't found; otherwise,
641 all revisions in set.
641 all revisions in set.
642 """
642 """
643 try:
643 try:
644 return getset(repo, subset, x)
644 return getset(repo, subset, x)
645 except error.RepoLookupError:
645 except error.RepoLookupError:
646 return []
646 return []
647
647
648 def removes(repo, subset, x):
648 def removes(repo, subset, x):
649 """``removes(pattern)``
649 """``removes(pattern)``
650 Changesets which remove files matching pattern.
650 Changesets which remove files matching pattern.
651 """
651 """
652 # i18n: "removes" is a keyword
652 # i18n: "removes" is a keyword
653 pat = getstring(x, _("removes requires a pattern"))
653 pat = getstring(x, _("removes requires a pattern"))
654 return checkstatus(repo, subset, pat, 2)
654 return checkstatus(repo, subset, pat, 2)
655
655
656 def rev(repo, subset, x):
656 def rev(repo, subset, x):
657 """``rev(number)``
657 """``rev(number)``
658 Revision with the given numeric identifier.
658 Revision with the given numeric identifier.
659 """
659 """
660 # i18n: "rev" is a keyword
660 # i18n: "rev" is a keyword
661 l = getargs(x, 1, 1, _("rev requires one argument"))
661 l = getargs(x, 1, 1, _("rev requires one argument"))
662 try:
662 try:
663 # i18n: "rev" is a keyword
663 # i18n: "rev" is a keyword
664 l = int(getstring(l[0], _("rev requires a number")))
664 l = int(getstring(l[0], _("rev requires a number")))
665 except ValueError:
665 except ValueError:
666 # i18n: "rev" is a keyword
666 # i18n: "rev" is a keyword
667 raise error.ParseError(_("rev expects a number"))
667 raise error.ParseError(_("rev expects a number"))
668 return [r for r in subset if r == l]
668 return [r for r in subset if r == l]
669
669
670 def reverse(repo, subset, x):
670 def reverse(repo, subset, x):
671 """``reverse(set)``
671 """``reverse(set)``
672 Reverse order of set.
672 Reverse order of set.
673 """
673 """
674 l = getset(repo, subset, x)
674 l = getset(repo, subset, x)
675 l.reverse()
675 l.reverse()
676 return l
676 return l
677
677
678 def roots(repo, subset, x):
678 def roots(repo, subset, x):
679 """``roots(set)``
679 """``roots(set)``
680 Changesets with no parent changeset in set.
680 Changesets with no parent changeset in set.
681 """
681 """
682 s = getset(repo, subset, x)
682 s = getset(repo, subset, x)
683 cs = set(children(repo, subset, x))
683 cs = set(children(repo, subset, x))
684 return [r for r in s if r not in cs]
684 return [r for r in s if r not in cs]
685
685
686 def sort(repo, subset, x):
686 def sort(repo, subset, x):
687 """``sort(set[, [-]key...])``
687 """``sort(set[, [-]key...])``
688 Sort set by keys. The default sort order is ascending, specify a key
688 Sort set by keys. The default sort order is ascending, specify a key
689 as ``-key`` to sort in descending order.
689 as ``-key`` to sort in descending order.
690
690
691 The keys can be:
691 The keys can be:
692
692
693 - ``rev`` for the revision number,
693 - ``rev`` for the revision number,
694 - ``branch`` for the branch name,
694 - ``branch`` for the branch name,
695 - ``desc`` for the commit message (description),
695 - ``desc`` for the commit message (description),
696 - ``user`` for user name (``author`` can be used as an alias),
696 - ``user`` for user name (``author`` can be used as an alias),
697 - ``date`` for the commit date
697 - ``date`` for the commit date
698 """
698 """
699 # i18n: "sort" is a keyword
699 # i18n: "sort" is a keyword
700 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
700 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
701 keys = "rev"
701 keys = "rev"
702 if len(l) == 2:
702 if len(l) == 2:
703 keys = getstring(l[1], _("sort spec must be a string"))
703 keys = getstring(l[1], _("sort spec must be a string"))
704
704
705 s = l[0]
705 s = l[0]
706 keys = keys.split()
706 keys = keys.split()
707 l = []
707 l = []
708 def invert(s):
708 def invert(s):
709 return "".join(chr(255 - ord(c)) for c in s)
709 return "".join(chr(255 - ord(c)) for c in s)
710 for r in getset(repo, subset, s):
710 for r in getset(repo, subset, s):
711 c = repo[r]
711 c = repo[r]
712 e = []
712 e = []
713 for k in keys:
713 for k in keys:
714 if k == 'rev':
714 if k == 'rev':
715 e.append(r)
715 e.append(r)
716 elif k == '-rev':
716 elif k == '-rev':
717 e.append(-r)
717 e.append(-r)
718 elif k == 'branch':
718 elif k == 'branch':
719 e.append(c.branch())
719 e.append(c.branch())
720 elif k == '-branch':
720 elif k == '-branch':
721 e.append(invert(c.branch()))
721 e.append(invert(c.branch()))
722 elif k == 'desc':
722 elif k == 'desc':
723 e.append(c.description())
723 e.append(c.description())
724 elif k == '-desc':
724 elif k == '-desc':
725 e.append(invert(c.description()))
725 e.append(invert(c.description()))
726 elif k in 'user author':
726 elif k in 'user author':
727 e.append(c.user())
727 e.append(c.user())
728 elif k in '-user -author':
728 elif k in '-user -author':
729 e.append(invert(c.user()))
729 e.append(invert(c.user()))
730 elif k == 'date':
730 elif k == 'date':
731 e.append(c.date()[0])
731 e.append(c.date()[0])
732 elif k == '-date':
732 elif k == '-date':
733 e.append(-c.date()[0])
733 e.append(-c.date()[0])
734 else:
734 else:
735 raise error.ParseError(_("unknown sort key %r") % k)
735 raise error.ParseError(_("unknown sort key %r") % k)
736 e.append(r)
736 e.append(r)
737 l.append(e)
737 l.append(e)
738 l.sort()
738 l.sort()
739 return [e[-1] for e in l]
739 return [e[-1] for e in l]
740
740
741 def tag(repo, subset, x):
741 def tag(repo, subset, x):
742 """``tag(name)``
742 """``tag(name)``
743 The specified tag by name, or all tagged revisions if no name is given.
743 The specified tag by name, or all tagged revisions if no name is given.
744 """
744 """
745 # i18n: "tag" is a keyword
745 # i18n: "tag" is a keyword
746 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
746 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
747 cl = repo.changelog
747 cl = repo.changelog
748 if args:
748 if args:
749 tn = getstring(args[0],
749 tn = getstring(args[0],
750 # i18n: "tag" is a keyword
750 # i18n: "tag" is a keyword
751 _('the argument to tag must be a string'))
751 _('the argument to tag must be a string'))
752 if not repo.tags().get(tn, None):
752 if not repo.tags().get(tn, None):
753 raise util.Abort(_("tag '%s' does not exist") % tn)
753 raise util.Abort(_("tag '%s' does not exist") % tn)
754 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
754 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
755 else:
755 else:
756 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
756 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
757 return [r for r in subset if r in s]
757 return [r for r in subset if r in s]
758
758
759 def tagged(repo, subset, x):
759 def tagged(repo, subset, x):
760 return tag(repo, subset, x)
760 return tag(repo, subset, x)
761
761
762 def user(repo, subset, x):
762 def user(repo, subset, x):
763 """``user(string)``
763 """``user(string)``
764 User name is string.
764 User name is string.
765 """
765 """
766 return author(repo, subset, x)
766 return author(repo, subset, x)
767
767
768 symbols = {
768 symbols = {
769 "adds": adds,
769 "adds": adds,
770 "all": getall,
770 "all": getall,
771 "ancestor": ancestor,
771 "ancestor": ancestor,
772 "ancestors": ancestors,
772 "ancestors": ancestors,
773 "author": author,
773 "author": author,
774 "bisected": bisected,
774 "bisected": bisected,
775 "bookmark": bookmark,
775 "bookmark": bookmark,
776 "branch": branch,
776 "branch": branch,
777 "children": children,
777 "children": children,
778 "closed": closed,
778 "closed": closed,
779 "contains": contains,
779 "contains": contains,
780 "date": date,
780 "date": date,
781 "descendants": descendants,
781 "descendants": descendants,
782 "file": hasfile,
782 "file": hasfile,
783 "follow": follow,
783 "follow": follow,
784 "grep": grep,
784 "grep": grep,
785 "head": head,
785 "head": head,
786 "heads": heads,
786 "heads": heads,
787 "keyword": keyword,
787 "keyword": keyword,
788 "last": last,
788 "last": last,
789 "limit": limit,
789 "limit": limit,
790 "max": maxrev,
790 "max": maxrev,
791 "min": minrev,
791 "min": minrev,
792 "merge": merge,
792 "merge": merge,
793 "modifies": modifies,
793 "modifies": modifies,
794 "id": node,
794 "id": node,
795 "outgoing": outgoing,
795 "outgoing": outgoing,
796 "p1": p1,
796 "p1": p1,
797 "p2": p2,
797 "p2": p2,
798 "parents": parents,
798 "parents": parents,
799 "present": present,
799 "present": present,
800 "removes": removes,
800 "removes": removes,
801 "reverse": reverse,
801 "reverse": reverse,
802 "rev": rev,
802 "rev": rev,
803 "roots": roots,
803 "roots": roots,
804 "sort": sort,
804 "sort": sort,
805 "tag": tag,
805 "tag": tag,
806 "tagged": tagged,
806 "tagged": tagged,
807 "user": user,
807 "user": user,
808 }
808 }
809
809
810 methods = {
810 methods = {
811 "range": rangeset,
811 "range": rangeset,
812 "string": stringset,
812 "string": stringset,
813 "symbol": symbolset,
813 "symbol": symbolset,
814 "and": andset,
814 "and": andset,
815 "or": orset,
815 "or": orset,
816 "not": notset,
816 "not": notset,
817 "list": listset,
817 "list": listset,
818 "func": func,
818 "func": func,
819 "ancestor": ancestorspec,
819 "ancestor": ancestorspec,
820 "parent": parentspec,
820 "parent": parentspec,
821 "parentpost": p1,
821 "parentpost": p1,
822 }
822 }
823
823
824 def optimize(x, small):
824 def optimize(x, small):
825 if x is None:
825 if x is None:
826 return 0, x
826 return 0, x
827
827
828 smallbonus = 1
828 smallbonus = 1
829 if small:
829 if small:
830 smallbonus = .5
830 smallbonus = .5
831
831
832 op = x[0]
832 op = x[0]
833 if op == 'minus':
833 if op == 'minus':
834 return optimize(('and', x[1], ('not', x[2])), small)
834 return optimize(('and', x[1], ('not', x[2])), small)
835 elif op == 'dagrange':
835 elif op == 'dagrange':
836 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
836 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
837 ('func', ('symbol', 'ancestors'), x[2])), small)
837 ('func', ('symbol', 'ancestors'), x[2])), small)
838 elif op == 'dagrangepre':
838 elif op == 'dagrangepre':
839 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
839 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
840 elif op == 'dagrangepost':
840 elif op == 'dagrangepost':
841 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
841 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
842 elif op == 'rangepre':
842 elif op == 'rangepre':
843 return optimize(('range', ('string', '0'), x[1]), small)
843 return optimize(('range', ('string', '0'), x[1]), small)
844 elif op == 'rangepost':
844 elif op == 'rangepost':
845 return optimize(('range', x[1], ('string', 'tip')), small)
845 return optimize(('range', x[1], ('string', 'tip')), small)
846 elif op == 'negate':
846 elif op == 'negate':
847 return optimize(('string',
847 return optimize(('string',
848 '-' + getstring(x[1], _("can't negate that"))), small)
848 '-' + getstring(x[1], _("can't negate that"))), small)
849 elif op in 'string symbol negate':
849 elif op in 'string symbol negate':
850 return smallbonus, x # single revisions are small
850 return smallbonus, x # single revisions are small
851 elif op == 'and' or op == 'dagrange':
851 elif op == 'and' or op == 'dagrange':
852 wa, ta = optimize(x[1], True)
852 wa, ta = optimize(x[1], True)
853 wb, tb = optimize(x[2], True)
853 wb, tb = optimize(x[2], True)
854 w = min(wa, wb)
854 w = min(wa, wb)
855 if wa > wb:
855 if wa > wb:
856 return w, (op, tb, ta)
856 return w, (op, tb, ta)
857 return w, (op, ta, tb)
857 return w, (op, ta, tb)
858 elif op == 'or':
858 elif op == 'or':
859 wa, ta = optimize(x[1], False)
859 wa, ta = optimize(x[1], False)
860 wb, tb = optimize(x[2], False)
860 wb, tb = optimize(x[2], False)
861 if wb < wa:
861 if wb < wa:
862 wb, wa = wa, wb
862 wb, wa = wa, wb
863 return max(wa, wb), (op, ta, tb)
863 return max(wa, wb), (op, ta, tb)
864 elif op == 'not':
864 elif op == 'not':
865 o = optimize(x[1], not small)
865 o = optimize(x[1], not small)
866 return o[0], (op, o[1])
866 return o[0], (op, o[1])
867 elif op == 'parentpost':
867 elif op == 'parentpost':
868 o = optimize(x[1], small)
868 o = optimize(x[1], small)
869 return o[0], (op, o[1])
869 return o[0], (op, o[1])
870 elif op == 'group':
870 elif op == 'group':
871 return optimize(x[1], small)
871 return optimize(x[1], small)
872 elif op in 'range list parent ancestorspec':
872 elif op in 'range list parent ancestorspec':
873 wa, ta = optimize(x[1], small)
873 wa, ta = optimize(x[1], small)
874 wb, tb = optimize(x[2], small)
874 wb, tb = optimize(x[2], small)
875 return wa + wb, (op, ta, tb)
875 return wa + wb, (op, ta, tb)
876 elif op == 'func':
876 elif op == 'func':
877 f = getstring(x[1], _("not a symbol"))
877 f = getstring(x[1], _("not a symbol"))
878 wa, ta = optimize(x[2], small)
878 wa, ta = optimize(x[2], small)
879 if f in "grep date user author keyword branch file outgoing closed":
879 if f in "grep date user author keyword branch file outgoing closed":
880 w = 10 # slow
880 w = 10 # slow
881 elif f in "modifies adds removes":
881 elif f in "modifies adds removes":
882 w = 30 # slower
882 w = 30 # slower
883 elif f == "contains":
883 elif f == "contains":
884 w = 100 # very slow
884 w = 100 # very slow
885 elif f == "ancestor":
885 elif f == "ancestor":
886 w = 1 * smallbonus
886 w = 1 * smallbonus
887 elif f in "reverse limit":
887 elif f in "reverse limit":
888 w = 0
888 w = 0
889 elif f in "sort":
889 elif f in "sort":
890 w = 10 # assume most sorts look at changelog
890 w = 10 # assume most sorts look at changelog
891 else:
891 else:
892 w = 1
892 w = 1
893 return w + wa, (op, x[1], ta)
893 return w + wa, (op, x[1], ta)
894 return 1, x
894 return 1, x
895
895
896 class revsetalias(object):
896 class revsetalias(object):
897 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
897 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
898 args = ()
898 args = ()
899
899
900 def __init__(self, token, value):
900 def __init__(self, token, value):
901 '''Aliases like:
901 '''Aliases like:
902
902
903 h = heads(default)
903 h = heads(default)
904 b($1) = ancestors($1) - ancestors(default)
904 b($1) = ancestors($1) - ancestors(default)
905 '''
905 '''
906 if isinstance(token, tuple):
906 if isinstance(token, tuple):
907 self.type, self.name = token
907 self.type, self.name = token
908 else:
908 else:
909 m = self.funcre.search(token)
909 m = self.funcre.search(token)
910 if m:
910 if m:
911 self.type = 'func'
911 self.type = 'func'
912 self.name = m.group(1)
912 self.name = m.group(1)
913 self.args = [x.strip() for x in m.group(2).split(',')]
913 self.args = [x.strip() for x in m.group(2).split(',')]
914 else:
914 else:
915 self.type = 'symbol'
915 self.type = 'symbol'
916 self.name = token
916 self.name = token
917
917
918 if isinstance(value, str):
918 if isinstance(value, str):
919 for arg in self.args:
919 for arg in self.args:
920 value = value.replace(arg, repr(arg))
920 value = value.replace(arg, repr(arg))
921 self.replacement, pos = parse(value)
921 self.replacement, pos = parse(value)
922 if pos != len(value):
922 if pos != len(value):
923 raise error.ParseError('invalid token', pos)
923 raise error.ParseError('invalid token', pos)
924 else:
924 else:
925 self.replacement = value
925 self.replacement = value
926
926
927 def match(self, tree):
927 def match(self, tree):
928 if not tree:
928 if not tree:
929 return False
929 return False
930 if tree == (self.type, self.name):
930 if tree == (self.type, self.name):
931 return True
931 return True
932 if tree[0] != self.type:
932 if tree[0] != self.type:
933 return False
933 return False
934 if len(tree) > 1 and tree[1] != ('symbol', self.name):
934 if len(tree) > 1 and tree[1] != ('symbol', self.name):
935 return False
935 return False
936 # 'func' + funcname + args
936 # 'func' + funcname + args
937 if ((self.args and len(tree) != 3) or
937 if ((self.args and len(tree) != 3) or
938 (len(self.args) == 1 and tree[2][0] == 'list') or
938 (len(self.args) == 1 and tree[2][0] == 'list') or
939 (len(self.args) > 1 and (tree[2][0] != 'list' or
939 (len(self.args) > 1 and (tree[2][0] != 'list' or
940 len(tree[2]) - 1 != len(self.args)))):
940 len(tree[2]) - 1 != len(self.args)))):
941 raise error.ParseError('invalid amount of arguments', len(tree) - 2)
941 raise error.ParseError('invalid amount of arguments', len(tree) - 2)
942 return True
942 return True
943
943
944 def replace(self, tree):
944 def replace(self, tree):
945 if tree == (self.type, self.name):
945 if tree == (self.type, self.name):
946 return self.replacement
946 return self.replacement
947 result = self.replacement
947 result = self.replacement
948 def getsubtree(i):
948 def getsubtree(i):
949 if tree[2][0] == 'list':
949 if tree[2][0] == 'list':
950 return tree[2][i + 1]
950 return tree[2][i + 1]
951 return tree[i + 2]
951 return tree[i + 2]
952 for i, v in enumerate(self.args):
952 for i, v in enumerate(self.args):
953 valalias = revsetalias(('string', v), getsubtree(i))
953 valalias = revsetalias(('string', v), getsubtree(i))
954 result = valalias.process(result)
954 result = valalias.process(result)
955 return result
955 return result
956
956
957 def process(self, tree):
957 def process(self, tree):
958 if self.match(tree):
958 if self.match(tree):
959 return self.replace(tree)
959 return self.replace(tree)
960 if isinstance(tree, tuple):
960 if isinstance(tree, tuple):
961 return tuple(map(self.process, tree))
961 return tuple(map(self.process, tree))
962 return tree
962 return tree
963
963
964 def findaliases(ui, tree):
964 def findaliases(ui, tree):
965 for k, v in ui.configitems('revsetalias'):
965 for k, v in ui.configitems('revsetalias'):
966 alias = revsetalias(k, v)
966 alias = revsetalias(k, v)
967 tree = alias.process(tree)
967 tree = alias.process(tree)
968 return tree
968 return tree
969
969
970 parse = parser.parser(tokenize, elements).parse
970 parse = parser.parser(tokenize, elements).parse
971
971
972 def match(ui, spec):
972 def match(ui, spec):
973 if not spec:
973 if not spec:
974 raise error.ParseError(_("empty query"))
974 raise error.ParseError(_("empty query"))
975 tree, pos = parse(spec)
975 tree, pos = parse(spec)
976 if (pos != len(spec)):
976 if (pos != len(spec)):
977 raise error.ParseError("invalid token", pos)
977 raise error.ParseError("invalid token", pos)
978 tree = findaliases(ui, tree)
978 tree = findaliases(ui, tree)
979 weight, tree = optimize(tree, True)
979 weight, tree = optimize(tree, True)
980 def mfunc(repo, subset):
980 def mfunc(repo, subset):
981 return getset(repo, subset, tree)
981 return getset(repo, subset, tree)
982 return mfunc
982 return mfunc
983
983
984 def makedoc(topic, doc):
984 def makedoc(topic, doc):
985 return help.makeitemsdoc(topic, doc, '.. predicatesmarker', symbols)
985 return help.makeitemsdoc(topic, doc, '.. predicatesmarker', symbols)
986
986
987 # tell hggettext to extract docstrings from these functions:
987 # tell hggettext to extract docstrings from these functions:
988 i18nfunctions = symbols.values()
988 i18nfunctions = symbols.values()
General Comments 0
You need to be logged in to leave comments. Login now